PHP 5.4.36 Released

Exemples

Exemple #1 Client HTTP simple

<?php
// Lecture de la fonction de rappel
function readcb($bev$base) {
    
//$input = $bev->input; //$bev->getInput();

    //$pos = $input->search("TTP");
    
$pos $bev->input->search("TTP");

    while ((
$n $bev->input->remove($buf1024)) > 0) {
        echo 
$buf;
    }
}

// Fonction de rappel de l'événement
function eventcb($bev$events$base) {
    if (
$events EventBufferEvent::CONNECTED) {
        echo 
"Connecté.\n";
    } elseif (
$events & (EventBufferEvent::ERROR EventBufferEvent::EOF)) {
        if (
$events EventBufferEvent::ERROR) {
            echo 
"erreur DNS : "$bev->getDnsErrorString(), PHP_EOL;
        }

        echo 
"Fermeture\n";
        
$base->exit();
        exit(
"Fait !\n");
    }
}

if (
$argc != 3) {
    echo <<<EOS
Trivial HTTP 0.x client
Syntax: php 
{$argv[0]} [hostname] [resource]
Example: php 
{$argv[0]} www.google.com /

EOS;
    exit();
}

$base = new EventBase();

$dns_base = new EventDnsBase($baseTRUE); // Nous utilisons une résolution DNS asynchrone
if (!$dns_base) {
    exit(
"Echec dans l'initialisation de la base DNS\n");
}

$bev = new EventBufferEvent($base/* use internal socket */ NULL,
    
EventBufferEvent::OPT_CLOSE_ON_FREE EventBufferEvent::OPT_DEFER_CALLBACKS,
    
"readcb"/* writecb */ NULL"eventcb"
);
if (!
$bev) {
    exit(
"Echec dans la création du socket bufferevent\n");
}

//$bev->setCallbacks("readcb", /* writecb */ NULL, "eventcb", $base);
$bev->enable(Event::READ Event::WRITE);

$output $bev->output//$bev->getOutput();
if (!$output->add(
    
"GET {$argv[2]} HTTP/1.0\r\n".
    
"Host: {$argv[1]}\r\n".
    
"Connection: Close\r\n\r\n"
)) {
    exit(
"Echec dans l'ajout de la requête dans le buffer de sortie\n");
}

if (!
$bev->connectHost($dns_base$argv[1], 80EventUtil::AF_UNSPEC)) {
    exit(
"Connexion impossible à l'hôte {$argv[1]}\n");
}

$base->dispatch();
?>

L'exemple ci-dessus va afficher quelque chose de similaire à :

Connected.
HTTP/1.1 301 Moved Permanently
Date: Fri, 01 Mar 2013 18:47:48 GMT
Location: http://www.google.co.uk/
Content-Type: text/html; charset=UTF-8
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Age: 133438
Expires: Sat, 30 Mar 2013 05:39:28 GMT
Connection: close

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.co.uk/">here</A>.
</BODY></HTML>
Closing
Done

Exemple #2 Client HTTP en utilisant une résolution DNS asynchrone

<?php
/*
 * 1. Connexion à 127.0.0.1 sur le port 80
 * en utilisant EventBufferEvent::connect().
 *
 * 2. Requête /index.cphp via HTTP/1.0
 * en utilisant le buffer de sortie.
 *
 * 3. Lecture asynchrone de la réponse et l'affiche dans stdout.
 */

// Lecture de la fonction de rappel
function readcb($bev$base) {
    
$input $bev->getInput();

    while ((
$n $input->remove($buf1024)) > 0) {
        echo 
$buf;
    }
}

// Fonction de rappel de l'événement
function eventcb($bev$events$base) {
    if (
$events EventBufferEvent::CONNECTED) {
        echo 
"Connecté.\n";
    } elseif (
$events & (EventBufferEvent::ERROR EventBufferEvent::EOF)) {
        if (
$events EventBufferEvent::ERROR) {
            echo 
"Erreur DNS : "$bev->getDnsErrorString(), PHP_EOL;
        }

        echo 
"Fermeture\n";
        
$base->exit();
        exit(
"Fait !\n");
    }
}

$base = new EventBase();

echo 
"étape n°1\n";
$bev = new EventBufferEvent($base/* use internal socket */ NULL,
    
EventBufferEvent::OPT_CLOSE_ON_FREE EventBufferEvent::OPT_DEFER_CALLBACKS);
if (!
$bev) {
    exit(
"Echec lors de la création du socket bufferevent\n");
}

echo 
"étape n°2\n";
$bev->setCallbacks("readcb"/* writecb */ NULL"eventcb"$base);
$bev->enable(Event::READ Event::WRITE);

echo 
"étape n°3\n";
// Envoi de la requête
$output $bev->getOutput();
if (!
$output->add(
    
"GET /index.cphp HTTP/1.0\r\n".
    
"Connection: Close\r\n\r\n"
)) {
    exit(
"Echec lors de l'ajout de la requête dans le buffer de sortie\n");
}

/* COnnexion à l'hôte de façon synchrone.
Nous connaissons l'IP, nous n'avons donc pas besoin de résolution DNS. */
if (!$bev->connect("127.0.0.1:80")) {
    exit(
"Impossible de se connecter à l'hôte\n");
}

// Diffuse les événements en attente
$base->dispatch();
?>

Exemple #3 Serveur d'affichage

<?php
/*
 * Serveur d'affichage simpple basé sur les écoutes de connexion libevent.
 *
 * Utilisation :
 * 1) Dans un terminal, exécutez :
 *
 * $ php listener.php 9881
 *
 * 2) Dans un autre terminal, ouvrez une connexion, i.e. :
 *
 * $ nc 127.0.0.1 9881
 *
 * 3) Commencez à taper. Le serveur devrait répéter les entrées.
 */

class MyListenerConnection {
    private 
$bev$base;

    public function 
__destruct() {
        
$this->bev->free();
    }

    public function 
__construct($base$fd) {
        
$this->base $base;

        
$this->bev = new EventBufferEvent($base$fdEventBufferEvent::OPT_CLOSE_ON_FREE);

        
$this->bev->setCallbacks(array($this"echoReadCallback"), NULL,
            array(
$this"echoEventCallback"), NULL);

        if (!
$this->bev->enable(Event::READ)) {
            echo 
"Echec dans l'activation de READ\n";
            return;
        }
    }

    public function 
echoReadCallback($bev$ctx) {
        
// Copie toutes les données depuis le buffer d'entrée vers le buffer de sortie

        // Variant #1
        
$bev->output->addBuffer($bev->input);

        
/* Variant #2 */
        /*
        $input    = $bev->getInput();
        $output = $bev->getOutput();
        $output->addBuffer($input);
        */
    
}

    public function 
echoEventCallback($bev$events$ctx) {
        if (
$events EventBufferEvent::ERROR) {
            echo 
"Erreur depuis bufferevent\n";
        }

        if (
$events & (EventBufferEvent::EOF EventBufferEvent::ERROR)) {
            
//$bev->free();
            
$this->__destruct();
        }
    }
}

class 
MyListener {
    public 
$base,
        
$listener,
        
$socket;
    private 
$conn = array();

    public function 
__destruct() {
        foreach (
$this->conn as &$c$c NULL;
    }

    public function 
__construct($port) {
        
$this->base = new EventBase();
        if (!
$this->base) {
            echo 
"Impossible d'ouvrir la base de l'événement";
            exit(
1);
        }

        
// Variant #1
        /*
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        if (!socket_bind($this->socket, '0.0.0.0', $port)) {
            echo "Impossible de lier le socket\n";
            exit(1);
        }
        $this->listener = new EventListener($this->base,
            array($this, "acceptConnCallback"), $this->base,
            EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE,
            -1, $this->socket);
         */

        // Variant #2
         
$this->listener = new EventListener($this->base,
             array(
$this"acceptConnCallback"), $this->base,
             
EventListener::OPT_CLOSE_ON_FREE EventListener::OPT_REUSEABLE, -1,
             
"0.0.0.0:$port");

        if (!
$this->listener) {
            echo 
"Impossible de créer l'écouteur";
            exit(
1);
        }

        
$this->listener->setErrorCallback(array($this"accept_error_cb"));
    }

    public function 
dispatch() {
        
$this->base->dispatch();
    }

    
// Cette fonction de rappel est appelée lorsqu'il y a des données à lire sur $bev
    
public function acceptConnCallback($listener$fd$address$ctx) {
        
// Nous avons une nouvelle connexion ! On définit un bufferevent pour elle. */
        
$base $this->base;
        
$this->conn[] = new MyListenerConnection($base$fd);
    }

    public function 
accept_error_cb($listener$ctx) {
        
$base $this->base;

        
fprintf(STDERR"On recoit une erreur %d (%s) sur l'écouteur. "
            
."Arrêt.\n",
            
EventUtil::getLastSocketErrno(),
            
EventUtil::getLastSocketError());

        
$base->exit(NULL);
    }
}

$port 9808;

if (
$argc 1) {
    
$port = (int) $argv[1];
}
if (
$port <= || $port 65535) {
    exit(
"Invalid port");
}

$l = new MyListener($port);
$l->dispatch();
?>

Exemple #4 Serveur d'affichage SSL

<?php
/*
 * Serveur d'affichage SSL
 *
 * Pour tester :
 * 1) Exécutez :
 * $ php examples/ssl-echo-server/server.php 9998
 *
 * 2) dans un autre terminal, exécutez :
 * $ socat - SSL:127.0.0.1:9998,verify=1,cafile=examples/ssl-echo-server/cert.pem
 */

class MySslEchoServer {
    public 
$port,
        
$base,
        
$bev,
        
$listener,
        
$ctx;

    function 
__construct ($port$host "127.0.0.1") {
        
$this->port $port;
        
$this->ctx $this->init_ssl();
        if (!
$this->ctx) {
            exit(
"Echec lors de la création du contexte SSL\n");
        }

        
$this->base = new EventBase();
        if (!
$this->base) {
            exit(
"Impossible d'ouvrir la base de l'événement\n");
        }

        
$this->listener = new EventListener($this->base,
            array(
$this"ssl_accept_cb"), $this->ctx,
            
EventListener::OPT_CLOSE_ON_FREE EventListener::OPT_REUSEABLE,
            -
1"$host:$port");
        if (!
$this->listener) {
            exit(
"Impossible de créer l'écouteur\n");
        }

        
$this->listener->setErrorCallback(array($this"accept_error_cb"));
    }
    function 
dispatch() {
        
$this->base->dispatch();
    }

    
// Cette fonction de rappel est appelée lorsqu'il y a des données à lire sur $bev.
    
function ssl_read_cb($bev$ctx) {
        
$in $bev->input//$bev->getInput();

        
printf("Réception de %zu octets\n"$in->length);
        
printf("----- données ----\n");
        
printf("%ld:\t%s\n", (int) $in->length$in->pullup(-1));

        
$bev->writeBuffer($in);
    }

    
// Cette fonction de rappel est appelée lorsque des erreurs surviennent sur l'écouteur d'événement,
    // i.e. la connexion se ferme, ou une erreur survient
    
function ssl_event_cb($bev$events$ctx) {
        if (
$events EventBufferEvent::ERROR) {
            
// Récupère les erreurs depuis la pile d'erreur SSL
            
while ($err $bev->sslError()) {
                
fprintf(STDERR"Erreur Bufferevent %s.\n"$err);
            }
        }

        if (
$events & (EventBufferEvent::EOF EventBufferEvent::ERROR)) {
            
$bev->free();
        }
    }

    
// Cette fonction de rappel est appelée lorsqu'un client accepte une nouvelle connexion
    
function ssl_accept_cb($listener$fd$address$ctx) {
        
// Nous avons une nouvelle connexion ! On définit un bufferevent pour elle.
        
$this->bev EventBufferEvent::sslSocket($this->base$fd$this->ctx,
            
EventBufferEvent::SSL_ACCEPTINGEventBufferEvent::OPT_CLOSE_ON_FREE);

        if (!
$this->bev) {
            echo 
"Echec lors de la création du buffer SSL\n";
            
$this->base->exit(NULL);
            exit(
1);
        }

        
$this->bev->enable(Event::READ);
        
$this->bev->setCallbacks(array($this"ssl_read_cb"), NULL,
            array(
$this"ssl_event_cb"), NULL);
    }

    
// Cette fonction de rappel est appelée lorsqu'on échoue à définir une nouvelle connexion pour un client
    
function accept_error_cb($listener$ctx) {
        
fprintf(STDERR"On reçoit une erreur %d (%s) sur l'écouteur. "
            
."Arrêt.\n",
            
EventUtil::getLastSocketErrno(),
            
EventUtil::getLastSocketError());

        
$this->base->exit(NULL);
    }

    
// Initialise les structures SSL ; crée un EventSslContext
    // Optionnellement, crée des certificats auto-signés
    
function init_ssl() {
        
// Nous *devons* avoir l'entropie. Sinon, il n'y a aucun intérêt à crypter.
        
if (!EventUtil::sslRandPoll()) {
            exit(
"Echec de EventUtil::sslRandPoll\n");
        }

        
$local_cert __DIR__."/cert.pem";
        
$local_pk   __DIR__."/privkey.pem";

        if (!
file_exists($local_cert) || !file_exists($local_pk)) {
            echo 
"Impossible de lire $local_cert ni $local_pk file. Pour générer une clé\n",
                
"et un certificat auto-signé, exécutez :\n",
                
"  openssl genrsa -out $local_pk 2048\n",
                
"  openssl req -new -key $local_pk -out cert.req\n",
                
"  openssl x509 -req -days 365 -in cert.req -signkey $local_pk -out $local_cert\n";

            return 
FALSE;
        }

        
$ctx = new EventSslContext(EventSslContext::SSLv3_SERVER_METHOD, array (
             
EventSslContext::OPT_LOCAL_CERT  => $local_cert,
             
EventSslContext::OPT_LOCAL_PK    => $local_pk,
             
//EventSslContext::OPT_PASSPHRASE  => "echo server",
             
EventSslContext::OPT_VERIFY_PEER => true,
             
EventSslContext::OPT_ALLOW_SELF_SIGNED => false,
        ));

        return 
$ctx;
    }
}

// Autorise l'écrasement du port
$port 9999;
if (
$argc 1) {
    
$port = (int) $argv[1];
}
if (
$port <= || $port 65535) {
    exit(
"Port invalide\n");
}


$l = new MySslEchoServer($port);
$l->dispatch();
?>

Exemple #5 Gestionnaire de signal

<?php
/*
Dans un terminal, exécutez :

$ php examples/signal.php

Dans un autre terminal, trouvez le pid et envoyé le signal SIGTERM, i.e. :

$ ps aux | grep examp
ruslan    3976  0.2  0.0 139896 11256 pts/1    S+   10:25   0:00 php examples/signal.php
ruslan    3978  0.0  0.0   9572   864 pts/2    S+   10:26   0:00 grep --color=auto examp
$ kill -TERM 3976

Dans le premier terminal, vous devriez attrapper ce qui suit :

On attrappe le signal 15
*/
class MyEventSignal {
    private 
$base;

    function 
__construct($base) {
        
$this->base $base;
    }

    function 
eventSighandler($no$c) {
        echo 
"On attrappe le signal $no\n";
        
event_base_loopexit($c->base);
    }
}

$base event_base_new();
$c    = new MyEventSignal($base);
$no   SIGTERM;
$ev   evsignal_new($base$no, array($c,'eventSighandler'), $c);

evsignal_add($ev);

event_base_loop($base);
?>

Exemple #6 Utilisation d'une boucle libevent pour réaliser les requêtes de l'extension `eio'

<?php
// Fonction de rappel pour eio_nop()
function my_nop_cb($d$r) {
    echo 
"étape 6\n";
}

$dir "/tmp/abc-eio-temp";
if (
file_exists($dir)) {
    
rmdir($dir);
}

echo 
"étape 1\n";

$base = new EventBase();

echo 
"étape 2\n";

eio_init();

eio_mkdir($dir0750EIO_PRI_DEFAULT"my_nop_cb");

$event = new Event($baseeio_get_event_stream(),
    
Event::READ Event::PERSIST, function ($fd$events$base) {
    echo 
"step 5\n";

    while (
eio_nreqs()) {
        
eio_poll();
    }

    
$base->stop();
}, 
$base);

echo 
"étape 3\n";

$event->add();

echo 
"étape 4\n";

$base->dispatch();

echo 
"Fait !\n";
?>

Exemple #7 Divers

<?php
/* {{{ Configuration & méthodes supportées */
echo "Méthodes supportées :\n";
foreach (
Event::getSupportedMethods() as $m) {
    echo 
$mPHP_EOL;
}

// On désactive la méthode "select"
$cfg = new EventConfig();
if (
$cfg->avoidMethod("select")) {
    echo 
"La méthode `select' a été désactivée\n";
}

// Crée un event_base associé à la configuration
$base = new EventBase($cfg);
echo 
"Méthode d'événement utilisée : "$base->getMethod(), PHP_EOL;

echo 
"fonctionalités :\n";
$features $base->getFeatures();
(
$features EventConfig::FEATURE_ET) and print("ET - edge-triggered IO\n");
(
$features EventConfig::FEATURE_O1) and print("O1 - O(1) operation for adding/deletting events\n");
(
$features EventConfig::FEATURE_FDS) and print("FDS - arbitrary file descriptor types, and not just sockets\n");

// Nécessite la fonctionalité FDS
if ($cfg->requireFeatures(EventConfig::FEATURE_FDS)) {
    echo 
"La fonctionalité FDS est maintenant requise\n";

    
$base = new EventBase($cfg);
    (
$base->getFeatures() & EventConfig::FEATURE_FDS)
        and print(
"FDS - type de descripteur de fichiers arbitraire, et non uniquement les sockets\n");
}
/* }}} */

/* {{{ Base */
$base = new EventBase();
$event = new Event($baseSTDINEvent::READ Event::PERSIST, function ($fd$events$arg) {
    static 
$max_iterations 0;

    if (++
$max_iterations >= 5) {
        
/* on sort après 5 itérations avec un délai maximal d'attente de 2.33 secondes */
        
echo "Arrêt...\n";
        
$arg[0]->exit(2.33);
    }

    echo 
fgets($fd);
}, array (&
$base));

$event->add();
$base->loop();
/* Base }}} */
?>

Exemple #8 Serveur HTTP simple

<?php
/*
 * Serveur HTTP simple.
 *
 * Pour le tester :
 * 1) Exécutez-le sur le port de votre choix, i.e. :
 * $ php examples/http.php 8010
 * 2) Dans un autre terminal, connectez-vous sur une adresse de ce port
 * et effectuez des requêtes GET ou POST (les autres types sont désactivées dans cet exemple), i.e. :
 * $ nc -t 127.0.0.1 8010
 * POST /about HTTP/1.0
 * Content-Type: text/plain
 * Content-Length: 4
 * Connection: close
 * (press Enter)
 *
 * Il devrait afficher :
 * a=12
 * HTTP/1.0 200 OK
 * Content-Type: text/html; charset=ISO-8859-1
 * Connection: close
 *
 * $ nc -t 127.0.0.1 8010
 * GET /dump HTTP/1.0
 * Content-Type: text/plain
 * Content-Encoding: UTF-8
 * Connection: close
 * (press Enter)
 *
 * Il devrait afficher :
 * HTTP/1.0 200 OK
 * Content-Type: text/html; charset=ISO-8859-1
 * Connection: close
 * (press Enter)
 *
 * $ nc -t 127.0.0.1 8010
 * GET /unknown HTTP/1.0
 * Connection: close
 *
 * Il devrait afficher :
 * HTTP/1.0 200 OK
 * Content-Type: text/html; charset=ISO-8859-1
 * Connection: close
 *
 * 3) Voir ce que le serveur affiche dans le terminal précédent.
 */

function _http_dump($req$data) {
    static 
$counter      0;
    static 
$max_requests 2;

    if (++
$counter >= $max_requests)  {
        echo 
"Le compteur a atteint le nombre maximal de requête ($max_requests). Sortie !\n";
        exit();
    }

    echo 
__METHOD__" called\n";
    echo 
"Requête :"var_dump($req);
    echo 
"Données :"var_dump($data);

    echo 
"\n===== DUMP =====\n";
    echo 
"Commande :"$req->getCommand(), PHP_EOL;
    echo 
"URI :"$req->getUri(), PHP_EOL;
    echo 
"En-têtes en entrée :"var_dump($req->getInputHeaders());
    echo 
"En-têtes en sortie :"var_dump($req->getOutputHeaders());

    echo 
"\n >> Envoi de la réponse ...";
    
$req->sendReply(200"OK");
    echo 
"OK\n";

    echo 
"\n >> Lecture du buffer d'entrée ...\n";
    
$buf $req->getInputBuffer();
    while (
$s $buf->readLine(EventBuffer::EOL_ANY)) {
        echo 
$sPHP_EOL;
    }
    echo 
"Il n'y a plus de données dans le buffer\n";
}

function 
_http_about($req) {
    echo 
__METHOD__PHP_EOL;
    echo 
"URI : "$req->getUri(), PHP_EOL;
    echo 
"\n >> Envoi de la réponse ...";
    
$req->sendReply(200"OK");
    echo 
"OK\n";
}

function 
_http_default($req$data) {
    echo 
__METHOD__PHP_EOL;
    echo 
"URI: "$req->getUri(), PHP_EOL;
    echo 
"\n >> Envoi de la réponse ...";
    
$req->sendReply(200"OK");
    echo 
"OK\n";
}

$port 8010;
if (
$argc 1) {
    
$port = (int) $argv[1];
}
if (
$port <= || $port 65535) {
    exit(
"Port invalide");
}

$base = new EventBase();
$http = new EventHttp($base);
$http->setAllowedMethods(EventHttpRequest::CMD_GET EventHttpRequest::CMD_POST);

$http->setCallback("/dump""_http_dump", array(48));
$http->setCallback("/about""_http_about");
$http->setDefaultCallback("_http_default""valeur de données personnalisées");

$http->bind("0.0.0.0"8010);
$base->loop();
?>

L'exemple ci-dessus va afficher quelque chose de similaire à :

a=12
HTTP/1.0 200 OK
Content-Type: text/html; charset=ISO-8859-1
Connection: close

HTTP/1.0 200 OK
Content-Type: text/html; charset=ISO-8859-1
Connection: close
(press Enter)

HTTP/1.0 200 OK
Content-Type: text/html; charset=ISO-8859-1
Connection: close

Exemple #9 Serveur HTTPS simple

<?php
/*
 * Serveur HTTPS simple.
 *
 * 1) Exécutez le serveur : `php examples/https.php 9999`
 * 2) Testez le : `php examples/ssl-connection.php 9999`
 */

function _http_dump($req$data) {
    static 
$counter      0;
    static 
$max_requests 200;

    if (++
$counter >= $max_requests)  {
        echo 
"Le compteur a atteint le nombre maximal de requêtes ($max_requests). Sortie\n";
        exit();
    }

    echo 
__METHOD__" appelée\n";
    echo 
"Requête :"var_dump($req);
    echo 
"Données :"var_dump($data);

    echo 
"\n===== DUMP =====\n";
    echo 
"Commande :"$req->getCommand(), PHP_EOL;
    echo 
"URI :"$req->getUri(), PHP_EOL;
    echo 
"En-têtes d'entrée :"var_dump($req->getInputHeaders());
    echo 
"En-têtes de sortie :"var_dump($req->getOutputHeaders());

    echo 
"\n >> Envoi de la réponse ...";
    
$req->sendReply(200"OK");
    echo 
"OK\n";

    
$buf $req->getInputBuffer();
    echo 
"\n >> Lecture du buffer d'entrée ("$buf->length") ...\n";
    while (
$s $buf->read(1024)) {
        echo 
$s;
    }
    echo 
"\nIl n'y a plus de données dans le buffer\n";
}

function 
_http_about($req) {
    echo 
__METHOD__PHP_EOL;
    echo 
"URI : "$req->getUri(), PHP_EOL;
    echo 
"\n >> Envoi de la réponse ...";
    
$req->sendReply(200"OK");
    echo 
"OK\n";
}

function 
_http_default($req$data) {
    echo 
__METHOD__PHP_EOL;
    echo 
"URI: "$req->getUri(), PHP_EOL;
    echo 
"\n >> Envoi de la réponse ...";
    
$req->sendReply(200"OK");
    echo 
"OK\n";
}

function 
_http_400($req) {
    
$req->sendError(400);
}

function 
_init_ssl() {
    
$local_cert __DIR__."/ssl-echo-server/cert.pem";
    
$local_pk   __DIR__."/ssl-echo-server/privkey.pem";

    
$ctx = new EventSslContext(EventSslContext::SSLv3_SERVER_METHOD, array (
        
EventSslContext::OPT_LOCAL_CERT  => $local_cert,
        
EventSslContext::OPT_LOCAL_PK    => $local_pk,
        
//EventSslContext::OPT_PASSPHRASE  => "test",
        
EventSslContext::OPT_ALLOW_SELF_SIGNED => true,
    ));

    return 
$ctx;
}

$port 9999;
if (
$argc 1) {
    
$port = (int) $argv[1];
}
if (
$port <= || $port 65535) {
    exit(
"Port invalide");
}
$ip '0.0.0.0';

$base = new EventBase();
$ctx  _init_ssl();
$http = new EventHttp($base$ctx);
$http->setAllowedMethods(EventHttpRequest::CMD_GET EventHttpRequest::CMD_POST);

$http->setCallback("/dump""_http_dump", array(48));
$http->setCallback("/about""_http_about");
$http->setCallback("/err400""_http_400");
$http->setDefaultCallback("_http_default""Valeur des données personnalisées");

$http->bind($ip$port);
$base->dispatch();

Exemple #10 Connexion OpenSSL

<?php
/*
 * Exemple de Client OpenSSL.
 *
 * Utilisation :
 * 1) Exécutez un serveur, i.e. :
 * $ php examples/https.php 9999
 *
 * 2) Lancez le client dans un autre terminal :
 * $ php examples/ssl-connection.php 9999
 */

function _request_handler($req$base) {
    echo 
__FUNCTION__PHP_EOL;

    if (
is_null($req)) {
        echo 
"Délai d'attente maximal atteint\n";
    } else {
        
$response_code $req->getResponseCode();

        if (
$response_code == 0) {
            echo 
"Connexion refusée\n";
        } elseif (
$response_code != 200) {
            echo 
"Réponse innatendue : $response_code\n";
        } else {
            echo 
"Succès : $response_code\n";
            
$buf $req->getInputBuffer();
            echo 
"Corps :\n";
            while (
$s $buf->readLine(EventBuffer::EOL_ANY)) {
                echo 
$sPHP_EOL;
            }
        }
    }

    
$base->exit(NULL);
}

function 
_init_ssl() {
    
$ctx = new EventSslContext(EventSslContext::SSLv3_CLIENT_METHOD, array ());

    return 
$ctx;
}


// Autorise l'écrasement du port
$port 9999;
if (
$argc 1) {
    
$port = (int) $argv[1];
}
if (
$port <= || $port 65535) {
    exit(
"Port invalide\n");
}
$host '127.0.0.1';

$ctx _init_ssl();
if (!
$ctx) {
    
trigger_error("Echec lors de la création du contexte SSL"E_USER_ERROR);
}

$base = new EventBase();
if (!
$base) {
    
trigger_error("Echec dans l'initialisation de la base d'événement"E_USER_ERROR);
}

$conn = new EventHttpConnection($baseNULL$host$port$ctx);
$conn->setTimeout(50);

$req = new EventHttpRequest("_request_handler"$base);
$req->addHeader("Host"$hostEventHttpRequest::OUTPUT_HEADER);
$buf $req->getOutputBuffer();
$buf->add("<html>HTML TEST</html>");
//$req->addHeader("Content-Length", $buf->length, EventHttpRequest::OUTPUT_HEADER);
//$req->addHeader("Connection", "close", EventHttpRequest::OUTPUT_HEADER);
$conn->makeRequest($reqEventHttpRequest::CMD_POST"/dump");

$base->dispatch();
echo 
"FIN\n";
?>

Exemple #11 Exemple avec EventHttpConnection::makeRequest()

<?php
function _request_handler($req$base) {
    echo 
__FUNCTION__PHP_EOL;

    if (
is_null($req)) {
        echo 
"Délai d'attente maximal atteint\n";
    } else {
        
$response_code $req->getResponseCode();

        if (
$response_code == 0) {
            echo 
"Connexion refusée\n";
        } elseif (
$response_code != 200) {
            echo 
"Réponse innatendue : $response_code\n";
        } else {
            echo 
"Succès : $response_code\n";
            
$buf $req->getInputBuffer();
            echo 
"Corps :\n";
            while (
$s $buf->readLine(EventBuffer::EOL_ANY)) {
                echo 
$sPHP_EOL;
            }
        }
    }

    
$base->exit(NULL);
}

$address "127.0.0.1";
$port 80;

$base = new EventBase();
$conn = new EventHttpConnection($baseNULL$address$port);
$conn->setTimeout(5);
$req = new EventHttpRequest("_request_handler"$base);

$req->addHeader("Host"$addressEventHttpRequest::OUTPUT_HEADER);
$req->addHeader("Content-Length""0"EventHttpRequest::OUTPUT_HEADER);
$conn->makeRequest($reqEventHttpRequest::CMD_GET"/index.cphp");

$base->loop();
?>

L'exemple ci-dessus va afficher quelque chose de similaire à :

_request_handler
Succès : 200
Corps :
PHP, date:
2013-03-13T20:27:52+05:00

Exemple #12 Ecoute d'une connexion en se basant sur un socket de domaine Unix

<?php
/*
 * Serveur d'écoute en se basant sur un écouteur de connexion libevent.
 *
 * Utilisation :
 * 1) Dans un terminal, exécutez :
 *
 * $ php unix-domain-listener.php [path-to-socket]
 *
 * 2) Dans un autre terminal, ouvrez la connexion
 * vers le socket, i.e. :
 *
 * $ socat - GOPEN:/tmp/1.sock
 *
 * 3) Commencez à taper. Le serveur doit répéter les entrées.
 */

class MyListenerConnection {
    private 
$bev$base;

    public function 
__destruct() {
        if (
$this->bev) {
            
$this->bev->free();
        }
    }

    public function 
__construct($base$fd) {
        
$this->base $base;

        
$this->bev = new EventBufferEvent($base$fdEventBufferEvent::OPT_CLOSE_ON_FREE);

        
$this->bev->setCallbacks(array($this"echoReadCallback"), NULL,
            array(
$this"echoEventCallback"), NULL);

        if (!
$this->bev->enable(Event::READ)) {
            echo 
"Echec dans l'activation de READ\n";
            return;
        }
    }

    public function 
echoReadCallback($bev$ctx) {
        
// Copie toutes les données depuis le buffer d'entrée dans le buffer de sortie
        
$bev->output->addBuffer($bev->input);
    }

    public function 
echoEventCallback($bev$events$ctx) {
        if (
$events EventBufferEvent::ERROR) {
            echo 
"Erreur depuis bufferevent\n";
        }

        if (
$events & (EventBufferEvent::EOF EventBufferEvent::ERROR)) {
            
$bev->free();
            
$bev NULL;
        }
    }
}

class 
MyListener {
    public 
$base,
        
$listener,
        
$socket;
    private 
$conn = array();

    public function 
__destruct() {
        foreach (
$this->conn as &$c$c NULL;
    }

    public function 
__construct($sock_path) {
        
$this->base = new EventBase();
        if (!
$this->base) {
            echo 
"Couldn't open event base";
            exit(
1);
        }

        if (
file_exists($sock_path)) {
            
unlink($sock_path);
        }

         
$this->listener = new EventListener($this->base,
             array(
$this"acceptConnCallback"), $this->base,
             
EventListener::OPT_CLOSE_ON_FREE EventListener::OPT_REUSEABLE, -1,
             
"unix:$sock_path");

        if (!
$this->listener) {
            
trigger_error("Impossible de créer l'écouteur"E_USER_ERROR);
        }

        
$this->listener->setErrorCallback(array($this"accept_error_cb"));
    }

    public function 
dispatch() {
        
$this->base->dispatch();
    }

    
// Cette fonction de rappel sera appelée lorsqu'il y aura des données à lire sur $bev
    
public function acceptConnCallback($listener$fd$address$ctx) {
        
// Nous avons une nouvelle connexion ! On définit un bufferevent pour elle. */
        
$base $this->base;
        
$this->conn[] = new MyListenerConnection($base$fd);
    }

    public function 
accept_error_cb($listener$ctx) {
        
$base $this->base;

        
fprintf(STDERR"On reçoit une erreur %d (%s) sur l'écouteur. "
            
."Shutting down.\n",
            
EventUtil::getLastSocketErrno(),
            
EventUtil::getLastSocketError());

        
$base->exit(NULL);
    }
}

if (
$argc <= 1) {
    exit(
"Le chemin vers le socket n'est pas fourni\n");
}
$sock_path $argv[1];

$l = new MyListener($sock_path);
$l->dispatch();
?>

Exemple #13 Exemple de serveur SMTP

<?php
 
/*
 * Auteur : Andrew Rose <hello at andrewrose dot co dot uk>
 *
 * Utilisation :
 * 1) On prépare le certificat cert.pem et la clé privée privkey.pem.
 * 2) On démarre le script du serveur
 * 3) On ouvre la connexion TLS, i.e. :
 *      $ openssl s_client -connect localhost:25 -starttls smtp -crlf
 * 4) On commence à tester les commandes listées dans la méthode `cmd` ci-dessous.
 */

class Handler {
    public 
$domainName FALSE;
    public 
$connections = [];
    public 
$buffers = [];
    public 
$maxRead 256000;

    public function 
__construct() {
        
$this->ctx = new EventSslContext(EventSslContext::SSLv3_SERVER_METHOD, [
            
EventSslContext::OPT_LOCAL_CERT  => 'cert.pem',
            
EventSslContext::OPT_LOCAL_PK    => 'privkey.pem',
            
//EventSslContext::OPT_PASSPHRASE  => '',
            
EventSslContext::OPT_VERIFY_PEER => false// modifier en TRUE avec les certificats authentiques
            
EventSslContext::OPT_ALLOW_SELF_SIGNED => true // modifier en FALSE avec les certificats authentiques
        
]);

        
$this->base = new EventBase();
        if (!
$this->base) {
            exit(
"Impossible d'ouvrir la base de l'événement\n");
        }

        if (!
$this->listener = new EventListener($this->base,
            [
$this'ev_accept'],
            
$this->ctx,
            
EventListener::OPT_CLOSE_ON_FREE EventListener::OPT_REUSEABLE,
            -
1,
            
'0.0.0.0:25'))
        {
            exit(
"Impossible de créer l'écouteur\n");
        }

        
$this->listener->setErrorCallback([$this'ev_error']);
        
$this->base->dispatch();
    }

    public function 
ev_accept($listener$fd$address$ctx) {
        static 
$id 0;
        
$id += 1;

        
$this->connections[$id]['clientData'] = '';
        
$this->connections[$id]['cnx'] = new EventBufferEvent($this->base$fd,
            
EventBufferEvent::OPT_CLOSE_ON_FREE);

        if (!
$this->connections[$id]['cnx']) {
            echo 
"Echec lors de la création du buffer\n";
            
$this->base->exit(NULL);
            exit(
1);
        }

        
$this->connections[$id]['cnx']->setCallbacks([$this"ev_read"], NULL,
            [
$this'ev_error'], $id);
        
$this->connections[$id]['cnx']->enable(Event::READ Event::WRITE);

        
$this->ev_write($id'220 '.$this->domainName." wazzzap?\r\n");
    }

    function 
ev_error($listener$ctx) {
        
$errno EventUtil::getLastSocketErrno();

        
fprintf(STDERR"On reçoit l'erreur %d (%s) sur l'écouteur. On stoppe.\n",
            
$errnoEventUtil::getLastSocketError());

        if (
$errno != 0) {
            
$this->base->exit(NULL);
            exit();
        }
    }

    public function 
ev_close($id) {
        
$this->connections[$id]['cnx']->disable(Event::READ Event::WRITE);
        unset(
$this->connections[$id]);
    }

    protected function 
ev_write($id$string) {
        echo 
'S('.$id.'): '.$string;
        
$this->connections[$id]['cnx']->write($string);
    }

    public function 
ev_read($buffer$id) {
        while(
$buffer->input->length 0) {
            
$this->connections[$id]['clientData'] .= $buffer->input->read($this->maxRead);
            
$clientDataLen strlen($this->connections[$id]['clientData']);

            if(
$this->connections[$id]['clientData'][$clientDataLen-1] == "\n"
                
&& $this->connections[$id]['clientData'][$clientDataLen-2] == "\r")
            {
                
// Supprime les caractères \r\n à la fin
                
$line substr($this->connections[$id]['clientData'], 0,
                    
strlen($this->connections[$id]['clientData']) - 2);

                
$this->connections[$id]['clientData'] = '';
                
$this->cmd($buffer$id$line);
            }
        }
    }

    protected function 
cmd($buffer$id$line) {
        switch (
$line) {
            case 
strncmp('EHLO '$line4):
                
$this->ev_write($id"250-STARTTLS\r\n");
                
$this->ev_write($id"250 OK ehlo\r\n");
                break;

            case 
strncmp('HELO '$line4):
                
$this->ev_write($id"250-STARTTLS\r\n");
                
$this->ev_write($id"250 OK helo\r\n");
                break;

            case 
strncmp('QUIT'$line3):
                
$this->ev_write($id"250 OK quit\r\n");
                
$this->ev_close($id);
                break;

            case 
strncmp('STARTTLS'$line3):
                
$this->ev_write($id"220 Ready to start TLS\r\n");
                
$this->connections[$id]['cnx'] = EventBufferEvent::sslFilter($this->base,
                    
$this->connections[$id]['cnx'], $this->ctx,
                    
EventBufferEvent::SSL_ACCEPTING,
                    
EventBufferEvent::OPT_CLOSE_ON_FREE);
                
$this->connections[$id]['cnx']->setCallbacks([$this"ev_read"], NULL, [$this'ev_error'], $id);
                
$this->connections[$id]['cnx']->enable(Event::READ Event::WRITE);
                break;

            default:
                echo 
'Commande inconnue : '.$line."\n";
                break;
        }
    }
}

new 
Handler();
add a note add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top