浏览模式: 标准 | 列表

原创作品,转载请注明出处。

PHPRPC 3.0 协议的升级主要在于完善 PHPRPC 协议安全性的设计。增加了对输出捕获的加密支持,另外,增加了密钥交换时密钥长度的选项。

在 2.0 和 2.1 协议中,在远程过程调用阶段的请求中的 phprpc_encrypt 参数用来指定加密模式,该参数在 3.0 协议中增加了 3 这个取值,该取值表示除了 phprpc_args 参数和应答中的 phprpc_result 加密以外,应答中的 phprpc_output 也要经过加密处理。

在 2.0 和 2.1 协议中,没有规定密钥交换的长度,所以密钥交换时密钥长度不同的两个实现是无法正常通讯的。但是目前所有的 2.0 和 2.1 实现中,都是按照 128 位的密钥长度进行编写的,因此它们目前没有遇到这种问题。但为了允许更长的密钥交换,并且可以兼容已有的实现。在 PHPRPC 3.0 协议中,增加了 phprpc_keylen 选项。对于该选项的描述如下:

当客户端发起密钥交换请求时,可以带有 phprpc_keylen 参数,该参数值表示密钥交换的位数。例如:

phprpc_keylen=512

如果服务器支持客户端所指定的位数,则进行密钥交换时,在响应中返回相同的参数,但格式按照响应的格式返回,例如:

phprpc_keylen="512";

如果服务器端不支持客户端所指定的位数,则选择支持的最接近客户端所指定的位数进行密钥交换,并且在响应中给出实际的位数,例如:

phprpc_keylen="160";

如果服务器端使用 128 位来进行密钥交换,则响应中可以不给出密钥交换的位数,客户端也应该按照 128 位来进行处理。

该响应参数与 phprpc_encrypt 响应参数都只在密钥交换第一阶段出现。

注意,以前版本的 PHPRPC 协议,phprpc_encrypt 在密钥交换的第二阶段返回一个序列化的 boolean 值 true,但因为该值从来没有被使用过,故而在 3.0 版本中取消该响应。

另外,在密钥交换阶段,不再返回 phprpc_functions 的响应。这样做的目的是为了进一步减少带宽占用。但可能会与早期的 2.0、2.1 版本的某些 JavaScript 客户端实现在加密传输处理上不兼容,但这种兼容性是与协议实现有关的,与 2.0、2.1 版本协议仍然是兼容的。

由于协议的以上变动,因此在密钥交换的第二阶段仅输出请求中 phprpc_callback 参数的值(如果存在的话)。早期的协议对于响应中各个参数的顺序,是有定义的,这样做是为了方便客户端实现。但建议新的客户端在实现时不要过于依赖相应参数的顺序。但对于新的服务器来说,仍然建议按照早期定义的顺序输出响应参数。另外需要强调,请求中 phprpc_callback 参数的值一定要作为响应中的最后一项输出。

为了使 PHPRPC 的浏览器客户端在禁用 cookie 的情况下仍然能够进行密钥交换和加密传输,建议服务器在密钥交换的第一阶段,如果检测到客户端可能不支持基于 cookie 的会话(例如可以检测建立的是否是一个新的会话)时,在输出密钥交换参数(phprpc_encrypt)和密钥长度(phprpc_keylen)选项后,增加一项输出 phprpc_url,例如:

phprpc_url="http://localhost:8080/test/test.jsp;jsessionid=896CE4204292E70D28D27FE7C4503232";

其中 phprpc_url 的值是在原服务地址上增加了服务器会话标示(session id)的地址。会话标示的附加方式由服务器端根据实际情况来决定,如果原客户端地址本身带有 url 请求参数,应该保留原有参数。例如,如果原服务器地址为 http://localhost:8080/test/test.jsp?serverid=2342&action=do,则响应中的 phprpc_url 应为如下格式:

phprpc_url="http://localhost:8080/test/test.jsp;jsessionid=896CE4204292E70D28D27FE7C4503232?serverid=2342&action=do";

服务器仅应该过滤掉请求地址中以 phprpc_ 开头的请求参数。另外,该值的编码方式与 phprpc_errstr 的编码方式相同,即根据请求中 phprpc_encode 的值来决定进行 base64 编码还是 javascript 字符串格式编码。该响应仅在密钥交换的第一阶段返回。

客户端在收到该响应后,应使用该服务地址替换原来的服务地址。之后所有的调用(包括密钥交换第二阶段)都使用新的地址,从而实现在无 cookie 的情况下,仍然可以使会话一直保持下去,保证密钥交换和加密传输顺利进行。

在 2.0 和 2.1 协议中,没有规定加密算法,但目前的实现所使用的加密算法都是 XXTEA 加密算法。为了保证所有的实现都能够兼容,因此,在 PHPRPC 3.0 中,规定加密应使用 XXTEA 加密算法。

XXTEA 加密算法的密钥长度为 128 位,如果密钥交换采用的是 128 位(默认)密钥,则交换后的密钥直接用于 XXTEA 加密算法。其它长度的密钥需要用 MD5 算法生成 128 位密钥(在对非 128 位密钥进行 MD5 时,是对其 10 进制表示的数字字符串进行 MD5,而非其它形式),然后再用于 XXTEA 加密算法中。

为了避免同一个页面上的多个 JavaScript 客户端在与同一个服务器进行密钥交换时产生冲突,故在请求中增加了一个参数: phprpc_id,该参数的值由客户端生成,用于唯一标示该客户端。服务器端根据该值来区别同一会话中的多个客户端。该参数仅用于 JavaScript 客户端。

服务器端如果对字符集进行解释(例如 Java、.NET 等双字节字符编码的语言实现的服务器),不论对客户端提交的请求,还是对输出的响应,都按照服务器端设置的字符集进行解释。客户端的请求中可以包含字符集设置,但是应该与服务器端设置相同,在与服务器端设置不同的情况下,按照服务器端设置的字符集进行处理。建议统一使用 UTF-8 字符集,在此种情况下,可以保证所有服务器与客户端正常通讯,如设置其它字符集,只能保证两个相同字符集设置的服务器和客户端可以正常通讯。

原创作品,转载请注明出处。

» 阅读全文

做 Java 程序,在封装一些程序库的时候,通常都是打包成 jar 文件的。如果跟随 class 文件一起打包的除了 class 文件还有其它资源文件的话,我们该如何在我们一起打包的程序中读取它们呢?这里给出一种方法:

final public class ResourceLoader {
    
public static byte[] getResource(String path) {
        
JarFile jarFile = new JarFile(URLDecoder.decode(ResourceLoader.class.getProtectionDomain().getCodeSource().getLocation().getFile()));
        
JarEntry entry = jarFile.getJarEntry(path);
        
byte[] data = new byte[(int)entry.getSize()];
        
BufferedInputStream in = new BufferedInputStream(jarFile.getInputStream(entry));
        
in.read(data);
        
in.close();
        
return data;
    
}
}

这样直接用 ResourceLoader.getResource(”data/data.dat”) 就可以读取 jar 文件中 data 目录下的 data.dat 文件了。这里静态方法 getResource 的 path 参数是相对于 Jar 文件来说的相对路径。

» 阅读全文

Beta 3 Update:

修正了当响应内容较多时,无法全部读取的 bug。

Beta 2 Update:

增加了对 Keep-Alive 的支持,在同一会话中进行多次服务调用时更加高效。
重新编写的纯 PHP 实现的大整数运算库,比原来的版本更加高效。
由于 gmp 在处理大整数运算时速度最快,对密钥交换时所使用的大整数运算的扩展设置为 gmp 优先,其次是 big_int、bcmath 扩展,最后是纯 PHP 实现的大整数运算库。

Beta 1 Update:

实现了 PHPRPC 3.0 协议升级描述中的内容。
实现了 PHPRPC 3.0 for PHP Client API Draft 中的所有接口。
支持 PHP 4.2+ 和 PHP 5+。
增加对没有 bcmath、gmp 和 big_int 扩展的支持。
增加了对 PHP 5 的异常处理的支持。
增加了反序列化未定义类的对象的特殊处理。
与 PHPRPC 2.1、2.0、1.1 的服务器相兼容。

Download: phprpc_3.0_php_client_beta_3.zip

该版本已过期。

» 阅读全文

3月
14

Nusoap vs PHPRPC for PHP

因为看到有人问 Nusoap 和 PHPRPC 的比较,为了让大家能够更清楚地了解 Nusoap 和 PHPRPC 的关系,所以在这里做一个简要的说明性介绍,所写的内容也不是面面俱到的,只写了一些主要的比较。更多细节的比较大家可以在使用中自己来对比。

Nusoap 是一个用于 PHP 的 Web Service 实现。PHP 版本的 PHPRPC 协议实现跟 Nusoap 是一个级别的东西。但是 PHPRPC 协议是跟 Web Service 一个级别的东西,所以下面我们来把 Nusoap 实现跟 PHP 版本的 PHPRPC 协议实现进行比较,把 Web Service 和 PHPRPC 协议进行比较。

1、协议比较:

相同之处:

这两个协议都是基于 HTTP 协议的,都可以使用 POST 方法提交请求。

主要不同之处:

(1) 请求:WebService 虽然也支持 GET 方式提交请求,但是一般不常用,常用的方式是利用 POST 方法提交 SOAP 格式的请求。而 PHPRPC 支持 GET 和 POST 两种方式来提交请求,请求格式是最常见的 application/x-www-form-urlencoded 格式,这对于实现一个浏览器客户端来说更加容易。

(2) 响应:WebService 返回的响应是 SOAP 格式的数据,对于浏览器客户端来说,只有利用 XMLHttpRequest 才能够对其进行处理,因为 XMLHttpRequest 收到跨域调用的限制,因此 WebService 的浏览器客户端无法做到跨域调用服务。PHPRPC 的响应格式是兼容于 JavaScript 格式的纯文本,因此返回的响应可以直接作为脚本执行,因此实现浏览器客户端可以完全不依赖于 XMLHttpRequest,利用纯 JavaScript 即可实现一个浏览器客户端,而浏览器允许跨域下载并执行脚本,因此 PHPRPC 的浏览器客户端可以做到跨域调用。

(3) 数据交换格式:WebService 中所使用的 SOAP 格式是基于 XML 语言定义的,XML 语言是纯文本的,因为其中的某些位置可以增加或删除一些空白(空格、制表符、回车或换行)而不影响其所表示的内容,因此其格式可以整理成便于人来阅读的,但也由于这点的灵活性,对于机器处理来说效率偏低。而 PHPRPC 的数据交换格式是 PHP 序列化格式,PHP 序列化格式可以算是半纯文本的,因为其数据的表示格式也是采用人类可读的方式表示的,但其中任何位置都不可以插入多于的空白,它对机器的可读性作了很好的支持,不但提供了有效的分隔符,并且提供了字符串长度、数组元素个数、对象成员个数等信息,所以更有利于机器高速处理。因为协议本质上是机机语言,而不是计算机程序设计语言,计算机程序设计语言是人机语言,它应该更偏重于人类可读性,而机机语言应该更重视机器可读性。因此可以说 PHP 序列化格式在人类可读性和机器可读性之间做到了非常好的平衡。

(4) 带宽占用:WebService 是重量级的 Web 服务,其数据格式冗长拖沓,占用网络带宽高。PHPRPC 是轻量级的 Web 服务,其数据格式简单紧凑,占用网络带宽低。注意,这里所说到重量级和轻量级是指网络带宽占用,而不是指其提供服务的能力,PHPRPC 所提供的服务能力绝不逊色于 WebService,甚至在很多地方优于 WebService。打个比方说:WebService 就像是 OSI 的 7 层网络模型,看似完美,但实现复杂,使用困难。而 PHPRPC 则像是简化了的 TCP/IP 的 5 层网络模型,实现高效,使用方便。

2、然后我们再来比较 Nusoap 和 PHP 版本的 PHPRPC 协议实现:

相同之处是都用于 PHP。

不同之处主要在于易用性上,Nusoap 虽然在易用性上做的还算不错,但是跟 PHP 版本的 PHPRPC 协议实现来比较就差太远了。例如,利用 Nusoap 发布的服务函数需要单独编写,而不能使用跟本地函数同样的方式进行编写,更无法使用 PHP 中内置扩展的函数,而 PHPRPC 所发布的函数跟本地函数完全一样,甚至包括 PHP 内置扩展的函数也可以直接发布。要用 Nusoap 发布一个 wsdl,需要为每一个发布的过程的名称、参数名、参数类型、返回值类型、名空间、动作、样式、文档等内容进行定义。而要发布一个 PHPRPC 服务,只需要告诉服务器要发布的那个函数(也可以是对象方法或类方法)的名字(还可以给出别名)即可。而不需要给出参数名、参数类型、返回值类型等信息。因此对于变长参数,可变类型参数的支持更好。在 PHPRPC 客户端的使用上,也是同样的方便,可以直接以远程函数名命名的本地 PHPRPC 客户端的方法来调用远程函数,而 Nusoap 相对来说比较麻烦一些。PHPRPC 还有一个很大的优势在于,它可以让你很轻松的以安全加密传输的方式来进行远程调用,这一点 Nusoap 是做不到的。

» 阅读全文

Beta 3 Update:

修改了对 Session 的处理方法,在同一会话中可以支持多个客户端进行安全加密传输。
重新编写的纯 PHP 实现的大整数运算库,比原来的版本更加高效。
由于 gmp 在处理大整数运算时速度最快,对密钥交换时所使用的大整数运算的扩展设置为 gmp 优先,其次是 big_int、bcmath 扩展,最后是纯 PHP 实现的大整数运算库。

Beta 2 Update:

更加完善了对客户端发起的 Session 处理。
增加了对 Fatal 和 Compile 错误重定向到客户端的支持。
修正了原来对 PHP 反序列化未定义类时的错误处理。

Beta 1 Update:

实现了 PHPRPC 3.0 协议升级描述中的内容。
实现了 PHPRPC 3.0 for PHP Server API Draft 中的所有接口。
增加了对禁用 Cookie 的客户端的支持(3.0 客户端支持该功能)。
支持 PHP 4.2+ 和 PHP 5+。
增加对没有 bcmath、gmp 和 big_int 扩展的支持。
增加了对 PHP 5 的异常处理的支持。
增加了当客户端传递一个服务器端未定义的类的对象时,服务器端自动定义该类的支持。
与 PHPRPC 2.1、2.0、1.1 的客户端相兼容。

Download: phprpc_3.0_php_server_beta_3.zip

该版本已过期。

» 阅读全文