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();
|
||
|
|
?>
|