Bonjour à tous
● Julien PAULI
– Utilisateur PHP depuis ~10ans
– Linux / Unix adopter
– PHP Internals reviewer depuis ~3y
● I love C coding
– PHP 5.5 Release Manager
– Travaille pour blablacar Paris
– Ecrit des articles tech PHP et des livres
– @julienpauli - github.com/jpauli - jpauli@php.net
BlaBlacar
● http://www.blablacar.com
● http://www.covoiturage.fr
– 2.5 Millions de membres
– 400.000 personnes font du covoiturage
chaque mois en France
– 100% croissance depuis 4 ans
● Nous recrutons ! Passez me voir :)
– European open : UK, Netherlands, Portugal,
Poland, Italy, Spain
– Apps mobiles Android & Iphone
BlaBlaCar tech
● PHP 5.3, MySQL 5.5 (percona),
Lighttpd+FastCGI
● Debian
● 8 front web servers (4 virtual)
● 1 MySQL master, 2 slaves
● 200Gb MySQL data
● Redis, ElasticSearch, Symfony2,
RabbitMQ, OpscodeChef ...
Au menu aujourd'hui
● Rappels généraux sur le réseau
– Protocoles et encapsulation
● Communiquer sur le réseau avec PHP
– Différentes API offertes
● HTTP avec PHP
– Différentes API offertes
Rappels sur le réseau
● Web = modèle TCP/IP (4 couches)
● PHP permet de jouer avec les couches 3
et 4
Analyser le trafic réseau
● TcpDump ou graphiquement : Wireshark
● Mise en pratique de l'encapsulation
protocolaire
● Superbe outils de piratage débogage de
réseau
Le réseau sous Unix / Linux
● Au moins sur un point, tout le monde Unix
s'est mis d'accord
– Grâce à BSD :)
● ! SOCKETS !
– POSIX
PHP et le réseau
● PHP utilise l'API sockets de l'OS
– Via une couche intermédiaire (streams)
– main/network.c et main/streams
● PHP fournit plusieurs API réseau à l'utilisateur
– Client ou serveur
– Une des API est calquée sur POSIX Sockets
Communiquer avec PHP
Fonctionnalité Couche réseau Client Serveur Disponibilité
fsockopen() Transport Oui Non Native
stream_socket_**() Transport Oui Oui Native
socket_**() Transport Oui Oui ext/sockets
curl_**() App Oui Non ext/curl
fopen() & friends App Oui Non Native
La base du réseau en PHP
● Sans s'embêter, on utilise les flux (streams)
fsockopen() : transport
● fsockopen() joue en couche transport
– Vous devez donc écrire le protocole applicatif
– Ici : HTTP
$fp = fsockopen(‘www.php.net’, 80);
fwrite($fp, “GET / HTTP/1.0rn”
. “Host: www.php.netrnrn”);
$data = fread($fp, 8192);
● Liste des transports disponibles :
stream_get_transports()
– souvent, TCP est utilisé
fsockopen() , quelques limites
● fsockopen() a quelques limites
– Client seulement
– Peu d'options (pas de stream context)
● Please, welcome stream_socket_**()
– stream_socket_client()
– stream_socket_server()
stream_socket_**()
● API cliente et serveur
● Couche transport toujours
● Client
$fp = stream_socket_client(‘www.php.net:80');
fwrite($fp, "GET / HTTP/1.0rnHost: www.php.netrnrn");
$data = fread($fp, 8192);
● Serveur
$fp = stream_socket_server(‘tcp://0.0.0.0:1234');
/* un doux combiné socket()-bind()-listen() */
stream_socket_***() : options
● Quelques options interessantes :
– stream_set_blocking()
● Règle l'API bloquante / non-bloquante
– stream_notification_callback()
● Appel une callback lorsque {xxxx} sur le flux
– stream_set_write/read_buffer()
● Taille des buffers
– stream_copy_to_stream()
● Genre de pipe
– stream_select()
● syscall select() / poll()
Agir sur une couche
● PHP propose de modifier à la volée ses
wrappers intégrés
– Exemple : proxy get to post
$context = stream_context_create(
array('http' =>array('method'=>'POST',
'header'=>'Content-Type: application/x-www-form-urlencoded',
'content'=>http_build_query($_GET)))
);
echo file_get_contents("http://inject-post-data-server",null,$context);
PHP et HTTP
● Plusieurs moyens de parler HTTP
– Utiliser le wrapper PHP intégré (http://)
– Ecrire soi-même la couche over transport
– Utiliser Curl
– Utiliser ext/HTTP
Wrapper intégré
● Tout ce qui est http:// sur les fonctions PHP
$context = stream_context_create(
array('http' =>array('method'=>'POST',
'header'=>'Content-Type: application/x-www-form-urlencoded',
'content'=>http_build_query($_GET)))
);
echo file_get_contents("http://inject-post-data-server",null,$context);
● Quelques fonctions PHP
– http_build_query()
– header() - get_headers() - get_meta_tags()
● Suffisant, mais pas très poussé
Ecrire son wrapper
● Reinvent the wheel ?
$fp = fsockopen('myserver.net', 80);
$http = <<<HTTP
GET /foo HTTP/1.1rn
Host: myserver.netrn
Accept: text/htmlrn
HTTP;
fwrite($fp, $http);
echo fgets($fp);
Curl
● http://curl.haxx.se/
● Pour PHP : --with-curl ou extension PECL
curl is a command line tool for transferring data with URL syntax, supporting
DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS,
POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP.
curl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading,
HTTP form based upload, proxies, cookies, user+password authentication
(Basic, Digest, NTLM, Negotiate, kerberos...), file transfer resume,
proxy tunneling and a busload of other useful tricks.
● On fait des choses très puissantes avec
Curl
– Pas seulement sur HTTP
ext/HTTP
● Sans doute le moyen le plus puissant et le
plus efficace de parler HTTP avec PHP
● Extension
– pecl install pecl_http
– Ou compiler dans la source
● Interface riche pour piloter HTTP, orientée
objet
ext/HTTP API
● Classes :
– HTTPRequest
– HTTPResponse
– HTTPQueryStream
– HTTPMessage
● Gestion de la compression gzip
● Gestion du cache
● Fonctions de liaison avec le buffer de
sortie PHP
ext/HTTP examples
$http_req = new HttpRequest("http://www.example.com");
$http_req->setOptions(array(timeout=>10,useragent=>"MyScript"));
$http_req->send();
echo $http_req->getResponseBody();
$http_req = new HttpRequest("http://www.example.com");
$http_req->setOptions(array(timeout=>10,useragent=>"MyScript"))
try {
$http_req->send();
} catch (HttpException $ex) {
echo $ex->getMessage();
}
● Quelques fonctions auto-parlantes au hasard :
– http_redirect(), http_send_data(), http_send_file(),
http_send_stream(), http_put_data(),
http_parse_cookie()...