|
1 <?php |
|
2 /** |
|
3 * Zend Framework |
|
4 * |
|
5 * LICENSE |
|
6 * |
|
7 * This source file is subject to the new BSD license that is bundled |
|
8 * with this package in the file LICENSE.txt. |
|
9 * It is also available through the world-wide-web at this URL: |
|
10 * http://framework.zend.com/license/new-bsd |
|
11 * If you did not receive a copy of the license and are unable to |
|
12 * obtain it through the world-wide-web, please send an email |
|
13 * to license@zend.com so we can send you a copy immediately. |
|
14 * |
|
15 * @category Zend |
|
16 * @package Zend_XmlRpc |
|
17 * @subpackage Client |
|
18 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
19 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
20 * @version $Id: Client.php 20096 2010-01-06 02:05:09Z bkarwin $ |
|
21 */ |
|
22 |
|
23 |
|
24 /** |
|
25 * For handling the HTTP connection to the XML-RPC service |
|
26 * @see Zend_Http_Client |
|
27 */ |
|
28 require_once 'Zend/Http/Client.php'; |
|
29 |
|
30 /** |
|
31 * Enables object chaining for calling namespaced XML-RPC methods. |
|
32 * @see Zend_XmlRpc_Client_ServerProxy |
|
33 */ |
|
34 require_once 'Zend/XmlRpc/Client/ServerProxy.php'; |
|
35 |
|
36 /** |
|
37 * Introspects remote servers using the XML-RPC de facto system.* methods |
|
38 * @see Zend_XmlRpc_Client_ServerIntrospection |
|
39 */ |
|
40 require_once 'Zend/XmlRpc/Client/ServerIntrospection.php'; |
|
41 |
|
42 /** |
|
43 * Represent a native XML-RPC value, used both in sending parameters |
|
44 * to methods and as the parameters retrieve from method calls |
|
45 * @see Zend_XmlRpc_Value |
|
46 */ |
|
47 require_once 'Zend/XmlRpc/Value.php'; |
|
48 |
|
49 /** |
|
50 * XML-RPC Request |
|
51 * @see Zend_XmlRpc_Request |
|
52 */ |
|
53 require_once 'Zend/XmlRpc/Request.php'; |
|
54 |
|
55 /** |
|
56 * XML-RPC Response |
|
57 * @see Zend_XmlRpc_Response |
|
58 */ |
|
59 require_once 'Zend/XmlRpc/Response.php'; |
|
60 |
|
61 /** |
|
62 * XML-RPC Fault |
|
63 * @see Zend_XmlRpc_Fault |
|
64 */ |
|
65 require_once 'Zend/XmlRpc/Fault.php'; |
|
66 |
|
67 |
|
68 /** |
|
69 * An XML-RPC client implementation |
|
70 * |
|
71 * @category Zend |
|
72 * @package Zend_XmlRpc |
|
73 * @subpackage Client |
|
74 * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) |
|
75 * @license http://framework.zend.com/license/new-bsd New BSD License |
|
76 */ |
|
77 class Zend_XmlRpc_Client |
|
78 { |
|
79 /** |
|
80 * Full address of the XML-RPC service |
|
81 * @var string |
|
82 * @example http://time.xmlrpc.com/RPC2 |
|
83 */ |
|
84 protected $_serverAddress; |
|
85 |
|
86 /** |
|
87 * HTTP Client to use for requests |
|
88 * @var Zend_Http_Client |
|
89 */ |
|
90 protected $_httpClient = null; |
|
91 |
|
92 /** |
|
93 * Introspection object |
|
94 * @var Zend_Http_Client_Introspector |
|
95 */ |
|
96 protected $_introspector = null; |
|
97 |
|
98 /** |
|
99 * Request of the last method call |
|
100 * @var Zend_XmlRpc_Request |
|
101 */ |
|
102 protected $_lastRequest = null; |
|
103 |
|
104 /** |
|
105 * Response received from the last method call |
|
106 * @var Zend_XmlRpc_Response |
|
107 */ |
|
108 protected $_lastResponse = null; |
|
109 |
|
110 /** |
|
111 * Proxy object for more convenient method calls |
|
112 * @var array of Zend_XmlRpc_Client_ServerProxy |
|
113 */ |
|
114 protected $_proxyCache = array(); |
|
115 |
|
116 /** |
|
117 * Flag for skipping system lookup |
|
118 * @var bool |
|
119 */ |
|
120 protected $_skipSystemLookup = false; |
|
121 |
|
122 /** |
|
123 * Create a new XML-RPC client to a remote server |
|
124 * |
|
125 * @param string $server Full address of the XML-RPC service |
|
126 * (e.g. http://time.xmlrpc.com/RPC2) |
|
127 * @param Zend_Http_Client $httpClient HTTP Client to use for requests |
|
128 * @return void |
|
129 */ |
|
130 public function __construct($server, Zend_Http_Client $httpClient = null) |
|
131 { |
|
132 if ($httpClient === null) { |
|
133 $this->_httpClient = new Zend_Http_Client(); |
|
134 } else { |
|
135 $this->_httpClient = $httpClient; |
|
136 } |
|
137 |
|
138 $this->_introspector = new Zend_XmlRpc_Client_ServerIntrospection($this); |
|
139 $this->_serverAddress = $server; |
|
140 } |
|
141 |
|
142 |
|
143 /** |
|
144 * Sets the HTTP client object to use for connecting the XML-RPC server. |
|
145 * |
|
146 * @param Zend_Http_Client $httpClient |
|
147 * @return Zend_Http_Client |
|
148 */ |
|
149 public function setHttpClient(Zend_Http_Client $httpClient) |
|
150 { |
|
151 return $this->_httpClient = $httpClient; |
|
152 } |
|
153 |
|
154 |
|
155 /** |
|
156 * Gets the HTTP client object. |
|
157 * |
|
158 * @return Zend_Http_Client |
|
159 */ |
|
160 public function getHttpClient() |
|
161 { |
|
162 return $this->_httpClient; |
|
163 } |
|
164 |
|
165 |
|
166 /** |
|
167 * Sets the object used to introspect remote servers |
|
168 * |
|
169 * @param Zend_XmlRpc_Client_ServerIntrospection |
|
170 * @return Zend_XmlRpc_Client_ServerIntrospection |
|
171 */ |
|
172 public function setIntrospector(Zend_XmlRpc_Client_ServerIntrospection $introspector) |
|
173 { |
|
174 return $this->_introspector = $introspector; |
|
175 } |
|
176 |
|
177 |
|
178 /** |
|
179 * Gets the introspection object. |
|
180 * |
|
181 * @return Zend_XmlRpc_Client_ServerIntrospection |
|
182 */ |
|
183 public function getIntrospector() |
|
184 { |
|
185 return $this->_introspector; |
|
186 } |
|
187 |
|
188 |
|
189 /** |
|
190 * The request of the last method call |
|
191 * |
|
192 * @return Zend_XmlRpc_Request |
|
193 */ |
|
194 public function getLastRequest() |
|
195 { |
|
196 return $this->_lastRequest; |
|
197 } |
|
198 |
|
199 |
|
200 /** |
|
201 * The response received from the last method call |
|
202 * |
|
203 * @return Zend_XmlRpc_Response |
|
204 */ |
|
205 public function getLastResponse() |
|
206 { |
|
207 return $this->_lastResponse; |
|
208 } |
|
209 |
|
210 |
|
211 /** |
|
212 * Returns a proxy object for more convenient method calls |
|
213 * |
|
214 * @param $namespace Namespace to proxy or empty string for none |
|
215 * @return Zend_XmlRpc_Client_ServerProxy |
|
216 */ |
|
217 public function getProxy($namespace = '') |
|
218 { |
|
219 if (empty($this->_proxyCache[$namespace])) { |
|
220 $proxy = new Zend_XmlRpc_Client_ServerProxy($this, $namespace); |
|
221 $this->_proxyCache[$namespace] = $proxy; |
|
222 } |
|
223 return $this->_proxyCache[$namespace]; |
|
224 } |
|
225 |
|
226 /** |
|
227 * Set skip system lookup flag |
|
228 * |
|
229 * @param bool $flag |
|
230 * @return Zend_XmlRpc_Client |
|
231 */ |
|
232 public function setSkipSystemLookup($flag = true) |
|
233 { |
|
234 $this->_skipSystemLookup = (bool) $flag; |
|
235 return $this; |
|
236 } |
|
237 |
|
238 /** |
|
239 * Skip system lookup when determining if parameter should be array or struct? |
|
240 * |
|
241 * @return bool |
|
242 */ |
|
243 public function skipSystemLookup() |
|
244 { |
|
245 return $this->_skipSystemLookup; |
|
246 } |
|
247 |
|
248 /** |
|
249 * Perform an XML-RPC request and return a response. |
|
250 * |
|
251 * @param Zend_XmlRpc_Request $request |
|
252 * @param null|Zend_XmlRpc_Response $response |
|
253 * @return void |
|
254 * @throws Zend_XmlRpc_Client_HttpException |
|
255 */ |
|
256 public function doRequest($request, $response = null) |
|
257 { |
|
258 $this->_lastRequest = $request; |
|
259 |
|
260 iconv_set_encoding('input_encoding', 'UTF-8'); |
|
261 iconv_set_encoding('output_encoding', 'UTF-8'); |
|
262 iconv_set_encoding('internal_encoding', 'UTF-8'); |
|
263 |
|
264 $http = $this->getHttpClient(); |
|
265 if($http->getUri() === null) { |
|
266 $http->setUri($this->_serverAddress); |
|
267 } |
|
268 |
|
269 $http->setHeaders(array( |
|
270 'Content-Type: text/xml; charset=utf-8', |
|
271 'Accept: text/xml', |
|
272 )); |
|
273 |
|
274 if ($http->getHeader('user-agent') === null) { |
|
275 $http->setHeaders(array('User-Agent: Zend_XmlRpc_Client')); |
|
276 } |
|
277 |
|
278 $xml = $this->_lastRequest->__toString(); |
|
279 $http->setRawData($xml); |
|
280 $httpResponse = $http->request(Zend_Http_Client::POST); |
|
281 |
|
282 if (! $httpResponse->isSuccessful()) { |
|
283 /** |
|
284 * Exception thrown when an HTTP error occurs |
|
285 * @see Zend_XmlRpc_Client_HttpException |
|
286 */ |
|
287 require_once 'Zend/XmlRpc/Client/HttpException.php'; |
|
288 throw new Zend_XmlRpc_Client_HttpException( |
|
289 $httpResponse->getMessage(), |
|
290 $httpResponse->getStatus()); |
|
291 } |
|
292 |
|
293 if ($response === null) { |
|
294 $response = new Zend_XmlRpc_Response(); |
|
295 } |
|
296 $this->_lastResponse = $response; |
|
297 $this->_lastResponse->loadXml($httpResponse->getBody()); |
|
298 } |
|
299 |
|
300 /** |
|
301 * Send an XML-RPC request to the service (for a specific method) |
|
302 * |
|
303 * @param string $method Name of the method we want to call |
|
304 * @param array $params Array of parameters for the method |
|
305 * @return mixed |
|
306 * @throws Zend_XmlRpc_Client_FaultException |
|
307 */ |
|
308 public function call($method, $params=array()) |
|
309 { |
|
310 if (!$this->skipSystemLookup() && ('system.' != substr($method, 0, 7))) { |
|
311 // Ensure empty array/struct params are cast correctly |
|
312 // If system.* methods are not available, bypass. (ZF-2978) |
|
313 $success = true; |
|
314 try { |
|
315 $signatures = $this->getIntrospector()->getMethodSignature($method); |
|
316 } catch (Zend_XmlRpc_Exception $e) { |
|
317 $success = false; |
|
318 } |
|
319 if ($success) { |
|
320 $validTypes = array( |
|
321 Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY, |
|
322 Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64, |
|
323 Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN, |
|
324 Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME, |
|
325 Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE, |
|
326 Zend_XmlRpc_Value::XMLRPC_TYPE_I4, |
|
327 Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER, |
|
328 Zend_XmlRpc_Value::XMLRPC_TYPE_NIL, |
|
329 Zend_XmlRpc_Value::XMLRPC_TYPE_STRING, |
|
330 Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT, |
|
331 ); |
|
332 |
|
333 if (!is_array($params)) { |
|
334 $params = array($params); |
|
335 } |
|
336 foreach ($params as $key => $param) { |
|
337 |
|
338 if ($param instanceof Zend_XmlRpc_Value) { |
|
339 continue; |
|
340 } |
|
341 |
|
342 $type = Zend_XmlRpc_Value::AUTO_DETECT_TYPE; |
|
343 foreach ($signatures as $signature) { |
|
344 if (!is_array($signature)) { |
|
345 continue; |
|
346 } |
|
347 |
|
348 if (isset($signature['parameters'][$key])) { |
|
349 $type = $signature['parameters'][$key]; |
|
350 $type = in_array($type, $validTypes) ? $type : Zend_XmlRpc_Value::AUTO_DETECT_TYPE; |
|
351 } |
|
352 } |
|
353 |
|
354 $params[$key] = Zend_XmlRpc_Value::getXmlRpcValue($param, $type); |
|
355 } |
|
356 } |
|
357 } |
|
358 |
|
359 $request = $this->_createRequest($method, $params); |
|
360 |
|
361 $this->doRequest($request); |
|
362 |
|
363 if ($this->_lastResponse->isFault()) { |
|
364 $fault = $this->_lastResponse->getFault(); |
|
365 /** |
|
366 * Exception thrown when an XML-RPC fault is returned |
|
367 * @see Zend_XmlRpc_Client_FaultException |
|
368 */ |
|
369 require_once 'Zend/XmlRpc/Client/FaultException.php'; |
|
370 throw new Zend_XmlRpc_Client_FaultException($fault->getMessage(), |
|
371 $fault->getCode()); |
|
372 } |
|
373 |
|
374 return $this->_lastResponse->getReturnValue(); |
|
375 } |
|
376 |
|
377 /** |
|
378 * Create request object |
|
379 * |
|
380 * @return Zend_XmlRpc_Request |
|
381 */ |
|
382 protected function _createRequest($method, $params) |
|
383 { |
|
384 return new Zend_XmlRpc_Request($method, $params); |
|
385 } |
|
386 } |