17.2. Zend_XmlRpc_Client

17.2.1. 介绍

Zend_XmlRpc_Client的用法和SoapClient 对象 (SOAP web service extension)是非常相似的。 你只需在Zend_XmlRpc_Client构造函数中指定服务端的完整地址,即可以用Zend_XmlRpc_Client的方法简单的调用XML-RPC 服务端的过程。

例 17.1. 一个基本的XML-RPC请求

<?php
/**
 * 连接到framework.zend.com服务器并获得
 * 一个描述服务端可用方法的数组。
 */
require_once 'Zend/XmlRpc/Client.php';

$server = new Zend_XmlRpc_Client('http://framework.zend.com/xmlrpc');

print_r( $server->system->listMethods() );

?>
            

[注意] 注意
Zend_XmlRpc_Client尝试调用一个远程服务器的方法看起来就像调用本地方法那样简单。如果一个远程方法包含一个命名空间,就像前面的system.listMethods()那样,那么调用的时候可以用PHP的对象链的形式:$server->system->listMethods()

17.2.2. 带参数

一些XML-RPC服务过程要求一些参数,那么必要的参数将被作为Zend_XmlRpc_Client方法的参数进行传递。 XML-RPC过程的参数必须指定XML-RPC类型。 参数能通过两种方法进行传递:PHP本地变量或是指定XML-RPC类型的Zend_XmlRpc_Value对象。

17.2.2.1. 以PHP本地变量的形式传递参数

用本地PHP变量传递参数,意味着参数将是一个字符串、整数、浮点数、布尔值、数组或者是一个对象。 在这种情况下,PHP本地变量将被自动检测类型并根据下表转换成一个XML-RPC类型:

表 17.1. PHP本地变量类型转化为XML-RPC类型

PHP变量类型 XML-RPC类型
integer int
double double
boolean boolean
string string
array array
associative array(关联数组) struct
object array
...
/** 在这个过程中两个参数被传递
 *  第一个参数是一个字符串类型它将被自动转换成XML-RPC的字符串类型
 *  第二个参数是一个关联数组它将被转化成一个XML-RCP结构类型
 */

$p1 = 'parameter 1';
$p2 = array('name' => 'Joe', 'age' => 30);

$service->serviceProcedure($p1, $p2);
...
            

17.2.2.2.  以Zend_XmlRpc_Value 对象的形式传递参数

传递Zend_XmlRpc_Value对象作为参数。你可以创建一个Zend_XmlRpc_Value实例精确的说明你传递参数的XML-RPC类型。 精确说明XML-RPC类型的主要原因是:

  • 当你想确保你传递给远程过程的参数是正确的类型时(也就是说,当远程过程要求的是一个整形而你传递的参数是从$_GET数组获得的字符串类型)。
  • 当远程过程要求一个base64或dateTime.iso8601类型时(PHP本地变量则不存在这种类型)。
  • 当自动转换变量失败时(也就是说你想传递一个空的XML-RPC结构类型作为参数时。除了将一个空的PHP数组精确说明为一个空的XML-RPC结构之外,如果获得一个空的数组作为参数那么它将被自动转化为XML-RPC数组,而不是将其作为关联数组转化为一个XML-RPC结构。)

有两种方法用于创建Zend_XmlRpc_Value对象:直接调用对象的构造函数或者用对象的Zend_XmlRpc_Value::getXmlRpcValue()静态方法带上必要的XML-RPC类型常量。

表 17.2. Zend_XmlRpc_Value 对象声明的XML-RPC类型

XML-RPC 变量类型 相匹配的 Zend_XmlRpc_Value 常量 Zend_XmlRpc_Value 对象
int Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER Zend_XmlRpc_Value_Integer
double Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE Zend_XmlRpc_Value_Double
boolean Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN Zend_XmlRpc_Value_Boolean
string Zend_XmlRpc_Value::XMLRPC_TYPE_STRING Zend_XmlRpc_Value_String
base64 Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64 Zend_XmlRpc_Value_Base64
dateTime.iso8601 Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME Zend_XmlRpc_Value_DateTime
array Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY Zend_XmlRpc_Value_Array
struct Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT Zend_XmlRpc_Value_Struct
...
/** 传递两个参数给远程过程
 *  第一个参数是用静态的Zend_XmlRpc_Value::getXmlRpcValue()方法创建的XML-RPC base64类型
 *  第二个参数是用类型对象精确说明的XML-RPC结构
 */

$p1 = ZXmlRpcValue::getXmlRpcValue('encoded string', Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64);
$p2 = new Zend_XmlRpc_Value_Struct(array('name' => 'Joe', 'age' => 30));

$service->serviceProcedure($p1, $p2);
...
            

[注意] 注意
传递的参数值仍是PHP变量的值,只不过用PHP转换技术转换成指定的类型(也就是说一个字符串的值传给Zend_XmlRpc_Value_Integer对象时,将会被转换成整形以(int)$value的形式)。

17.2.2.3. 将一个XML字符串解析为XML-RPC参数

这种方法传递参数仅在Zend_XmlRpc内部使用,因此不推荐使用这种方法传递参数。

如果你坚持要使用该方法,那么你应该用Zend_XmlRpc_Value::getXmlRpcValue()静态方法将一个XML字符串解析为一个 Zend_XmlRpc_Value对象指定的相应的XML-RPC类型。 Zend_XmlRpc_Value::getXmlRpcValue()方法需要两个参数:XML字符串和Zend_XmlRpc_Value::XML_STRING常量。

17.2.3. 参数类型提示

XML-RPC和SOAP web服务的最主要不同就是WSDL文件。SOAP协议通常用WSDL文件描述web服务接口。根据这个接口SOPA客户端懂得需要传递给服务端的参数类型并且知道返回的值是什么类型。 如果没有WSDL文件,那么用户可能在对变量类型的判断上会有些问题。

XML-RPC协议解决这个问题的办法是调用一个特殊的远程过程system.methodSignature。这个过程得到一个过程名作为参数并返回一个该过程的签名。这个签名中包含这个过程需要传递的参数类型和返回值的类型。

[注意] 注意
不是所有的XML-RPC服务器都支持这个特殊的system.methodSignature过程,不支持这个过程的服务器则无法支持参数类型提醒。

Zend_XmlRpc_Client实现了一个对XML-RPC服务器system.methodSignature过程返回的'WSDL'类型文件的排序。 如果发出请求的话,Zend_XmlRpc_Client将可以请求获得一份XML-RPC服务器的所有过程的列表,可以请求获得所有这些过程的签名,并将它们保存在XML文件中(就像SOAP的WSDL文件一样)。 当再次用到相同的XML-RPC服务器时,用户就能提供一个XML签名文件并且Zend_XmlRpc_Client将可以根据XML文件中过程的签名获得请求过程所有相关的变量类型提示。

过程的签名XML文件是通过调用Zend_XmlRpc_Client::__getMethodsXml()(这个方法返回一个包含所有签名数据的XML格式字符串)来生成的。 用户可以将XML数据作为Zend_XmlRpc_Client构造方法或者调用Zend_XmlRpc_Client::__setMethodsXml()方法时的参数来使用一个存在的签名XML文件。

例 17.2. 用类型提示来调用一个XML-RPC服务

<?php
/**
 * 连接一个XML-RPC服务器,并保存它的签名文件(相当于SOAP的WSDL文件)
 */
require_once 'Zend/XmlRpc/Client.php';

$service = new Zend_XmlRpc_Client('http://www.example.org/xmlrpc');

file_put_contents('/tmp/xmlrpc-signatures/example.xml', $service->__getMethodsXml());

/**
 * $service 对象包含了所有XML-RPC服务器的签名,当serviceProcedure被调用时,它的参数将根据过程签名被转换成需要的类型。
 */
$service->serviceProcedure($param);
?>
            
<?php
/**
 * 连接XML-RPC服务器,使用一个存在的签名文件确保
 * 我们传递的参数被转化为过程需要的类型。
 */
require_once 'Zend/XmlRpc/Client.php';

$signature_file_xml = file_get_contents('/tmp/xmlrpc-signatures/example.xml');
$service = new Zend_XmlRpc_Client('http://www.example.org/xmlrpc', 'namespace', $signature_file_xml);

/* $service 对象包含所有XML-RPC服务器的签名,
   当serviceProcedur被调用时,它的参数($param)将根据过程的签名被
   自动转化为过程需要的类型。
 */
$service->serviceProcedure($param);
?>
            

17.2.4. 获取响应

调用XML-RPC的过程将返回一个XML-RPC类型的值。 Zend_XmlRpc_Client方法调用XML-RPC过程返回一个从XML-RPC类型转化而来的PHP本地类型。

你可以用Zend_XmlRpc_Client::__getResponse()方法来获得被请求过程的返回值。 __getResponse()方法需要一个参数用于说明返回值的类型。 响应选项是:

  • Zend_XmlRpc_Client::RESPONSE_PHP_NATIVE - 以PHP本地类型的形式返回过程的返回值(将XML-RPC类型转化为PHP类型)。
  • Zend_XmlRpc_Client::RESPONSE_XML_STRING - 返回描述XML-RPC服务器端响应的XML字符串。
  • Zend_XmlRpc_Client::RESPONSE_ZXMLRPC_OBJECT - 返回一个用于描述返回的XML-RPC类型的Zend_XmlRpc_Value对象。

...
$service->serviceProcedure();

$response = $service->__getResponse();
// $response 是一个从XML-RPC类型返回值转化而来的PHP变量
  
$response = $service->__getResponse(ZXmlRpcClient::RESPONSE_XML_STRING);
// $response 是一个描述过程返回值的XML字符串

$response = $service->__getResponse(ZXmlRpcClient::RESPONSE_ZXMLRPC_OBJECT);
// $response 是一个描述XML-RPC类型返回值的Zend_XmlRpc_Value实例
...