©
Dokumen ini menggunakan Manual laman web PHP Cina Lepaskan
Example #1 Simple HTTP client
<?php
// Read callback
function readcb ( $bev , $base ) {
//$input = $bev->input; //$bev->getInput();
//$pos = $input->search("TTP");
$pos = $bev -> input -> search ( "TTP" );
while (( $n = $bev -> input -> remove ( $buf , 1024 )) > 0 ) {
echo $buf ;
}
}
// Event callback
function eventcb ( $bev , $events , $base ) {
if ( $events & EventBufferEvent :: CONNECTED ) {
echo "Connected.\n" ;
} elseif ( $events & ( EventBufferEvent :: ERROR | EventBufferEvent :: EOF )) {
if ( $events & EventBufferEvent :: ERROR ) {
echo "DNS error: " , $bev -> getDnsErrorString (), PHP_EOL ;
}
echo "Closing\n" ;
$base -> exit ();
exit( "Done\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 ( $base , TRUE ); // We'll use async DNS resolving
if (! $dns_base ) {
exit( "Failed to init DNS Base\n" );
}
$bev = new EventBufferEvent ( $base , NULL ,
EventBufferEvent :: OPT_CLOSE_ON_FREE | EventBufferEvent :: OPT_DEFER_CALLBACKS ,
"readcb" , NULL , "eventcb"
);
if (! $bev ) {
exit( "Failed creating bufferevent socket\n" );
}
//$bev->setCallbacks("readcb", 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( "Failed adding request to output buffer\n" );
}
if (! $bev -> connectHost ( $dns_base , $argv [ 1 ], 80 , EventUtil :: AF_UNSPEC )) {
exit( "Can't connect to host { $argv [ 1 ]} \n" );
}
$base -> dispatch ();
?>
以上例程的输出类似于:
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
Example #2 HTTP client using asynchronous DNS resolver
<?php
// Read callback
function readcb ( $bev , $base ) {
$input = $bev -> getInput ();
while (( $n = $input -> remove ( $buf , 1024 )) > 0 ) {
echo $buf ;
}
}
// Event callback
function eventcb ( $bev , $events , $base ) {
if ( $events & EventBufferEvent :: CONNECTED ) {
echo "Connected.\n" ;
} elseif ( $events & ( EventBufferEvent :: ERROR | EventBufferEvent :: EOF )) {
if ( $events & EventBufferEvent :: ERROR ) {
echo "DNS error: " , $bev -> getDnsErrorString (), PHP_EOL ;
}
echo "Closing\n" ;
$base -> exit ();
exit( "Done\n" );
}
}
$base = new EventBase ();
echo "step 1\n" ;
$bev = new EventBufferEvent ( $base , NULL ,
EventBufferEvent :: OPT_CLOSE_ON_FREE | EventBufferEvent :: OPT_DEFER_CALLBACKS );
if (! $bev ) {
exit( "Failed creating bufferevent socket\n" );
}
echo "step 2\n" ;
$bev -> setCallbacks ( "readcb" , NULL , "eventcb" , $base );
$bev -> enable ( Event :: READ | Event :: WRITE );
echo "step 3\n" ;
// Send request
$output = $bev -> getOutput ();
if (! $output -> add (
"GET /index.cphp HTTP/1.0\r\n" .
"Connection: Close\r\n\r\n"
)) {
exit( "Failed adding request to output buffer\n" );
}
if (! $bev -> connect ( "127.0.0.1:80" )) {
exit( "Can't connect to host\n" );
}
// Dispatch pending events
$base -> dispatch ();
?>
Example #3 Echo server
<?php
class MyListenerConnection {
private $bev , $base ;
public function __destruct () {
$this -> bev -> free ();
}
public function __construct ( $base , $fd ) {
$this -> base = $base ;
$this -> bev = new EventBufferEvent ( $base , $fd , EventBufferEvent :: OPT_CLOSE_ON_FREE );
$this -> bev -> setCallbacks (array( $this , "echoReadCallback" ), NULL ,
array( $this , "echoEventCallback" ), NULL );
if (! $this -> bev -> enable ( Event :: READ )) {
echo "Failed to enable READ\n" ;
return;
}
}
public function echoReadCallback ( $bev , $ctx ) {
// Copy all the data from the input buffer to the output buffer
// Variant #1
$bev -> output -> addBuffer ( $bev -> input );
}
public function echoEventCallback ( $bev , $events , $ctx ) {
if ( $events & EventBufferEvent :: ERROR ) {
echo "Error from 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 "Couldn't open event base" ;
exit( 1 );
}
// Variant #1
// 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 "Couldn't create listener" ;
exit( 1 );
}
$this -> listener -> setErrorCallback (array( $this , "accept_error_cb" ));
}
public function dispatch () {
$this -> base -> dispatch ();
}
// This callback is invoked when there is data to read on $bev
public function acceptConnCallback ( $listener , $fd , $address , $ctx ) {
// We got a new connection! Set up a bufferevent for it. */
$base = $this -> base ;
$this -> conn [] = new MyListenerConnection ( $base , $fd );
}
public function accept_error_cb ( $listener , $ctx ) {
$base = $this -> base ;
fprintf ( STDERR , "Got an error %d (%s) on the listener. "
. "Shutting down.\n" ,
EventUtil :: getLastSocketErrno (),
EventUtil :: getLastSocketError ());
$base -> exit ( NULL );
}
}
$port = 9808 ;
if ( $argc > 1 ) {
$port = (int) $argv [ 1 ];
}
if ( $port <= 0 || $port > 65535 ) {
exit( "Invalid port" );
}
$l = new MyListener ( $port );
$l -> dispatch ();
?>
Example #4 SSL echo server
<?php
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( "Failed creating SSL context\n" );
}
$this -> base = new EventBase ();
if (! $this -> base ) {
exit( "Couldn't open event base\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( "Couldn't create listener\n" );
}
$this -> listener -> setErrorCallback (array( $this , "accept_error_cb" ));
}
function dispatch () {
$this -> base -> dispatch ();
}
// This callback is invoked when there is data to read on $bev.
function ssl_read_cb ( $bev , $ctx ) {
$in = $bev -> input ; //$bev->getInput();
printf ( "Received %zu bytes\n" , $in -> length );
printf ( "----- data ----\n" );
printf ( "%ld:\t%s\n" , (int) $in -> length , $in -> pullup (- 1 ));
$bev -> writeBuffer ( $in );
}
// This callback is invoked when some even occurs on the event listener,
// e.g. connection closed, or an error occured
function ssl_event_cb ( $bev , $events , $ctx ) {
if ( $events & EventBufferEvent :: ERROR ) {
// Fetch errors from the SSL error stack
while ( $err = $bev -> sslError ()) {
fprintf ( STDERR , "Bufferevent error %s.\n" , $err );
}
}
if ( $events & ( EventBufferEvent :: EOF | EventBufferEvent :: ERROR )) {
$bev -> free ();
}
}
// This callback is invoked when a client accepts new connection
function ssl_accept_cb ( $listener , $fd , $address , $ctx ) {
// We got a new connection! Set up a bufferevent for it.
$this -> bev = EventBufferEvent :: sslSocket ( $this -> base , $fd , $this -> ctx ,
EventBufferEvent :: SSL_ACCEPTING , EventBufferEvent :: OPT_CLOSE_ON_FREE );
if (! $this -> bev ) {
echo "Failed creating ssl buffer\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 );
}
// This callback is invoked when we failed to setup new connection for a client
function accept_error_cb ( $listener , $ctx ) {
fprintf ( STDERR , "Got an error %d (%s) on the listener. "
. "Shutting down.\n" ,
EventUtil :: getLastSocketErrno (),
EventUtil :: getLastSocketError ());
$this -> base -> exit ( NULL );
}
// Initialize SSL structures, create an EventSslContext
// Optionally create self-signed certificates
function init_ssl () {
// We *must* have entropy. Otherwise there's no point to crypto.
if (! EventUtil :: sslRandPoll ()) {
exit( "EventUtil::sslRandPoll failed\n" );
}
$local_cert = __DIR__ . "/cert.pem" ;
$local_pk = __DIR__ . "/privkey.pem" ;
if (! file_exists ( $local_cert ) || ! file_exists ( $local_pk )) {
echo "Couldn't read $local_cert or $local_pk file. To generate a key\n" ,
"and self-signed certificate, run:\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 ;
}
}
// Allow to override the port
$port = 9999 ;
if ( $argc > 1 ) {
$port = (int) $argv [ 1 ];
}
if ( $port <= 0 || $port > 65535 ) {
exit( "Invalid port\n" );
}
$l = new MySslEchoServer ( $port );
$l -> dispatch ();
?>
Example #5 Signal handler
<?php
class MyEventSignal {
private $base ;
function __construct ( $base ) {
$this -> base = $base ;
}
function eventSighandler ( $no , $c ) {
echo "Caught 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 );
?>
Example #6 Use libevent's loop to process requests of `eio' extension
<?php
// Callback for eio_nop()
function my_nop_cb ( $d , $r ) {
echo "step 6\n" ;
}
$dir = "/tmp/abc-eio-temp" ;
if ( file_exists ( $dir )) {
rmdir ( $dir );
}
echo "step 1\n" ;
$base = new EventBase ();
echo "step 2\n" ;
eio_init ();
eio_mkdir ( $dir , 0750 , EIO_PRI_DEFAULT , "my_nop_cb" );
$event = new Event ( $base , eio_get_event_stream (),
Event :: READ | Event :: PERSIST , function ( $fd , $events , $base ) {
echo "step 5\n" ;
while ( eio_nreqs ()) {
eio_poll ();
}
$base -> stop ();
}, $base );
echo "step 3\n" ;
$event -> add ();
echo "step 4\n" ;
$base -> dispatch ();
echo "Done\n" ;
?>
Example #7 Miscellaneous
<?php
echo "Supported methods:\n" ;
foreach ( Event :: getSupportedMethods () as $m ) {
echo $m , PHP_EOL ;
}
// Avoiding "select" method
$cfg = new EventConfig ();
if ( $cfg -> avoidMethod ( "select" )) {
echo "`select' method avoided\n" ;
}
// Create event_base associated with the config
$base = new EventBase ( $cfg );
echo "Event method used: " , $base -> getMethod (), PHP_EOL ;
echo "Features:\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" );
// Require FDS feature
if ( $cfg -> requireFeatures ( EventConfig :: FEATURE_FDS )) {
echo "FDS feature is now requried\n" ;
$base = new EventBase ( $cfg );
( $base -> getFeatures () & EventConfig :: FEATURE_FDS )
and print( "FDS - arbitrary file descriptor types, and not just sockets\n" );
}
$base = new EventBase ();
$event = new Event ( $base , STDIN , Event :: READ | Event :: PERSIST , function ( $fd , $events , $arg ) {
static $max_iterations = 0 ;
if (++ $max_iterations >= 5 ) {
echo "Stopping...\n" ;
$arg [ 0 ]-> exit ( 2.33 );
}
echo fgets ( $fd );
}, array (& $base ));
$event -> add ();
$base -> loop ();
?>
Example #8 Simple HTTP server
<?php
function _http_dump ( $req , $data ) {
static $counter = 0 ;
static $max_requests = 2 ;
if (++ $counter >= $max_requests ) {
echo "Counter reached max requests $max_requests . Exiting\n" ;
exit();
}
echo __METHOD__ , " called\n" ;
echo "request:" ; var_dump ( $req );
echo "data:" ; var_dump ( $data );
echo "\n===== DUMP =====\n" ;
echo "Command:" , $req -> getCommand (), PHP_EOL ;
echo "URI:" , $req -> getUri (), PHP_EOL ;
echo "Input headers:" ; var_dump ( $req -> getInputHeaders ());
echo "Output headers:" ; var_dump ( $req -> getOutputHeaders ());
echo "\n >> Sending reply ..." ;
$req -> sendReply ( 200 , "OK" );
echo "OK\n" ;
echo "\n >> Reading input buffer ...\n" ;
$buf = $req -> getInputBuffer ();
while ( $s = $buf -> readLine ( EventBuffer :: EOL_ANY )) {
echo $s , PHP_EOL ;
}
echo "No more data in the buffer\n" ;
}
function _http_about ( $req ) {
echo __METHOD__ , PHP_EOL ;
echo "URI: " , $req -> getUri (), PHP_EOL ;
echo "\n >> Sending reply ..." ;
$req -> sendReply ( 200 , "OK" );
echo "OK\n" ;
}
function _http_default ( $req , $data ) {
echo __METHOD__ , PHP_EOL ;
echo "URI: " , $req -> getUri (), PHP_EOL ;
echo "\n >> Sending reply ..." ;
$req -> sendReply ( 200 , "OK" );
echo "OK\n" ;
}
$port = 8010 ;
if ( $argc > 1 ) {
$port = (int) $argv [ 1 ];
}
if ( $port <= 0 || $port > 65535 ) {
exit( "Invalid port" );
}
$base = new EventBase ();
$http = new EventHttp ( $base );
$http -> setAllowedMethods ( EventHttpRequest :: CMD_GET | EventHttpRequest :: CMD_POST );
$http -> setCallback ( "/dump" , "_http_dump" , array( 4 , 8 ));
$http -> setCallback ( "/about" , "_http_about" );
$http -> setDefaultCallback ( "_http_default" , "custom data value" );
$http -> bind ( "0.0.0.0" , 8010 );
$base -> loop ();
?>
以上例程的输出类似于:
a=12 HTTP/1.0 200 OK Content-Type: text/html; charset=ISO-8859-1 Connection: closeHTTP/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
Example #9 Simple HTTPS server
<?php
function _http_dump ( $req , $data ) {
static $counter = 0 ;
static $max_requests = 200 ;
if (++ $counter >= $max_requests ) {
echo "Counter reached max requests $max_requests . Exiting\n" ;
exit();
}
echo __METHOD__ , " called\n" ;
echo "request:" ; var_dump ( $req );
echo "data:" ; var_dump ( $data );
echo "\n===== DUMP =====\n" ;
echo "Command:" , $req -> getCommand (), PHP_EOL ;
echo "URI:" , $req -> getUri (), PHP_EOL ;
echo "Input headers:" ; var_dump ( $req -> getInputHeaders ());
echo "Output headers:" ; var_dump ( $req -> getOutputHeaders ());
echo "\n >> Sending reply ..." ;
$req -> sendReply ( 200 , "OK" );
echo "OK\n" ;
$buf = $req -> getInputBuffer ();
echo "\n >> Reading input buffer (" , $buf -> length , ") ...\n" ;
while ( $s = $buf -> read ( 1024 )) {
echo $s ;
}
echo "\nNo more data in the buffer\n" ;
}
function _http_about ( $req ) {
echo __METHOD__ , PHP_EOL ;
echo "URI: " , $req -> getUri (), PHP_EOL ;
echo "\n >> Sending reply ..." ;
$req -> sendReply ( 200 , "OK" );
echo "OK\n" ;
}
function _http_default ( $req , $data ) {
echo __METHOD__ , PHP_EOL ;
echo "URI: " , $req -> getUri (), PHP_EOL ;
echo "\n >> Sending reply ..." ;
$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 <= 0 || $port > 65535 ) {
exit( "Invalid port" );
}
$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( 4 , 8 ));
$http -> setCallback ( "/about" , "_http_about" );
$http -> setCallback ( "/err400" , "_http_400" );
$http -> setDefaultCallback ( "_http_default" , "custom data value" );
$http -> bind ( $ip , $port );
$base -> dispatch ();
Example #10 OpenSSL connection
<?php
function _request_handler ( $req , $base ) {
echo __FUNCTION__ , PHP_EOL ;
if ( is_null ( $req )) {
echo "Timed out\n" ;
} else {
$response_code = $req -> getResponseCode ();
if ( $response_code == 0 ) {
echo "Connection refused\n" ;
} elseif ( $response_code != 200 ) {
echo "Unexpected response: $response_code \n" ;
} else {
echo "Success: $response_code \n" ;
$buf = $req -> getInputBuffer ();
echo "Body:\n" ;
while ( $s = $buf -> readLine ( EventBuffer :: EOL_ANY )) {
echo $s , PHP_EOL ;
}
}
}
$base -> exit ( NULL );
}
function _init_ssl () {
$ctx = new EventSslContext ( EventSslContext :: SSLv3_CLIENT_METHOD , array ());
return $ctx ;
}
// Allow to override the port
$port = 9999 ;
if ( $argc > 1 ) {
$port = (int) $argv [ 1 ];
}
if ( $port <= 0 || $port > 65535 ) {
exit( "Invalid port\n" );
}
$host = '127.0.0.1' ;
$ctx = _init_ssl ();
if (! $ctx ) {
trigger_error ( "Failed creating SSL context" , E_USER_ERROR );
}
$base = new EventBase ();
if (! $base ) {
trigger_error ( "Failed to initialize event base" , E_USER_ERROR );
}
$conn = new EventHttpConnection ( $base , NULL , $host , $port , $ctx );
$conn -> setTimeout ( 50 );
$req = new EventHttpRequest ( "_request_handler" , $base );
$req -> addHeader ( "Host" , $host , EventHttpRequest :: 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 ( $req , EventHttpRequest :: CMD_POST , "/dump" );
$base -> dispatch ();
echo "END\n" ;
?>
Example #11 EventHttpConnection::makeRequest() example
<?php
function _request_handler ( $req , $base ) {
echo __FUNCTION__ , PHP_EOL ;
if ( is_null ( $req )) {
echo "Timed out\n" ;
} else {
$response_code = $req -> getResponseCode ();
if ( $response_code == 0 ) {
echo "Connection refused\n" ;
} elseif ( $response_code != 200 ) {
echo "Unexpected response: $response_code \n" ;
} else {
echo "Success: $response_code \n" ;
$buf = $req -> getInputBuffer ();
echo "Body:\n" ;
while ( $s = $buf -> readLine ( EventBuffer :: EOL_ANY )) {
echo $s , PHP_EOL ;
}
}
}
$base -> exit ( NULL );
}
$address = "127.0.0.1" ;
$port = 80 ;
$base = new EventBase ();
$conn = new EventHttpConnection ( $base , NULL , $address , $port );
$conn -> setTimeout ( 5 );
$req = new EventHttpRequest ( "_request_handler" , $base );
$req -> addHeader ( "Host" , $address , EventHttpRequest :: OUTPUT_HEADER );
$req -> addHeader ( "Content-Length" , "0" , EventHttpRequest :: OUTPUT_HEADER );
$conn -> makeRequest ( $req , EventHttpRequest :: CMD_GET , "/index.cphp" );
$base -> loop ();
?>
以上例程的输出类似于:
_request_handler Success: 200 Body: PHP, date: 2013-03-13T20:27:52+05:00
Example #12 Connection listener based on a UNIX domain socket
<?php
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 , $fd , EventBufferEvent :: OPT_CLOSE_ON_FREE );
$this -> bev -> setCallbacks (array( $this , "echoReadCallback" ), NULL ,
array( $this , "echoEventCallback" ), NULL );
if (! $this -> bev -> enable ( Event :: READ )) {
echo "Failed to enable READ\n" ;
return;
}
}
public function echoReadCallback ( $bev , $ctx ) {
// Copy all the data from the input buffer to the output buffer
$bev -> output -> addBuffer ( $bev -> input );
}
public function echoEventCallback ( $bev , $events , $ctx ) {
if ( $events & EventBufferEvent :: ERROR ) {
echo "Error from 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 ( "Couldn't create listener" , E_USER_ERROR );
}
$this -> listener -> setErrorCallback (array( $this , "accept_error_cb" ));
}
public function dispatch () {
$this -> base -> dispatch ();
}
// This callback is invoked when there is data to read on $bev
public function acceptConnCallback ( $listener , $fd , $address , $ctx ) {
// We got a new connection! Set up a bufferevent for it. */
$base = $this -> base ;
$this -> conn [] = new MyListenerConnection ( $base , $fd );
}
public function accept_error_cb ( $listener , $ctx ) {
$base = $this -> base ;
fprintf ( STDERR , "Got an error %d (%s) on the listener. "
. "Shutting down.\n" ,
EventUtil :: getLastSocketErrno (),
EventUtil :: getLastSocketError ());
$base -> exit ( NULL );
}
}
if ( $argc <= 1 ) {
exit( "Socket path is not provided\n" );
}
$sock_path = $argv [ 1 ];
$l = new MyListener ( $sock_path );
$l -> dispatch ();
?>
Example #13 Simple SMTP server
<?php
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 , // change to true with authentic cert
EventSslContext :: OPT_ALLOW_SELF_SIGNED => true // change to false with authentic cert
]);
$this -> base = new EventBase ();
if (! $this -> base ) {
exit( "Couldn't open event base\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( "Couldn't create listener\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 "Failed creating 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 , "Got an error %d (%s) on the listener. Shutting down.\n" ,
$errno , EventUtil :: 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" )
{
// remove the trailing \r\n
$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 ' , $line , 4 ):
$this -> ev_write ( $id , "250-STARTTLS\r\n" );
$this -> ev_write ( $id , "250 OK ehlo\r\n" );
break;
case strncmp ( 'HELO ' , $line , 4 ):
$this -> ev_write ( $id , "250-STARTTLS\r\n" );
$this -> ev_write ( $id , "250 OK helo\r\n" );
break;
case strncmp ( 'QUIT' , $line , 3 ):
$this -> ev_write ( $id , "250 OK quit\r\n" );
$this -> ev_close ( $id );
break;
case strncmp ( 'STARTTLS' , $line , 3 ):
$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 'unknown command: ' . $line . "\n" ;
break;
}
}
}
new Handler ();
[#1] Bas Vijfwinkel [2015-06-26 09:17:32]
In order to use certain features used in the examples above here you need a very recent version of libevent (>= 2.1).
Although 'pecl install event' will not show any errors, certain features are disabled and certain function calls might use a different number of parameters.
For example EventHttp will throw a warning that the number of parameters should be 1 instead of 2 (when using it with a SSL context) and as a bonus cause a segmentation fault.
On some distributions of Linux, the stable libevent library might not be recent enough for all features to be enabled and you might need to use an alpha version.
You can install an alpha version of libevent next to the stable version that might already be on your machine.
The basic steps are:
- download the alpha tarball to a folder e.g libevent-2.1.3-alpha.tar.gz
- tar zxvf libevent-2.1.3-alpha.tar.gz
- cd libevent-2.1.3-alpha
- ./configure --prefix=/opt/libevent-alpha
- make
- make install
Now the alpha version of libevent is created in /opt/libevent-alpha.
Before running pecl, first export the library folder of libevent so that pecl knows where your most recent libevent stuff is:
export LD_LIBRARY_PATH=/opt/libevent-2.1.3-alpha/lib
Without this export I couldn't get pecl to use the correct libevent
Now run 'pecl install event'
and when asked libevent installation prefix [/usr] :
enter : /opt/libevent-2.1.3-alpha
Now pecl will use your alpha version of libevent instead of the default version.
If everything goes well then you should be able to enjoy the full glory of this wonderfull extension.
If you try to install a very recent version of libevent on a system with a old version of openssl (0.9), you also need to update that because there are some dependencies in libevent that do not work with 0.9