| | | | This file may be distributed and/or modified under the | | terms of the GNU Lesser General Public License (LGPL) | | version 2.1 as published by the Free Software Foundation | | and appearing in the included file LICENSE. | | | \**********************************************************/ /* PHPRPC Server for PHP. * * Copyright (C) 2007 Ma Bingyao * Version: 3.0.0 beta 5 * LastModified: May 5, 2007 * This library is free. You can redistribute it and/or modify it. * /* * 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"); } 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('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 (stripos($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(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('/(.*?) error<\/b>:(.*?)
debug) { $errstr = preg_replace('/<.*?>/', '', $match[2]); } else { $errstr = preg_replace('/ in .*<\/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]['keylen'])){ $this->keylen = $_SESSION[$this->cid]['keylen']; } 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 (isset($_SESSION[$this->cid]['key'])) { $this->key = $_SESSION[$this->cid]['key']; require_once('xxtea.php'); } else if ($this->encrypt > 0) { $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)); } else { $arguments = array(); } return $arguments; } function callFunction() { $function = strtolower($this->getRequest('phprpc_func')); if (array_key_exists($function, $this->functions)) { $this->initKey(); $function = $this->functions[$function]; $arguments = $this->getArguments(); $result = $this->encodeString($this->encryptString(serialize($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($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 ($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); if (!isset($_SESSION[$this->cid])) { $_SESSION[$this->cid] = array(); } $_SESSION[$this->cid]['x'] = bigint_num2dec($x); $_SESSION[$this->cid]['p'] = $encrypt['p']; $_SESSION[$this->cid]['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($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[$this->cid]['x']); $p = bigint_dec2num($_SESSION[$this->cid]['p']); $key = bigint_powmod($y, $x, $p); if ($this->keylen == 128) { $key = bigint_num2str($key); } else { $key = pack('H*', md5(bigint_num2dec($key))); } $_SESSION[$this->cid]['key'] = str_repeat("\0", 16 - strlen($key)) . $key; } $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(); ?>