PageRenderTime 26ms CodeModel.GetById 1ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

/Inc/Lib/ORG/PHPRPC/phprpc_client.php

http://iiccms.googlecode.com/
PHP | 583 lines | 315 code | 17 blank | 251 comment | 72 complexity | a6826f19e97bd0a6f044717546d11274 MD5 | raw file
  1<?php
  2/**********************************************************\
  3|                                                          |
  4| The implementation of PHPRPC Protocol 3.0                |
  5|                                                          |
  6| phprpc_client.php                                        |
  7|                                                          |
  8| Release 3.0.1                                            |
  9| Copyright by Team-PHPRPC                                 |
 10|                                                          |
 11| WebSite:  http://www.phprpc.org/                         |
 12|           http://www.phprpc.net/                         |
 13|           http://www.phprpc.com/                         |
 14|           http://sourceforge.net/projects/php-rpc/       |
 15|                                                          |
 16| Authors:  Ma Bingyao <andot@ujn.edu.cn>                  |
 17|                                                          |
 18| This file may be distributed and/or modified under the   |
 19| terms of the GNU Lesser General Public License (LGPL)    |
 20| version 3.0 as published by the Free Software Foundation |
 21| and appearing in the included file LICENSE.              |
 22|                                                          |
 23\**********************************************************/
 24
 25/* PHPRPC Client for PHP.
 26 *
 27 * Copyright: Ma Bingyao <andot@ujn.edu.cn>
 28 * Version: 3.0
 29 * LastModified: Apr 28, 2009
 30 * This library is free.  You can redistribute it and/or modify it.
 31 *
 32/*
 33 * Interfaces
 34 *
 35 * $rpc_client = new PHPRPC_Client();
 36 * $rpc_client->setProxy(NULL);
 37 * $rpc_client->useService('http://www.phprpc.org/server.php');
 38 * $rpc_client->setKeyLength(1024);
 39 * $rpc_client->setEncryptMode(3);
 40 * $args = array(1, 2);
 41 * echo $rpc_client->invoke('add', &$args);
 42 * echo "<br />";
 43 * $n = 3;
 44 * $args = array(&$n);
 45 * echo $rpc_client->invoke('inc', &$args, true);
 46 * echo "<br />";
 47 * echo $rpc_client->sub(3, 2);
 48 * echo "<br />";
 49 * // error handle
 50 * $result = $rpc_client->mul(1, 2);  // no mul function
 51 * if (is_a($result, "PHPRPC_Error")) {
 52 *     echo $result->toString();
 53 * }
 54 */
 55
 56
 57$_PHPRPC_COOKIES = array();
 58$_PHPRPC_COOKIE = '';
 59$_PHPRPC_SID = 0;
 60
 61if (defined('KEEP_PHPRPC_COOKIE_IN_SESSION')) {
 62    if (isset($_SESSION['phprpc_cookies']) and isset($_SESSION['phprpc_cookie'])) {
 63        $_PHPRPC_COOKIES = $_SESSION['phprpc_cookies'];
 64        $_PHPRPC_COOKIE = $_SESSION['phprpc_cookie'];
 65    }
 66    function keep_phprpc_cookie_in_session() {
 67        global $_PHPRPC_COOKIES, $_PHPRPC_COOKIE;
 68        $_SESSION['phprpc_cookies'] = $_PHPRPC_COOKIES;
 69        $_SESSION['phprpc_cookie'] = $_PHPRPC_COOKIE;
 70    }
 71    register_shutdown_function('keep_phprpc_cookie_in_session');
 72}
 73
 74class PHPRPC_Error {
 75    var $Number;
 76    var $Message;
 77    function PHPRPC_Error($errno, $errstr) {
 78        $this->Number = $errno;
 79        $this->Message = $errstr;
 80    }
 81    function toString() {
 82        return $this->Number . ":" . $this->Message;
 83    }
 84    function __toString() {
 85        return $this->toString();
 86    }
 87    function getNumber() {
 88        return $this->Number;
 89    }
 90    function getMessage() {
 91        return $this->Message;
 92    }
 93}
 94
 95class _PHPRPC_Client {
 96    var $_server;
 97    var $_timeout;
 98    var $_output;
 99    var $_warning;
100    var $_proxy;
101    var $_key;
102    var $_keylen;
103    var $_encryptMode;
104    var $_charset;
105    var $_socket;
106    var $_clientid;
107    var $_http_version;
108    var $_keep_alive;
109    // Public Methods
110    function _PHPRPC_Client($serverURL = '') {
111        global $_PHPRPC_SID;
112        require_once('compat.php');
113        register_shutdown_function(array(&$this, "_disconnect"));
114        $this->_proxy = NULL;
115        $this->_timeout = 30;
116        $this->_clientid = 'php' . rand(1 << 30, 1 << 31) . time() . $_PHPRPC_SID;
117        $_PHPRPC_SID++;
118        $this->_socket = false;
119        if ($serverURL != '') {
120            $this->useService($serverURL);
121        }
122    }
123    function useService($serverURL, $username = NULL, $password = NULL) {
124        $this->_disconnect();
125        $this->_http_version = "1.1";
126        $this->_keep_alive = true;
127        $this->_server = array();
128        $this->_key = NULL;
129        $this->_keylen = 128;
130        $this->_encryptMode = 0;
131        $this->_charset = 'utf-8';
132        $urlparts = parse_url($serverURL);
133        if (!isset($urlparts['host'])) {
134            if (isset($_SERVER["HTTP_HOST"])) {
135                $urlparts['host'] = $_SERVER["HTTP_HOST"];
136            }
137            else if (isset($_SERVER["SERVER_NAME"])) {
138                $urlparts['host'] = $_SERVER["SERVER_NAME"];
139            }
140            else {
141                $urlparts['host'] = "localhost";
142            }
143            if (!isset($_SERVER["HTTPS"]) ||
144                $_SERVER["HTTPS"] == "off"  ||
145                $_SERVER["HTTPS"] == "") {
146                $urlparts['scheme'] = "http";
147            }
148            else {
149                $urlparts['scheme'] = "https";
150            }
151            $urlparts['port'] = $_SERVER["SERVER_PORT"];
152        }
153
154        if (!isset($urlparts['port'])) {
155            if ($urlparts['scheme'] == "https") {
156                $urlparts['port'] = 443;
157            }
158            else {
159                $urlparts['port'] = 80;
160            }
161        }
162
163        if (!isset($urlparts['path'])) {
164            $urlparts['path'] = "/";
165        }
166        else if (($urlparts['path']{0} != '/') && ($_SERVER["PHP_SELF"]{0} == '/')) {
167            $urlparts['path'] = substr($_SERVER["PHP_SELF"], 0, strrpos($_SERVER["PHP_SELF"], '/') + 1) . $urlparts['path'];
168        }
169
170        if (isset($urlparts['query'])) {
171            $urlparts['path'] .= '?' . $urlparts['query'];
172        }
173
174        if (!isset($urlparts['user']) || !is_null($username)) {
175            $urlparts['user'] = $username;
176        }
177
178        if (!isset($urlparts['pass']) || !is_null($password)) {
179            $urlparts['pass'] = $password;
180        }
181
182        $this->_server['scheme'] = $urlparts['scheme'];
183        $this->_server['host'] = $urlparts['host'];
184        $this->_server['port'] = $urlparts['port'];
185        $this->_server['path'] = $urlparts['path'];
186        $this->_server['user'] = $urlparts['user'];
187        $this->_server['pass'] = $urlparts['pass'];
188    }
189    function setProxy($host, $port = NULL, $username = NULL, $password = NULL) {
190        if (is_null($host)) {
191            $this->_proxy = NULL;
192        }
193        else {
194            if (is_null($port)) {
195                $urlparts = parse_url($host);
196                if (isset($urlparts['host'])) {
197                    $host = $urlparts['host'];
198                }
199                if (isset($urlparts['port'])) {
200                    $port = $urlparts['port'];
201                }
202                else {
203                    $port = 80;
204                }
205                if (isset($urlparts['user']) && is_null($username)) {
206                    $username = $urlparts['user'];
207                }
208                if (isset($urlparts['pass']) && is_null($password)) {
209                    $password = $urlparts['pass'];
210                }
211            }
212            $this->_proxy = array();
213            $this->_proxy['host'] = $host;
214            $this->_proxy['port'] = $port;
215            $this->_proxy['user'] = $username;
216            $this->_proxy['pass'] = $password;
217        }
218    }
219    function setKeyLength($keylen) {
220        if (!is_null($this->_key)) {
221            return false;
222        }
223        else {
224            $this->_keylen = $keylen;
225            return true;
226        }
227    }
228    function getKeyLength() {
229        return $this->_keylen;
230    }
231    function setEncryptMode($encryptMode) {
232        if (($encryptMode >= 0) && ($encryptMode <= 3)) {
233            $this->_encryptMode = (int)($encryptMode);
234            return true;
235        }
236        else {
237            $this->_encryptMode = 0;
238            return false;
239        }
240    }
241    function getEncryptMode() {
242        return $this->_encryptMode;
243    }
244    function setCharset($charset) {
245        $this->_charset = $charset;
246    }
247    function getCharset() {
248        return $this->_charset;
249    }
250    function setTimeout($timeout) {
251        $this->_timeout = $timeout;
252    }
253    function getTimeout() {
254        return $this->_timeout;
255    }
256    function invoke($funcname, &$args, $byRef = false) {
257        $result = $this->_key_exchange();
258        if (is_a($result, 'PHPRPC_Error')) {
259            return $result;
260        }
261        $request = "phprpc_func=$funcname";
262        if (count($args) > 0) {
263            $request .= "&phprpc_args=" . base64_encode($this->_encrypt(serialize_fix($args), 1));
264        }
265        $request .= "&phprpc_encrypt={$this->_encryptMode}";
266        if (!$byRef) {
267            $request .= "&phprpc_ref=false";
268        }
269        $request = str_replace('+', '%2B', $request);
270        $result = $this->_post($request);
271        if (is_a($result, 'PHPRPC_Error')) {
272            return $result;
273        }
274        $phprpc_errno = 0;
275        $phprpc_errstr = NULL;
276        if (isset($result['phprpc_errno'])) {
277            $phprpc_errno = intval($result['phprpc_errno']);
278        }
279        if (isset($result['phprpc_errstr'])) {
280            $phprpc_errstr = base64_decode($result['phprpc_errstr']);
281        }
282        $this->_warning = new PHPRPC_Error($phprpc_errno, $phprpc_errstr);
283        if (array_key_exists('phprpc_output', $result)) {
284            $this->_output = base64_decode($result['phprpc_output']);
285            if ($this->_server['version'] >= 3) {
286                $this->_output = $this->_decrypt($this->_output, 3);
287            }
288        }
289        else {
290            $this->_output = '';
291        }
292        if (array_key_exists('phprpc_result', $result)) {
293            if (array_key_exists('phprpc_args', $result)) {
294                $arguments = unserialize($this->_decrypt(base64_decode($result['phprpc_args']), 1));
295                for ($i = 0; $i < count($arguments); $i++) {
296                    $args[$i] = $arguments[$i];
297                }
298            }
299            $result = unserialize($this->_decrypt(base64_decode($result['phprpc_result']), 2));
300        }
301        else {
302            $result = $this->_warning;
303        }
304        return $result;
305    }
306
307    function getOutput() {
308        return $this->_output;
309    }
310
311    function getWarning() {
312        return $this->_warning;
313    }
314
315    function _connect() {
316        if (is_null($this->_proxy)) {
317            $host = (($this->_server['scheme'] == "https") ? "ssl://" : "") . $this->_server['host'];
318            $this->_socket = @fsockopen($host, $this->_server['port'], $errno, $errstr, $this->_timeout);
319        }
320        else {
321            $host = (($this->_server['scheme'] == "https") ? "ssl://" : "") . $this->_proxy['host'];
322            $this->_socket = @fsockopen($host, $this->_proxy['port'], $errno, $errstr, $this->_timeout);
323        }
324        if ($this->_socket === false) {
325            return new PHPRPC_Error($errno, $errstr);
326        }
327        stream_set_write_buffer($this->_socket, 0);
328        socket_set_timeout($this->_socket, $this->_timeout);
329        return true;
330    }
331
332    function _disconnect() {
333        if ($this->_socket !== false) {
334            fclose($this->_socket);
335            $this->_socket = false;
336        }
337    }
338
339    function _socket_read($size) {
340        $content = "";
341        while (!feof($this->_socket) && ($size > 0)) {
342            $str = fread($this->_socket, $size);
343            $content .= $str;
344            $size -= strlen($str);
345        }
346        return $content;
347    }
348    function _post($request_body) {
349        global $_PHPRPC_COOKIE;
350        $request_body = 'phprpc_id=' . $this->_clientid . '&' . $request_body;
351        if ($this->_socket === false) {
352            $error = $this->_connect();
353            if (is_a($error, 'PHPRPC_Error')) {
354                return $error;
355            }
356        }
357        if (is_null($this->_proxy)) {
358            $url = $this->_server['path'];
359            $connection = "Connection: " . ($this->_keep_alive ? 'keep-alive' : 'close') . "\r\n" .
360                          "Cache-Control: no-cache\r\n";
361        }
362        else {
363            $url = "{$this->_server['scheme']}://{$this->_server['host']}:{$this->_server['port']}{$this->_server['path']}";
364            $connection = "Proxy-Connection: " . ($this->_keep_alive ? 'keep-alive' : 'close') . "\r\n";
365            if (!is_null($this->_proxy['user'])) {
366                $connection .= "Proxy-Authorization: Basic " . base64_encode($this->_proxy['user'] . ":" . $this->_proxy['pass']) . "\r\n";
367            }
368        }
369        $auth = '';
370        if (!is_null($this->_server['user'])) {
371            $auth = "Authorization: Basic " . base64_encode($this->_server['user'] . ":" . $this->_server['pass']) . "\r\n";
372        }
373        $cookie = '';
374        if ($_PHPRPC_COOKIE) {
375            $cookie = "Cookie: " . $_PHPRPC_COOKIE . "\r\n";
376        }
377        $content_len = strlen($request_body);
378        $request =
379            "POST $url HTTP/{$this->_http_version}\r\n" .
380            "Host: {$this->_server['host']}:{$this->_server['port']}\r\n" .
381            "User-Agent: PHPRPC Client 3.0 for PHP\r\n" .
382            $auth .
383            $connection .
384            $cookie .
385            "Accept: */*\r\n" .
386            "Accept-Encoding: gzip,deflate\r\n" .
387            "Content-Type: application/x-www-form-urlencoded; charset={$this->_charset}\r\n" .
388            "Content-Length: {$content_len}\r\n" .
389            "\r\n" .
390            $request_body;
391        fputs($this->_socket, $request, strlen($request));
392        while (!feof($this->_socket)) {
393            $line = fgets($this->_socket);
394            if (preg_match('/HTTP\/(\d\.\d)\s+(\d+)([^(\r|\n)]*)(\r\n|$)/i', $line, $match)) {
395                $this->_http_version = $match[1];
396                $status = (int)$match[2];
397                $status_message = trim($match[3]);
398                if ($status != 100 && $status != 200) {
399                    $this->_disconnect();
400                    return new PHPRPC_Error($status, $status_message);
401                }
402            }
403            else {
404                $this->_disconnect();
405                return new PHPRPC_Error(E_ERROR, "Illegal HTTP server.");
406            }
407            $header = array();
408            while (!feof($this->_socket) && (($line = fgets($this->_socket)) != "\r\n")) {
409                $line = explode(':', $line, 2);
410                $header[strtolower($line[0])][] =trim($line[1]);
411            }
412            if ($status == 100) continue;
413            $response_header = $this->_parseHeader($header);
414            if (is_a($response_header, 'PHPRPC_Error')) {
415                $this->_disconnect();
416                return $response_header;
417            }
418            break;
419        }
420        $response_body = '';
421        if (isset($response_header['transfer_encoding']) && (strtolower($response_header['transfer_encoding']) == 'chunked')) {
422            $s = fgets($this->_socket);
423            if ($s == "") {
424                $this->_disconnect();
425                return array();
426            }
427            $chunk_size = (int)hexdec($s);
428            while ($chunk_size > 0) {
429                $response_body .= $this->_socket_read($chunk_size);
430                if (fgets($this->_socket) != "\r\n") {
431                    $this->_disconnect();
432                    return new PHPRPC_Error(1, "Response is incorrect.");
433                }
434                $chunk_size = (int)hexdec(fgets($this->_socket));
435            }
436            fgets($this->_socket);
437        }
438        elseif (isset($response_header['content_length']) && !is_null($response_header['content_length'])) {
439            $response_body = $this->_socket_read($response_header['content_length']);
440        }
441        else {
442            while (!feof($this->_socket)) {
443                $response_body .= fread($this->_socket, 4096);
444            }
445            $this->_keep_alive = false;
446            $this->_disconnect();
447        }
448        if (isset($response_header['content_encoding']) && (strtolower($response_header['content_encoding']) == 'gzip')) {
449            $response_body = gzdecode($response_body);
450        }
451        if (!$this->_keep_alive) $this->_disconnect();
452        if ($this->_keep_alive && strtolower($response_header['connection']) == 'close') {
453            $this->_keep_alive = false;
454            $this->_disconnect();
455        }
456        return $this->_parseBody($response_body);
457    }
458    function _parseHeader($header) {
459        global $_PHPRPC_COOKIE, $_PHPRPC_COOKIES;
460        if (preg_match('/PHPRPC Server\/([^,]*)(,|$)/i', implode(',', $header['x-powered-by']), $match)) {
461            $this->_server['version'] = (float)$match[1];
462        }
463        else {
464            return new PHPRPC_Error(E_ERROR, "Illegal PHPRPC server.");
465        }
466        if (preg_match('/text\/plain\; charset\=([^,;]*)([,;]|$)/i', $header['content-type'][0], $match)) {
467            $this->_charset = $match[1];
468        }
469        if (isset($header['set-cookie'])) {
470            foreach ($header['set-cookie'] as $cookie) {
471                foreach (preg_split('/[;,]\s?/', $cookie) as $c) {
472                    list($name, $value) = explode('=', $c, 2);
473                    if (!in_array($name, array('domain', 'expires', 'path', 'secure'))) {
474                        $_PHPRPC_COOKIES[$name] = $value;
475                    }
476                }
477            }
478            $cookies = array();
479            foreach ($_PHPRPC_COOKIES as $name => $value) {
480                $cookies[] = "$name=$value";
481            }
482            $_PHPRPC_COOKIE = join('; ', $cookies);
483        }
484        if (isset($header['content-length'])) {
485            $content_length = (int)$header['content-length'][0];
486        }
487        else {
488            $content_length = NULL;
489        }
490        $transfer_encoding = isset($header['transfer-encoding']) ? $header['transfer-encoding'][0] : '';
491        $content_encoding = isset($header['content-encoding']) ? $header['content-encoding'][0] : '';
492        $connection = isset($header['connection']) ? $header['connection'][0] : 'close';
493        return array('transfer_encoding' => $transfer_encoding,
494                     'content_encoding' => $content_encoding,
495                     'content_length' => $content_length,
496                     'connection' => $connection);
497    }
498    function _parseBody($body) {
499        $body = explode(";\r\n", $body);
500        $result = array();
501        $n = count($body);
502        for ($i = 0; $i < $n; $i++) {
503            $p = strpos($body[$i], '=');
504            if ($p !== false) {
505                $l = substr($body[$i], 0, $p);
506                $r = substr($body[$i], $p + 1);
507                $result[$l] = trim($r, '"');
508            }
509        }
510        return $result;
511    }
512    function _key_exchange() {
513        if (!is_null($this->_key) || ($this->_encryptMode == 0)) return true;
514        $request = "phprpc_encrypt=true&phprpc_keylen={$this->_keylen}";
515        $result = $this->_post($request);
516        if (is_a($result, 'PHPRPC_Error')) {
517            return $result;
518        }
519        if (array_key_exists('phprpc_keylen', $result)) {
520            $this->_keylen = (int)$result['phprpc_keylen'];
521        }
522        else {
523            $this->_keylen = 128;
524        }
525        if (array_key_exists('phprpc_encrypt', $result)) {
526            $encrypt = unserialize(base64_decode($result['phprpc_encrypt']));
527            require_once('bigint.php');
528            require_once('xxtea.php');
529            $x = bigint_random($this->_keylen - 1, true);
530            $key = bigint_powmod(bigint_dec2num($encrypt['y']), $x, bigint_dec2num($encrypt['p']));
531            if ($this->_keylen == 128) {
532                $key = bigint_num2str($key);
533            }
534            else {
535                $key = pack('H*', md5(bigint_num2dec($key)));
536            }
537            $this->_key = str_pad($key, 16, "\0", STR_PAD_LEFT);
538            $encrypt = bigint_num2dec(bigint_powmod(bigint_dec2num($encrypt['g']), $x, bigint_dec2num($encrypt['p'])));
539            $request = "phprpc_encrypt=$encrypt";
540            $result = $this->_post($request);
541            if (is_a($result, 'PHPRPC_Error')) {
542                return $result;
543            }
544        }
545        else {
546            $this->_key = NULL;
547            $this->_encryptMode = 0;
548        }
549        return true;
550    }
551    function _encrypt($str, $level) {
552        if (!is_null($this->_key) && ($this->_encryptMode >= $level)) {
553            $str = xxtea_encrypt($str, $this->_key);
554        }
555        return $str;
556    }
557    function _decrypt($str, $level) {
558        if (!is_null($this->_key) && ($this->_encryptMode >= $level)) {
559            $str = xxtea_decrypt($str, $this->_key);
560        }
561        return $str;
562    }
563}
564
565if (function_exists("overload") && version_compare(phpversion(), "5", "<")) {
566    eval('
567    class PHPRPC_Client extends _PHPRPC_Client {
568        function __call($function, $arguments, &$return) {
569            $return = $this->invoke($function, $arguments);
570            return true;
571        }
572    }
573    overload("phprpc_client");
574    ');
575}
576else {
577    class PHPRPC_Client extends _PHPRPC_Client {
578        function __call($function, $arguments) {
579            return $this->invoke($function, $arguments);
580        }
581    }
582}
583?>