File indexing completed on 2024-12-22 05:37:14

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_XmlRpc
0017  * @subpackage Client
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * For handling the HTTP connection to the XML-RPC service
0026  * @see Zend_Http_Client
0027  */
0028 // require_once 'Zend/Http/Client.php';
0029 
0030 /**
0031  * Enables object chaining for calling namespaced XML-RPC methods.
0032  * @see Zend_XmlRpc_Client_ServerProxy
0033  */
0034 // require_once 'Zend/XmlRpc/Client/ServerProxy.php';
0035 
0036 /**
0037  * Introspects remote servers using the XML-RPC de facto system.* methods
0038  * @see Zend_XmlRpc_Client_ServerIntrospection
0039  */
0040 // require_once 'Zend/XmlRpc/Client/ServerIntrospection.php';
0041 
0042 /**
0043  * Represent a native XML-RPC value, used both in sending parameters
0044  * to methods and as the parameters retrieve from method calls
0045  * @see Zend_XmlRpc_Value
0046  */
0047 // require_once 'Zend/XmlRpc/Value.php';
0048 
0049 /**
0050  * XML-RPC Request
0051  * @see Zend_XmlRpc_Request
0052  */
0053 // require_once 'Zend/XmlRpc/Request.php';
0054 
0055 /**
0056  * XML-RPC Response
0057  * @see Zend_XmlRpc_Response
0058  */
0059 // require_once 'Zend/XmlRpc/Response.php';
0060 
0061 /**
0062  * XML-RPC Fault
0063  * @see Zend_XmlRpc_Fault
0064  */
0065 // require_once 'Zend/XmlRpc/Fault.php';
0066 
0067 
0068 /**
0069  * An XML-RPC client implementation
0070  *
0071  * @category   Zend
0072  * @package    Zend_XmlRpc
0073  * @subpackage Client
0074  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0075  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0076  */
0077 class Zend_XmlRpc_Client
0078 {
0079     /**
0080      * Full address of the XML-RPC service
0081      * @var string
0082      * @example http://time.xmlrpc.com/RPC2
0083      */
0084     protected $_serverAddress;
0085 
0086     /**
0087      * HTTP Client to use for requests
0088      * @var Zend_Http_Client
0089      */
0090     protected $_httpClient = null;
0091 
0092     /**
0093      * Introspection object
0094      * @var Zend_Http_Client_Introspector
0095      */
0096     protected $_introspector = null;
0097 
0098     /**
0099      * Request of the last method call
0100      * @var Zend_XmlRpc_Request
0101      */
0102     protected $_lastRequest = null;
0103 
0104     /**
0105      * Response received from the last method call
0106      * @var Zend_XmlRpc_Response
0107      */
0108     protected $_lastResponse = null;
0109 
0110     /**
0111      * Proxy object for more convenient method calls
0112      * @var array of Zend_XmlRpc_Client_ServerProxy
0113      */
0114     protected $_proxyCache = array();
0115 
0116     /**
0117      * Flag for skipping system lookup
0118      * @var bool
0119      */
0120     protected $_skipSystemLookup = false;
0121 
0122     /**
0123      * Create a new XML-RPC client to a remote server
0124      *
0125      * @param  string $server      Full address of the XML-RPC service
0126      *                             (e.g. http://time.xmlrpc.com/RPC2)
0127      * @param  Zend_Http_Client $httpClient HTTP Client to use for requests
0128      * @return void
0129      */
0130     public function __construct($server, Zend_Http_Client $httpClient = null)
0131     {
0132         if ($httpClient === null) {
0133             $this->_httpClient = new Zend_Http_Client();
0134         } else {
0135             $this->_httpClient = $httpClient;
0136         }
0137 
0138         $this->_introspector  = new Zend_XmlRpc_Client_ServerIntrospection($this);
0139         $this->_serverAddress = $server;
0140     }
0141 
0142 
0143     /**
0144      * Sets the HTTP client object to use for connecting the XML-RPC server.
0145      *
0146      * @param  Zend_Http_Client $httpClient
0147      * @return Zend_Http_Client
0148      */
0149     public function setHttpClient(Zend_Http_Client $httpClient)
0150     {
0151         return $this->_httpClient = $httpClient;
0152     }
0153 
0154 
0155     /**
0156      * Gets the HTTP client object.
0157      *
0158      * @return Zend_Http_Client
0159      */
0160     public function getHttpClient()
0161     {
0162         return $this->_httpClient;
0163     }
0164 
0165 
0166     /**
0167      * Sets the object used to introspect remote servers
0168      *
0169      * @param  Zend_XmlRpc_Client_ServerIntrospection
0170      * @return Zend_XmlRpc_Client_ServerIntrospection
0171      */
0172     public function setIntrospector(Zend_XmlRpc_Client_ServerIntrospection $introspector)
0173     {
0174         return $this->_introspector = $introspector;
0175     }
0176 
0177 
0178     /**
0179      * Gets the introspection object.
0180      *
0181      * @return Zend_XmlRpc_Client_ServerIntrospection
0182      */
0183     public function getIntrospector()
0184     {
0185         return $this->_introspector;
0186     }
0187 
0188 
0189    /**
0190      * The request of the last method call
0191      *
0192      * @return Zend_XmlRpc_Request
0193      */
0194     public function getLastRequest()
0195     {
0196         return $this->_lastRequest;
0197     }
0198 
0199 
0200     /**
0201      * The response received from the last method call
0202      *
0203      * @return Zend_XmlRpc_Response
0204      */
0205     public function getLastResponse()
0206     {
0207         return $this->_lastResponse;
0208     }
0209 
0210 
0211     /**
0212      * Returns a proxy object for more convenient method calls
0213      *
0214      * @param string $namespace  Namespace to proxy or empty string for none
0215      * @return Zend_XmlRpc_Client_ServerProxy
0216      */
0217     public function getProxy($namespace = '')
0218     {
0219         if (empty($this->_proxyCache[$namespace])) {
0220             $proxy = new Zend_XmlRpc_Client_ServerProxy($this, $namespace);
0221             $this->_proxyCache[$namespace] = $proxy;
0222         }
0223         return $this->_proxyCache[$namespace];
0224     }
0225 
0226     /**
0227      * Set skip system lookup flag
0228      *
0229      * @param  bool $flag
0230      * @return Zend_XmlRpc_Client
0231      */
0232     public function setSkipSystemLookup($flag = true)
0233     {
0234         $this->_skipSystemLookup = (bool) $flag;
0235         return $this;
0236     }
0237 
0238     /**
0239      * Skip system lookup when determining if parameter should be array or struct?
0240      *
0241      * @return bool
0242      */
0243     public function skipSystemLookup()
0244     {
0245         return $this->_skipSystemLookup;
0246     }
0247 
0248     /**
0249      * Perform an XML-RPC request and return a response.
0250      *
0251      * @param Zend_XmlRpc_Request $request
0252      * @param null|Zend_XmlRpc_Response $response
0253      * @return void
0254      * @throws Zend_XmlRpc_Client_HttpException
0255      */
0256     public function doRequest($request, $response = null)
0257     {
0258         $this->_lastRequest = $request;
0259 
0260         if (PHP_VERSION_ID < 50600) {
0261             iconv_set_encoding('input_encoding', 'UTF-8');
0262             iconv_set_encoding('output_encoding', 'UTF-8');
0263             iconv_set_encoding('internal_encoding', 'UTF-8');
0264         } else {
0265             ini_set('input_encoding', 'UTF-8');
0266             ini_set('output_encoding', 'UTF-8');
0267             ini_set('default_charset', 'UTF-8');
0268         }
0269 
0270         $http = $this->getHttpClient();
0271         if($http->getUri() === null) {
0272             $http->setUri($this->_serverAddress);
0273         }
0274 
0275         $http->setHeaders(array(
0276             'Content-Type: text/xml; charset=utf-8',
0277             'Accept: text/xml',
0278         ));
0279 
0280         if ($http->getHeader('user-agent') === null) {
0281             $http->setHeaders(array('User-Agent: Zend_XmlRpc_Client'));
0282         }
0283 
0284         $xml = $this->_lastRequest->__toString();
0285         $http->setRawData($xml);
0286         $httpResponse = $http->request(Zend_Http_Client::POST);
0287 
0288         if (! $httpResponse->isSuccessful()) {
0289             /**
0290              * Exception thrown when an HTTP error occurs
0291              * @see Zend_XmlRpc_Client_HttpException
0292              */
0293             // require_once 'Zend/XmlRpc/Client/HttpException.php';
0294             throw new Zend_XmlRpc_Client_HttpException(
0295                                     $httpResponse->getMessage(),
0296                                     $httpResponse->getStatus());
0297         }
0298 
0299         if ($response === null) {
0300             $response = new Zend_XmlRpc_Response();
0301         }
0302         $this->_lastResponse = $response;
0303         $this->_lastResponse->loadXml(trim($httpResponse->getBody()));
0304     }
0305 
0306     /**
0307      * Send an XML-RPC request to the service (for a specific method)
0308      *
0309      * @param  string $method Name of the method we want to call
0310      * @param  array $params Array of parameters for the method
0311      * @return mixed
0312      * @throws Zend_XmlRpc_Client_FaultException
0313      */
0314     public function call($method, $params=array())
0315     {
0316         if (!$this->skipSystemLookup() && ('system.' != substr($method, 0, 7))) {
0317             // Ensure empty array/struct params are cast correctly
0318             // If system.* methods are not available, bypass. (ZF-2978)
0319             $success = true;
0320             try {
0321                 $signatures = $this->getIntrospector()->getMethodSignature($method);
0322             } catch (Zend_XmlRpc_Exception $e) {
0323                 $success = false;
0324             }
0325             if ($success) {
0326                 $validTypes = array(
0327                     Zend_XmlRpc_Value::XMLRPC_TYPE_ARRAY,
0328                     Zend_XmlRpc_Value::XMLRPC_TYPE_BASE64,
0329                     Zend_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN,
0330                     Zend_XmlRpc_Value::XMLRPC_TYPE_DATETIME,
0331                     Zend_XmlRpc_Value::XMLRPC_TYPE_DOUBLE,
0332                     Zend_XmlRpc_Value::XMLRPC_TYPE_I4,
0333                     Zend_XmlRpc_Value::XMLRPC_TYPE_INTEGER,
0334                     Zend_XmlRpc_Value::XMLRPC_TYPE_NIL,
0335                     Zend_XmlRpc_Value::XMLRPC_TYPE_STRING,
0336                     Zend_XmlRpc_Value::XMLRPC_TYPE_STRUCT,
0337                 );
0338 
0339                 if (!is_array($params)) {
0340                     $params = array($params);
0341                 }
0342 
0343                 foreach ($params as $key => $param)
0344                 {
0345                     if ($param instanceof Zend_XmlRpc_Value) {
0346                         continue;
0347                     }
0348 
0349                     if (count($signatures) > 1) {
0350                         $type = Zend_XmlRpc_Value::getXmlRpcTypeByValue($param);
0351                         foreach ($signatures as $signature) {
0352                             if (!is_array($signature)) {
0353                                 continue;
0354                             }
0355                             if (isset($signature['parameters'][$key])) {
0356                                 if ($signature['parameters'][$key] == $type) {
0357                                     break;
0358                                 }
0359                             }
0360                         }
0361                     } elseif (isset($signatures[0]['parameters'][$key])) {
0362                         $type = $signatures[0]['parameters'][$key];
0363                     } else {
0364                         $type = null;
0365                     }
0366 
0367                     if (empty($type) || !in_array($type, $validTypes)) {
0368                         $type = Zend_XmlRpc_Value::AUTO_DETECT_TYPE;
0369                     }
0370 
0371                     $params[$key] = Zend_XmlRpc_Value::getXmlRpcValue($param, $type);
0372                 }
0373             }
0374         }
0375 
0376         $request = $this->_createRequest($method, $params);
0377 
0378         $this->doRequest($request);
0379 
0380         if ($this->_lastResponse->isFault()) {
0381             $fault = $this->_lastResponse->getFault();
0382             /**
0383              * Exception thrown when an XML-RPC fault is returned
0384              * @see Zend_XmlRpc_Client_FaultException
0385              */
0386             // require_once 'Zend/XmlRpc/Client/FaultException.php';
0387             throw new Zend_XmlRpc_Client_FaultException($fault->getMessage(),
0388                                                         $fault->getCode());
0389         }
0390 
0391         return $this->_lastResponse->getReturnValue();
0392     }
0393 
0394     /**
0395      * Create request object
0396      *
0397      * @return Zend_XmlRpc_Request
0398      */
0399     protected function _createRequest($method, $params)
0400     {
0401         return new Zend_XmlRpc_Request($method, $params);
0402     }
0403 }