/XmlRpc/Client.php

https://github.com/zf/ZendFramework-Library · PHP · 403 lines · 175 code · 53 blank · 175 comment · 24 complexity · 00a6cb640e71ba3f769c052ea637f533 MD5 · raw file

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