You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
496 lines
17 KiB
PHP
496 lines
17 KiB
PHP
<?php
|
|
/**********************************************************\
|
|
| |
|
|
| The implementation of PHPRPC Protocol 3.0 |
|
|
| |
|
|
| phprpc_server.php |
|
|
| |
|
|
| Release 3.0.1 |
|
|
| Copyright by Team-PHPRPC |
|
|
| |
|
|
| WebSite: http://www.phprpc.org/ |
|
|
| http://www.phprpc.net/ |
|
|
| http://www.phprpc.com/ |
|
|
| http://sourceforge.net/projects/php-rpc/ |
|
|
| |
|
|
| Authors: Ma Bingyao <andot@ujn.edu.cn> |
|
|
| |
|
|
| This file may be distributed and/or modified under the |
|
|
| terms of the GNU General Public License (GPL) version |
|
|
| 2.0 as published by the Free Software Foundation and |
|
|
| appearing in the included file LICENSE. |
|
|
| |
|
|
\**********************************************************/
|
|
|
|
/* PHPRPC Server for PHP.
|
|
*
|
|
* Copyright: Ma Bingyao <andot@ujn.edu.cn>
|
|
* Version: 3.0
|
|
* LastModified: Apr 12, 2010
|
|
* This library is free. You can redistribute it and/or modify it under GPL.
|
|
*
|
|
/*
|
|
* Interfaces
|
|
*
|
|
* function add($a, $b) {
|
|
* return $a + $b;
|
|
* }
|
|
* function sub($a, $b) {
|
|
* return $a - $b;
|
|
* }
|
|
* function inc(&$n) {
|
|
* return $n++;
|
|
* }
|
|
* include('phprpc_server.php');
|
|
* $server = new PHPRPC_Server();
|
|
* $server->add(array('add', 'sub'));
|
|
* $server->add('inc');
|
|
* $server->setCharset('UTF-8');
|
|
* $server->setDebugMode(true);
|
|
* $server->start();
|
|
*
|
|
*/
|
|
|
|
class PHPRPC_Server {
|
|
var $callback;
|
|
var $charset;
|
|
var $encode;
|
|
var $ref;
|
|
var $encrypt;
|
|
var $enableGZIP;
|
|
var $debug;
|
|
var $keylen;
|
|
var $key;
|
|
var $errno;
|
|
var $errstr;
|
|
var $functions;
|
|
var $cid;
|
|
var $buffer;
|
|
// Private Methods
|
|
function addJsSlashes($str, $flag) {
|
|
if ($flag) {
|
|
$str = addcslashes($str, "\0..\006\010..\012\014..\037\042\047\134\177..\377");
|
|
}
|
|
else {
|
|
$str = addcslashes($str, "\0..\006\010..\012\014..\037\042\047\134\177");
|
|
}
|
|
return str_replace(array(chr(7), chr(11)), array('\007', '\013'), $str);
|
|
}
|
|
function encodeString($str, $flag = true) {
|
|
if ($this->encode) {
|
|
return base64_encode($str);
|
|
}
|
|
else {
|
|
return $this->addJsSlashes($str, $flag);
|
|
}
|
|
}
|
|
function encryptString($str, $level) {
|
|
if ($this->encrypt >= $level) {
|
|
$str = xxtea_encrypt($str, $this->key);
|
|
}
|
|
return $str;
|
|
}
|
|
function decryptString($str, $level) {
|
|
if ($this->encrypt >= $level) {
|
|
$str = xxtea_decrypt($str, $this->key);
|
|
}
|
|
return $str;
|
|
}
|
|
function sendHeader() {
|
|
header("HTTP/1.1 200 OK");
|
|
header("Content-Type: text/plain; charset={$this->charset}");
|
|
header("X-Powered-By: PHPRPC Server/3.0");
|
|
header('P3P: CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"');
|
|
header('Expires: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
|
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
|
}
|
|
function getRequestURL() {
|
|
if (!isset($_SERVER['HTTPS']) ||
|
|
$_SERVER['HTTPS'] == 'off' ||
|
|
$_SERVER['HTTPS'] == '') {
|
|
$scheme = 'http';
|
|
}
|
|
else {
|
|
$scheme = 'https';
|
|
}
|
|
$host = $_SERVER['SERVER_NAME'];
|
|
$port = $_SERVER['SERVER_PORT'];
|
|
$path = $_SERVER['SCRIPT_NAME'];
|
|
return $scheme . '://' . $host . (($port == 80) ? '' : ':' . $port) . $path;
|
|
}
|
|
function sendURL() {
|
|
if (SID != "") {
|
|
$url = $this->getRequestURL();
|
|
if (count($_GET) > 0) {
|
|
$url .= '?' . strip_tags(SID);
|
|
foreach ($_GET as $key => $value) {
|
|
if (strpos(strtolower($key), 'phprpc_') !== 0) {
|
|
$url .= '&' . $key . '=' . urlencode($value);
|
|
}
|
|
}
|
|
}
|
|
$this->buffer .= "phprpc_url=\"" . $this->encodeString($url) . "\";\r\n";
|
|
}
|
|
}
|
|
function gzip($buffer) {
|
|
$len = strlen($buffer);
|
|
if ($this->enableGZIP && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip,deflate')) {
|
|
$gzbuffer = gzencode($buffer);
|
|
$gzlen = strlen($gzbuffer);
|
|
if ($len > $gzlen) {
|
|
header("Content-Length: $gzlen");
|
|
header("Content-Encoding: gzip");
|
|
return $gzbuffer;
|
|
}
|
|
}
|
|
header("Content-Length: $len");
|
|
return $buffer;
|
|
}
|
|
function sendCallback() {
|
|
$this->buffer .= $this->callback;
|
|
echo $this->gzip($this->buffer);
|
|
ob_end_flush();
|
|
restore_error_handler();
|
|
if (function_exists('restore_exception_handler')) {
|
|
restore_exception_handler();
|
|
}
|
|
exit();
|
|
}
|
|
function sendFunctions() {
|
|
$this->buffer .= "phprpc_functions=\"" . $this->encodeString(serialize_fix(array_keys($this->functions))) . "\";\r\n";
|
|
$this->sendCallback();
|
|
}
|
|
function sendOutput($output) {
|
|
if ($this->encrypt >= 3) {
|
|
$this->buffer .= "phprpc_output=\"" . $this->encodeString(xxtea_encrypt($output, $this->key)) . "\";\r\n";
|
|
}
|
|
else {
|
|
$this->buffer .= "phprpc_output=\"" . $this->encodeString($output, false) . "\";\r\n";
|
|
}
|
|
}
|
|
function sendError($output = NULL) {
|
|
if (is_null($output)) {
|
|
$output = ob_get_clean();
|
|
}
|
|
$this->buffer .= "phprpc_errno=\"{$this->errno}\";\r\n";
|
|
$this->buffer .= "phprpc_errstr=\"" . $this->encodeString($this->errstr, false) . "\";\r\n";
|
|
$this->sendOutput($output);
|
|
$this->sendCallback();
|
|
}
|
|
function fatalErrorHandler($buffer) {
|
|
if (preg_match('/<b>(.*?) error<\/b>:(.*?)<br/', $buffer, $match)) {
|
|
if ($match[1] == 'Fatal') {
|
|
$errno = E_ERROR;
|
|
}
|
|
else {
|
|
$errno = E_COMPILE_ERROR;
|
|
}
|
|
if ($this->debug) {
|
|
$errstr = preg_replace('/<.*?>/', '', $match[2]);
|
|
}
|
|
else {
|
|
$errstr = preg_replace('/ in <b>.*<\/b>$/', '', $match[2]);
|
|
}
|
|
|
|
$buffer = "phprpc_errno=\"{$errno}\";\r\n" .
|
|
"phprpc_errstr=\"" . $this->encodeString(trim($errstr), false) . "\";\r\n" .
|
|
"phprpc_output=\"\";\r\n" .
|
|
$this->callback;
|
|
$buffer = $this->gzip($buffer);
|
|
}
|
|
return $buffer;
|
|
}
|
|
function errorHandler($errno, $errstr, $errfile, $errline) {
|
|
if ($this->debug) {
|
|
$errstr .= " in $errfile on line $errline";
|
|
}
|
|
if (($errno == E_ERROR) or ($errno == E_CORE_ERROR) or
|
|
($errno == E_COMPILE_ERROR) or ($errno == E_USER_ERROR)) {
|
|
$this->errno = $errno;
|
|
$this->errstr = $errstr;
|
|
$this->sendError();
|
|
}
|
|
else {
|
|
if (($errno == E_NOTICE) or ($errno == E_USER_NOTICE)) {
|
|
if ($this->errno == 0) {
|
|
$this->errno = $errno;
|
|
$this->errstr = $errstr;
|
|
}
|
|
}
|
|
else {
|
|
if (($this->errno == 0) or
|
|
($this->errno == E_NOTICE) or
|
|
($this->errno == E_USER_NOTICE)) {
|
|
$this->errno = $errno;
|
|
$this->errstr = $errstr;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function exceptionHandler($exception) {
|
|
$this->errno = $exception->getCode();
|
|
$this->errstr = $exception->getMessage();
|
|
if ($this->debug) {
|
|
$this->errstr .= "\nfile: " . $exception->getFile() .
|
|
"\nline: " . $exception->getLine() .
|
|
"\ntrace: " . $exception->getTraceAsString();
|
|
}
|
|
$this->sendError();
|
|
}
|
|
function initErrorHandler() {
|
|
$this->errno = 0;
|
|
$this->errstr = "";
|
|
set_error_handler(array(&$this, 'errorHandler'));
|
|
if (function_exists('set_exception_handler')) {
|
|
set_exception_handler(array(&$this, 'exceptionHandler'));
|
|
}
|
|
}
|
|
function call($function, &$args) {
|
|
if ($this->ref) {
|
|
$arguments = array();
|
|
for ($i = 0; $i < count($args); $i++) {
|
|
$arguments[$i] = &$args[$i];
|
|
}
|
|
}
|
|
else {
|
|
$arguments = $args;
|
|
}
|
|
return call_user_func_array($function, $arguments);
|
|
}
|
|
function getRequest($name) {
|
|
$result = $_REQUEST[$name];
|
|
if (get_magic_quotes_gpc()) {
|
|
$result = stripslashes($result);
|
|
}
|
|
return $result;
|
|
}
|
|
function getBooleanRequest($name) {
|
|
$var = true;
|
|
if (isset($_REQUEST[$name])) {
|
|
$var = strtolower($this->getRequest($name));
|
|
if ($var == "false") {
|
|
$var = false;
|
|
}
|
|
}
|
|
return $var;
|
|
}
|
|
function initEncode() {
|
|
$this->encode = $this->getBooleanRequest('phprpc_encode');
|
|
}
|
|
function initRef() {
|
|
$this->ref = $this->getBooleanRequest('phprpc_ref');
|
|
}
|
|
function initCallback() {
|
|
if (isset($_REQUEST['phprpc_callback'])) {
|
|
$this->callback = base64_decode($this->getRequest('phprpc_callback'));
|
|
}
|
|
else {
|
|
$this->callback = "";
|
|
}
|
|
}
|
|
function initKeylen() {
|
|
if (isset($_REQUEST['phprpc_keylen'])) {
|
|
$this->keylen = (int)$this->getRequest('phprpc_keylen');
|
|
}
|
|
else if (isset($_SESSION[$this->cid])) {
|
|
$session = unserialize(base64_decode($_SESSION[$this->cid]));
|
|
if (isset($session['keylen'])) {
|
|
$this->keylen = $session['keylen'];
|
|
}
|
|
else {
|
|
$this->keylen = 128;
|
|
}
|
|
}
|
|
else {
|
|
$this->keylen = 128;
|
|
}
|
|
}
|
|
function initClientID() {
|
|
$this->cid = 0;
|
|
if (isset($_REQUEST['phprpc_id'])) {
|
|
$this->cid = $this->getRequest('phprpc_id');
|
|
}
|
|
$this->cid = "phprpc_" . $this->cid;
|
|
}
|
|
function initEncrypt() {
|
|
$this->encrypt = false;
|
|
if (isset($_REQUEST['phprpc_encrypt'])) {
|
|
$this->encrypt = $this->getRequest('phprpc_encrypt');
|
|
if ($this->encrypt === "true") $this->encrypt = true;
|
|
if ($this->encrypt === "false") $this->encrypt = false;
|
|
}
|
|
}
|
|
function initKey() {
|
|
if ($this->encrypt == 0) {
|
|
return;
|
|
}
|
|
else if (isset($_SESSION[$this->cid])) {
|
|
$session = unserialize(base64_decode($_SESSION[$this->cid]));
|
|
if (isset($session['key'])) {
|
|
$this->key = $session['key'];
|
|
require_once('xxtea.php');
|
|
return;
|
|
}
|
|
}
|
|
$this->errno = E_ERROR;
|
|
$this->errstr = "Can't find the key for decryption.";
|
|
$this->encrypt = 0;
|
|
$this->sendError();
|
|
}
|
|
function getArguments() {
|
|
if (isset($_REQUEST['phprpc_args'])) {
|
|
$arguments = unserialize($this->decryptString(base64_decode($this->getRequest('phprpc_args')), 1));
|
|
ksort($arguments);
|
|
}
|
|
else {
|
|
$arguments = array();
|
|
}
|
|
return $arguments;
|
|
}
|
|
function callFunction() {
|
|
$this->initKey();
|
|
$function = strtolower($this->getRequest('phprpc_func'));
|
|
if (array_key_exists($function, $this->functions)) {
|
|
$function = $this->functions[$function];
|
|
$arguments = $this->getArguments();
|
|
$result = $this->encodeString($this->encryptString(serialize_fix($this->call($function, $arguments)), 2));
|
|
$output = ob_get_clean();
|
|
$this->buffer .= "phprpc_result=\"$result\";\r\n";
|
|
if ($this->ref) {
|
|
$arguments = $this->encodeString($this->encryptString(serialize_fix($arguments), 1));
|
|
$this->buffer .= "phprpc_args=\"$arguments\";\r\n";
|
|
}
|
|
}
|
|
else {
|
|
$this->errno = E_ERROR;
|
|
$this->errstr = "Can't find this function $function().";
|
|
$output = ob_get_clean();
|
|
}
|
|
$this->sendError($output);
|
|
}
|
|
function keyExchange() {
|
|
require_once('bigint.php');
|
|
$this->initKeylen();
|
|
if (isset($_SESSION[$this->cid])) {
|
|
$session = unserialize(base64_decode($_SESSION[$this->cid]));
|
|
}
|
|
else {
|
|
$session = array();
|
|
}
|
|
if ($this->encrypt === true) {
|
|
require_once('dhparams.php');
|
|
$DHParams = new DHParams($this->keylen);
|
|
$this->keylen = $DHParams->getL();
|
|
$encrypt = $DHParams->getDHParams();
|
|
$x = bigint_random($this->keylen - 1, true);
|
|
$session['x'] = bigint_num2dec($x);
|
|
$session['p'] = $encrypt['p'];
|
|
$session['keylen'] = $this->keylen;
|
|
$encrypt['y'] = bigint_num2dec(bigint_powmod(bigint_dec2num($encrypt['g']), $x, bigint_dec2num($encrypt['p'])));
|
|
$this->buffer .= "phprpc_encrypt=\"" . $this->encodeString(serialize_fix($encrypt)) . "\";\r\n";
|
|
if ($this->keylen != 128) {
|
|
$this->buffer .= "phprpc_keylen=\"{$this->keylen}\";\r\n";
|
|
}
|
|
$this->sendURL();
|
|
}
|
|
else {
|
|
$y = bigint_dec2num($this->encrypt);
|
|
$x = bigint_dec2num($session['x']);
|
|
$p = bigint_dec2num($session['p']);
|
|
$key = bigint_powmod($y, $x, $p);
|
|
if ($this->keylen == 128) {
|
|
$key = bigint_num2str($key);
|
|
}
|
|
else {
|
|
$key = pack('H*', md5(bigint_num2dec($key)));
|
|
}
|
|
$session['key'] = str_pad($key, 16, "\0", STR_PAD_LEFT);
|
|
}
|
|
$_SESSION[$this->cid] = base64_encode(serialize($session));
|
|
$this->sendCallback();
|
|
}
|
|
function initSession() {
|
|
@ob_start();
|
|
ob_implicit_flush(0);
|
|
session_start();
|
|
}
|
|
function initOutputBuffer() {
|
|
@ob_start(array(&$this, "fatalErrorHandler"));
|
|
ob_implicit_flush(0);
|
|
$this->buffer = "";
|
|
}
|
|
// Public Methods
|
|
function PHPRPC_Server() {
|
|
require_once('compat.php');
|
|
$this->functions = array();
|
|
$this->charset = 'UTF-8';
|
|
$this->debug = false;
|
|
$this->enableGZIP = false;
|
|
}
|
|
function add($functions, $obj = NULL, $aliases = NULL) {
|
|
if (is_null($functions) || (gettype($functions) != gettype($aliases) && !is_null($aliases))) {
|
|
return false;
|
|
}
|
|
if (is_object($functions)) {
|
|
$obj = $functions;
|
|
$functions = get_class_methods(get_class($obj));
|
|
$aliases = $functions;
|
|
}
|
|
if (is_null($aliases)) {
|
|
$aliases = $functions;
|
|
}
|
|
if (is_string($functions)) {
|
|
if (is_null($obj)) {
|
|
$this->functions[strtolower($aliases)] = $functions;
|
|
}
|
|
else if (is_object($obj)) {
|
|
$this->functions[strtolower($aliases)] = array(&$obj, $functions);
|
|
}
|
|
else if (is_string($obj)) {
|
|
$this->functions[strtolower($aliases)] = array($obj, $functions);
|
|
}
|
|
}
|
|
else {
|
|
if (count($functions) != count($aliases)) {
|
|
return false;
|
|
}
|
|
foreach ($functions as $key => $function) {
|
|
$this->add($function, $obj, $aliases[$key]);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
function setCharset($charset) {
|
|
$this->charset = $charset;
|
|
}
|
|
function setDebugMode($debug) {
|
|
$this->debug = $debug;
|
|
}
|
|
function setEnableGZIP($enableGZIP) {
|
|
$this->enableGZIP = $enableGZIP;
|
|
}
|
|
function start() {
|
|
while(ob_get_length() !== false) @ob_end_clean();
|
|
$this->initOutputBuffer();
|
|
$this->sendHeader();
|
|
$this->initErrorHandler();
|
|
$this->initEncode();
|
|
$this->initCallback();
|
|
$this->initRef();
|
|
$this->initClientID();
|
|
$this->initEncrypt();
|
|
if (isset($_REQUEST['phprpc_func'])) {
|
|
$this->callFunction();
|
|
}
|
|
else if ($this->encrypt != false) {
|
|
$this->keyExchange();
|
|
}
|
|
else {
|
|
$this->sendFunctions();
|
|
}
|
|
}
|
|
}
|
|
|
|
PHPRPC_Server::initSession();
|
|
?>
|