===================================== 原文地址:http://www.coolcode.cn/?p=101 ===================================== 有时候我们需要在两个 php 服务器之间执行远程过程调用,虽然用 xml-rpc 是一种解决方案,但是目前的 xml-rpc 的 php 实现用起来都非常麻烦,原来我也写过一个能够方便使用的 php 的 xml-rpc 类库, 但是那个需要安装 xmlrpc-epi 扩展,这对于不支持这个扩展的服务器就不方便了。所以我写了下面这个 phprpc 的类库,它没有使用 xml-rpc 协议,而是我自己定义的 phprpc 协议,这个虽然只能用于 php 程序之间的远程过程调用,但是使用起来比 xml-rpc 更方便。 其他语言也不是完全不可能实现,只是实现起来比用 php 麻烦点而已,因为这里对参数和返回值的序列化与反序列化直接使用的 php 的 serialize 和 unserialize,其他语言只要能够实现这两个函数,要实现这个协议也很简单。 下载:phprpc.php PHP: <?php/** * @author Ma Bingyao([email protected]) * @copyright 2005 CoolCode.CN * @package PHPRPC * @version 0.1 * @link http://www.coolcode.cn/?p=101 * * Example usage: * * server.php * <?php * include('phprpc.php'); * function add($a, $b) { * return $a + $b; * } * function sub($a, $b) { * return $a - $b; * } * new phprpc_server(array('add', 'sub')); * ?> * * client.php * <?php * include('phprpc.php'); * $rpc_client = new phprpc_client('http://test.coolcode.cn/phprpc/server.php'); * echo $rpc_client->add(1, 2); * echo "<br />"; * echo $rpc_client->Sub(1, 2); // the function name is case-insensitive * echo "<br />"; * // error handle * echo "<pre>"; * $result = $rpc_client->mul(1, 2); // no mul function * if (get_class($result) == "phprpc_error") { * print_r($result); * } * $result = $rpc_client->add(1); // wrong arguments * if (get_class($result) == "phprpc_error") { * print_r($result); * } * $rpc_client->use_service('wrong url'); // wrong url * $result = $rpc_client->add(1, 2); * if (get_class($result) == "phprpc_error") { * print_r($result); * } * echo "</pre>"; * ?> */class phprpc_error { var $errno; var $errstr; function phprpc_error($errno, $errstr) { $this->errno = $errno; $this->errstr = $errstr; }}class phprpc_server { function tolower(&$func, $keys) { $func = strtolower($func); } function error_handler($errno, $errstr) { echo $errno; echo "\r\n\r\n"; echo $errstr; exit; } function phprpc_server($functions) { header("HTTP/1.1 200 OK"); header("Connection: close"); header("Content-Type: text/plain"); header("X-Powered-By: PHPRPC Server"); header("Date: " . gmdate("D, d M Y H:i:s") . " GMT"); error_reporting(0); set_error_handler(array(&$this, 'error_handler')); if (isset($_POST['phprpc_func'])) { array_walk($functions, array(&$this, 'tolower')); $function = strtolower(get_magic_quotes_gpc() ? stripslashes($_POST['phprpc_func']) : $_POST['phprpc_func']); if (in_array($function, $functions)) { if (isset($_POST['phprpc_args'])) { $arguments = unserialize(base64_decode(get_magic_quotes_gpc() ? stripslashes($_POST['phprpc_args']) : $_POST['phprpc_args'])); } else { $arguments = array(); } $result = base64_encode(serialize(call_user_func_array($function, $arguments))); } else { $result = "1\r\n\r\nCan't find this function $function()"; } } else { $result = "1\r\n\r\nCalled no function"; } print $result; restore_error_handler(); }}class phprpc_client { var $scheme; var $host; var $port; var $path; var $user; var $pass; var $timeout; function phprpc_client($url, $user = '', $pass = '', $timeout = 10) { $this->use_service($url); $this->user = $user; $this->pass = $pass; $this->timeout = $timeout; } function use_service($url) { $urlparts = parse_url($url); if (isset($urlparts['scheme']) && ($urlparts['scheme'] == "https")) { $urlparts['scheme'] = "ssl"; } else { $urlparts['scheme'] = ""; } if (!isset($urlparts['host'])) { if (isset($_SERVER["HTTP_HOST"])) { $urlparts['host'] = $_SERVER["HTTP_HOST"]; } else if (isset($_SERVER["SERVER_NAME"])) { $urlparts['host'] = $_SERVER["SERVER_NAME"]; } else { $urlparts['host'] = "localhost"; } } if (!isset($urlparts['port'])) { if ($urlparts['scheme'] == "ssl") { $urlparts['port'] = 443; } else { $urlparts['port'] = 80; } } if (!isset($urlparts['path'])) { $urlparts['path'] = "/"; } else if (($urlparts['path']{0} != '/') && ($_SERVER["PHP_SELF"]{0} == '/')) { $urlparts['path'] = substr($_SERVER["PHP_SELF"], 0, strrpos($_SERVER["PHP_SELF"], '/') + 1) . $urlparts['path']; } $this->scheme = $urlparts['scheme']; $this->host = $urlparts['host']; $this->port = $urlparts['port']; $this->path = $urlparts['path']; } function __invoke($function, $arguments) { $request = "phprpc_func=$function"; if (count($arguments) > 0) { $request .= "&phprpc_args=" . base64_encode(serialize($arguments)); } $content_len = strlen($request); $errno = 0; $errstr = ''; $host = ($this->scheme) ? $this->scheme . "://" . $this->host : $this->host; $handle = @fsockopen($host, $this->port, $errno, $errstr, $this->timeout); $buf = ''; if ($handle) { if ($this->user) { $auth = "Authorization: Basic " . base64_encode($this->user . ":" . $this->pass) . "\r\n"; } $http_request = "POST $this->path HTTP/1.0\r\n" . "User-Agent: PHPRPC Client\r\n" . "Host: $this->host:$this->port\r\n" . $auth . "Content-Type: application/x-www-form-urlencoded\r\n" . "Content-Length: $content_len\r\n" . "\r\n" . $request; fputs($handle, $http_request, strlen($http_request)); while (!feof($handle)) { $buf .= fgets($handle, 128); } fclose($handle); if (strlen($buf)) { $buf = explode("\r\n\r\n", $buf); $header = $buf[0]; if (strpos($header, 'X-Powered-By: PHPRPC Server') !== FALSE) { if (count($buf) == 2) { $result = unserialize(base64_decode($buf[1])); } else if (count($buf) == 3){ $result = new phprpc_error((int)$buf[1], $buf[2]); } else { $result = new phprpc_error(E_ERROR, "Unknown error"); } } else { $result = new phprpc_error(E_ERROR, "Wrong PHPRPC Server"); } } else { $result = new phprpc_error(E_ERROR, "No data received from server"); } } else { $result = new phprpc_error($errno, $errstr); } return $result; } function __call($function, $arguments, &$return) { $return = $this->__invoke($function, $arguments); if (phpversion() < 5) return true; } function call($function, $args) { $arguments = func_get_args(); array_shift($arguments); return $this->__invoke($function, $arguments); }}if (function_exists("overload") && version_compare(phpversion(), "5", "<")) { overload('phprpc_client');}?>