Sometimes you've to call a function from one php-process to another. Polling mechanisms are quite boring, so here's a fast RPC implementation.
Imagine a PHP-script running infinite in background. Now you'd like to send it some data, call functions in it and so on.
<?php class rpc_function { var $name='rpc_test'; var $arg=array('foo'=>'ok','bar'=>'123'); } @unlink('/tmp/php-socket'); $socket = socket_create(AF_UNIX, SOCK_SEQPACKET, 0); socket_bind($socket,'/tmp/php-socket'); socket_listen($socket); $rpc=new rpc(); if (!$socket) { echo "$errstr ($errno)<br />\n"; } else { while (true) { while ($conn = socket_accept($socket)) { $data=socket_read($conn,1024); $funct=unserialize($data); $retval=false; if (method_exists($rpc,$funct->name)) { $retval=call_user_func_array(array('rpc',$funct->name),$funct->arg); } $data=serialize($retval); socket_write($conn, $data,strlen($data)); socket_shutdown($conn); } } } class rpc { function rpc_test($foo,$bar) { echo "rpc_test($foo,$bar) called... \n"; return array('result'=>'good'); } } ?>
<?php class rpc_function { var $name='rpc_test'; var $arg=array('foo'=>'ok','bar'=>'123'); } $socket = socket_create(AF_UNIX, SOCK_SEQPACKET, 0); if (socket_connect($socket,'/tmp/php-socket')) { //send the call $data=serialize(new rpc_function() ); socket_write($socket,$data,strlen($data)); //retrieve retval $response=socket_read($socket,1024,PHP_BINARY_READ); $retval=unserialize($response); echo "result: \n"; print_r($retval); } socket_close($socket);
<?php class RPC_call{ var $name; var $arg; function RPC_call($name,$args=array()) { $this->name=$name; $this->args=$args; } } class RPC { var $rpc_class; var $socket; var $connected=false; var $connections=10; function RPC($address,&$rpc_class) { $this->rpc_class=&$rpc_class; $this->address=$address; $this->socket = socket_create(AF_UNIX, SOCK_STREAM, 0); return $this->socket; } function listen(){ unlink($this->address); socket_bind($this->socket,$this->address); socket_listen($this->socket); $sockets[0]=$this->socket; while (true) { //copy our array cos select modifies $read $read=$sockets; $ready = socket_select($read,$write=null,$except=null,1); foreach($read as $socket) { if ($socket==$sockets[0]) { //read requests on master are connects $sockets[]=socket_accept($this->socket); } else { $data = socket_read($socket, 1024); if ($data == null) { //means socket has been closed $key=array_search($socket,$sockets); unset($sockets[$key]); socket_close($socket); } else { $funct=unserialize($data); $retval=false; if (method_exists($this->rpc_class,$funct->name)) { $retval=call_user_func_array(array($this->rpc_class,$funct->name),$funct->arg); } $data=serialize($retval); socket_write($socket, $data); } } } } } function call($func,$args=array()){ $waiting=socket_select($read=array($this->socket),$write=null,$except=null,0); if ($waiting) { $connected=socket_connect($this->socket,$this->address); } else { $connected=true; } if ($connected) { //send the call $data=serialize(new RPC_call($func,$args)); socket_write($this->socket,$data,strlen($data)); //retrieve retval $response=socket_read($this->socket,1024); //socket_shutdown($this->socket); return unserialize($response); } } } class RPC_class { var $_rpc=false; function _bind(&$rpc_class){ $this->_rpc=$rpc_class; } public function __call($method, $args) { return $this->_rpc->call($method, $args); } }
<?php if(!defined('INC_PATH')) define('INC_PATH',realpath(dirname(__FILE__).'/../inc/').'/'); require_once(INC_PATH.'rpc/unix-sockets.php'); class myCalls{ function test(){ echo "I'm the server!\n"; return "response for the client...\n"; } function test2(){ echo "I'm still the server!\n"; return "another response for the client...\n"; } } $rpc=new RPC('/tmp/php-socket',new myCalls()); $rpc->listen(); ?>
Since RPC_class overloads __call all functions in myCalls are unused, only their name and arguments are used.
<?php if(!defined('INC_PATH')) define('INC_PATH',realpath(dirname(__FILE__).'/../inc/').'/'); require_once(INC_PATH.'rpc/unix-sockets.php'); class myCalls extends RPC_class{ function test(){ echo "I'm the client!\n"; } function test2(){ echo "I'm still the client!\n"; } } $rpc=new RPC('/tmp/php-socket',new myCalls()); echo $rpc->call('test'); echo $rpc->call('test2'); ?>