本文给出了 PHPRPC 2.1 协议的 Ajax 客户端实现。该客户端的使用方式与 2.0 版本的使用方式基本上相同。不同点在于如果要调用的远程函数是引用参数传递的话,需要在调用前设置该函数的 ref 属性为 true。该属性表示是否是引用参数传递。该属性默认为 false。推荐在客户端对象的 onready 事件中进行设置。
下面为该客户端的实现代码:
-
/* phprpc_ajax_client.js - Ajax PHPRPC Client
-
*
-
* Copyright Ma Bingyao <andot@ujn.edu.cn>
-
* Version: 2.1
-
* LastModified: 2006-03-12
-
* This library is free. You can redistribute it and/or modify it.
-
*/
-
-
/*
-
* Interfaces:
-
* phprpc_client.create('rpc');
-
* rpc.use_service('http://domain.com/phprpc/server.php');
-
* rpc.method_callback = function(result, args, output) {
-
* if (result instanceof phprpc_error) {
-
* alert(result.errstr);
-
* }
-
* else {
-
* alert(result); // or do any other things.
-
* }
-
* }
-
* ....
-
* if (rpc.ready) rpc.method();
-
*/
-
-
function phprpc_error(errno, errstr) {
-
this.errno = errno;
-
this.errstr = errstr;
-
}
-
-
function phprpc_client() {
-
this.__php = new PHP_Serializer();
-
this.__url = '';
-
this.__encrypt = false;
-
this.encrypt = 0;
-
this.async = true;
-
this.ready = false;
-
this.args = null;
-
this.output = "";
-
this.use_service = function (url, encrypt) {
-
if (typeof(encrypt) == "undefined") {
-
encrypt = this.__encrypt;
-
}
-
if (typeof(this.__name) == "undefined") {
-
return false;
-
}
-
this.__url = url;
-
var xmlhttp = this.__create_xmlhttp();
-
var __rpc = this;
-
if (encrypt === true) {
-
xmlhttp.onreadystatechange = function () {
-
if (xmlhttp.readyState == 4) {
-
if (xmlhttp.responseText) {
-
eval(xmlhttp.responseText);
-
if (typeof(phprpc_encrypt) == "undefined") {
-
__rpc.__encrypt = false;
-
__rpc.use_service(__rpc.__url);
-
}
-
else {
-
__rpc.__encrypt = __rpc.__php.unserialize(phprpc_encrypt);
-
__rpc.__encrypt['p'] = dec2num(__rpc.__encrypt['p']);
-
__rpc.__encrypt['g'] = dec2num(__rpc.__encrypt['g']);
-
__rpc.__encrypt['y'] = dec2num(__rpc.__encrypt['y']);
-
__rpc.__encrypt['x'] = rand(127, 1);
-
var key = pow_mod(__rpc.__encrypt['y'],
-
__rpc.__encrypt['x'],
-
__rpc.__encrypt['p']);
-
key = num2str(key);
-
for (var i = 0; i < 16 - key.length; i++) {
-
key = '\0' + key;
-
}
-
__rpc.__encrypt['k'] = key;
-
var encrypt = pow_mod(__rpc.__encrypt['g'],
-
__rpc.__encrypt['x'],
-
__rpc.__encrypt['p']);
-
__rpc.use_service(__rpc.__url, num2dec(encrypt).replace(/\+/g, '%2B'));
-
}
-
}
-
delete(xmlhttp);
-
}
-
}
-
}
-
else {
-
xmlhttp.onreadystatechange = function () {
-
if (xmlhttp.readyState == 4) {
-
if (xmlhttp.responseText) {
-
eval(xmlhttp.responseText);
-
var functions = __rpc.__php.unserialize(phprpc_functions);
-
var func;
-
for (var i = 0; i < functions.length; i++) {
-
func = __rpc.__name + "." + functions[i] + " = function () {\r\n";
-
func += " this.__call('" + functions[i] + "', this.__args_to_array(arguments));\r\n";
-
func += "}\r\n";
-
func += __rpc.__name + "." + functions[i] + ".ref = false;\r\n";
-
eval(func);
-
}
-
__rpc.ready = true;
-
if (typeof(__rpc.onready) == "function") {
-
__rpc.onready();
-
}
-
}
-
delete(xmlhttp);
-
}
-
}
-
}
-
xmlhttp.open("get", this.__url + '?phprpc_encrypt=' + encrypt + '&phprpc_encode=false', true);
-
xmlhttp.send(null);
-
};
-
this.__call = function (func, args) {
-
var __args = this.__php.serialize(args);
-
if ((this.__encrypt !== false) && (this.encrypt > 0)) {
-
__args = xxtea_encrypt(__args, this.__encrypt['k']);
-
}
-
__args = base64encode(__args);
-
var request = 'phprpc_func=' + func
-
+ '&phprpc_args=' + __args
-
+ '&phprpc_encode=false'
-
+ '&phprpc_encrypt=' + this.encrypt;
-
var ref = eval(this.__name + "." + func + ".ref");
-
if (!ref) {
-
request += '&phprpc_ref=false';
-
}
-
var xmlhttp = this.__create_xmlhttp();
-
var session = {'args': args, 'ref': ref, 'encrypt': this.encrypt};
-
if (this.async) {
-
var __rpc = this;
-
xmlhttp.onreadystatechange = function () {
-
if (xmlhttp.readyState == 4) {
-
if (xmlhttp.responseText) {
-
__rpc.__get_result(xmlhttp, session);
-
if (typeof(eval(__rpc.__name + "." + func + "_callback")) == "function") {
-
eval(__rpc.__name + "." + func + "_callback(phprpc_result, phprpc_args, phprpc_output);");
-
}
-
}
-
delete(xmlhttp);
-
}
-
}
-
}
-
xmlhttp.open("post", this.__url, this.async);
-
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
-
xmlhttp.send(request.replace(/\+/g, '%2B'));
-
if (!this.async) {
-
if (xmlhttp.responseText) {
-
this.__get_result(xmlhttp, session);
-
this.output = phprpc_output;
-
this.args = phprpc_args;
-
return phprpc_result;
-
}
-
else {
-
return new phprpc_error(1, "No data received from server");
-
}
-
delete(xmlhttp);
-
}
-
};
-
this.__get_result = function (xmlhttp, session) {
-
eval(xmlhttp.responseText);
-
if (phprpc_errno == 0) {
-
if ((this.__encrypt !== false) && (session.encrypt > 0)) {
-
if (session.encrypt > 1) {
-
phprpc_result = xxtea_decrypt(phprpc_result, this.__encrypt['k']);
-
}
-
if (session.ref) {
-
phprpc_args = xxtea_decrypt(phprpc_args, this.__encrypt['k']);
-
}
-
}
-
phprpc_result = this.__php.unserialize(phprpc_result);
-
if (session.ref) {
-
phprpc_args = this.__php.unserialize(phprpc_args);
-
}
-
else {
-
phprpc_args = this.args;
-
}
-
}
-
else {
-
phprpc_result = new phprpc_error(phprpc_errno, phprpc_errstr);
-
phprpc_args = null;
-
}
-
}
-
// the function __create_xmlhttp modified from
-
this.__create_xmlhttp = function() {
-
if (window.XMLHttpRequest) {
-
var objXMLHttp = new XMLHttpRequest();
-
-
// some older versions of Moz did not support the readyState property
-
// and the onreadystate event so we patch it!
-
if (objXMLHttp.readyState == null) {
-
objXMLHttp.readyState = 0;
-
objXMLHttp.addEventListener(
-
"load",
-
function () {
-
objXMLHttp.readyState = 4;
-
if (typeof(objXMLHttp.onreadystatechange) == "function") {
-
objXMLHttp.onreadystatechange();
-
}
-
},
-
false
-
);
-
}
-
return objXMLHttp;
-
}
-
else {
-
var MSXML = ['MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'];
-
for(var n = 0; n < MSXML.length; n ++) {
-
try {
-
return objXMLHttp = new ActiveXObject(MSXML[n]);
-
}
-
catch(e) {}
-
}
-
throw new Error("Your browser does not support xmlhttp objects");
-
}
-
};
-
this.__args_to_array = function (args) {
-
argArray = [];
-
for (i = 0; i < args.length; i++) {
-
argArray[i] = args[i];
-
}
-
return argArray;
-
}
-
}
-
-
phprpc_client.create = function (name, encrypt) {
-
eval(name + ' = new phprpc_client();');
-
eval(name + '.__name = "' + name + '";');
-
if (encrypt) {
-
encrypt = true;
-
eval(name + '.__encrypt = ' + encrypt + ';');
-
}
-
}
