/** * Handle an xmlrpc call (actual work) * * @param Polycast_XmlRpc_Request $request * @return Polycast_XmlRpc_Response * @throws Zend_XmlRpcServer_Exception|Exception * Zend_XmlRpcServer_Exceptions are thrown for internal errors; otherwise, * any other exception may be thrown by the callback */ protected function _handle(Polycast_XmlRpc_Request $request) { $method = $request->getMethod(); // Check for valid method if (!$this->_table->hasMethod($method)) { require_once 'Polycast/XmlRpc/Server/Exception.php'; throw new Polycast_XmlRpc_Server_Exception('Method "' . $method . '" does not exist', 620); } $info = $this->_table->getMethod($method); $params = $request->getParams(); $argv = $info->getInvokeArguments(); if (0 < count($argv) and $this->sendArgumentsToAllMethods()) { $params = array_merge($params, $argv); } // Check calling parameters against signatures $matched = false; $sigCalled = $request->getTypes(); $sigLength = count($sigCalled); $paramsLen = count($params); if ($sigLength < $paramsLen) { for ($i = $sigLength; $i < $paramsLen; ++$i) { $xmlRpcValue = Polycast_XmlRpc_Value::getXmlRpcValue($params[$i]); $sigCalled[] = $xmlRpcValue->getType(); } } $signatures = $info->getPrototypes(); foreach ($signatures as $signature) { $sigParams = $signature->getParameters(); if ($sigCalled === $sigParams) { $matched = true; break; } } if (!$matched) { require_once 'Polycast/XmlRpc/Server/Exception.php'; throw new Polycast_XmlRpc_Server_Exception('Calling parameters do not match signature', 623); } $return = $this->_dispatch($info, $params); $responseClass = $this->getResponseClass(); return new $responseClass($return); }
/** * Retrieve method parameters as XMLRPC values * * @return array */ protected function _getXmlRpcParams() { $params = array(); if (is_array($this->_xmlRpcParams)) { foreach ($this->_xmlRpcParams as $param) { $value = $param['value']; $type = isset($param['type']) ? $param['type'] : Polycast_XmlRpc_Value::AUTO_DETECT_TYPE; if (!$value instanceof Polycast_XmlRpc_Value) { $value = Polycast_XmlRpc_Value::getXmlRpcValue($value, $type); } $params[] = $value; } } return $params; }
/** * Send an XML-RPC request to the service (for a specific method) * * @param string $method Name of the method we want to call * @param array $params Array of parameters for the method * @return mixed * @throws Polycast_XmlRpc_Client_FaultException */ public function call($method, $params = array()) { if (!$this->skipSystemLookup() && 'system.' != substr($method, 0, 7)) { // Ensure empty array/struct params are cast correctly // If system.* methods are not available, bypass. (ZF-2978) $success = true; try { $signatures = $this->getIntrospector()->getMethodSignature($method); } catch (Polycast_XmlRpc_Exception $e) { $success = false; } if ($success) { $validTypes = array(Polycast_XmlRpc_Value::XMLRPC_TYPE_ARRAY, Polycast_XmlRpc_Value::XMLRPC_TYPE_BASE64, Polycast_XmlRpc_Value::XMLRPC_TYPE_BOOLEAN, Polycast_XmlRpc_Value::XMLRPC_TYPE_DATETIME, Polycast_XmlRpc_Value::XMLRPC_TYPE_DOUBLE, Polycast_XmlRpc_Value::XMLRPC_TYPE_I4, Polycast_XmlRpc_Value::XMLRPC_TYPE_INTEGER, Polycast_XmlRpc_Value::XMLRPC_TYPE_NIL, Polycast_XmlRpc_Value::XMLRPC_TYPE_STRING, Polycast_XmlRpc_Value::XMLRPC_TYPE_STRUCT); $params = (array) $params; foreach ($params as $key => $param) { $type = Polycast_XmlRpc_Value::AUTO_DETECT_TYPE; foreach ($signatures as $signature) { if (!is_array($signature)) { continue; } if (isset($signature['parameters'][$key])) { $type = $signature['parameters'][$key]; $type = in_array($type, $validTypes) ? $type : Polycast_XmlRpc_Value::AUTO_DETECT_TYPE; } } $params[$key] = Polycast_XmlRpc_Value::getXmlRpcValue($param, $type); } } } $request = $this->_createRequest($method, $params); $this->doRequest($request); if ($this->_lastResponse->isFault()) { $fault = $this->_lastResponse->getFault(); /** * Exception thrown when an XML-RPC fault is returned * @see Polycast_XmlRpc_Client_FaultException */ require_once 'Polycast/XmlRpc/Client/FaultException.php'; throw new Polycast_XmlRpc_Client_FaultException($fault->getMessage(), $fault->getCode()); } return $this->_lastResponse->getReturnValue(); }
/** * Load a response from an XML response * * Attempts to load a response from an XMLRPC response, autodetecting if it * is a fault response. * * @param string $response * @return boolean True if a valid XMLRPC response, false if a fault * response or invalid input */ public function loadXml($response) { if (!is_string($response)) { $this->_fault = new Polycast_XmlRpc_Fault(650); $this->_fault->setEncoding($this->getEncoding()); return false; } try { $xml = @new SimpleXMLElement($response); } catch (Exception $e) { // Not valid XML $this->_fault = new Polycast_XmlRpc_Fault(651); $this->_fault->setEncoding($this->getEncoding()); return false; } if (!empty($xml->fault)) { // fault response $this->_fault = new Polycast_XmlRpc_Fault(); $this->_fault->setEncoding($this->getEncoding()); $this->_fault->loadXml($response); return false; } if (empty($xml->params)) { // Invalid response $this->_fault = new Polycast_XmlRpc_Fault(652); $this->_fault->setEncoding($this->getEncoding()); return false; } try { if (!isset($xml->params) || !isset($xml->params->param) || !isset($xml->params->param->value)) { throw new Polycast_XmlRpc_Value_Exception('Missing XML-RPC value in XML'); } $valueXml = $xml->params->param->value->asXML(); $valueXml = preg_replace('/<\\?xml version=.*?\\?>/i', '', $valueXml); $value = Polycast_XmlRpc_Value::getXmlRpcValue(trim($valueXml), Polycast_XmlRpc_Value::XML_STRING); } catch (Polycast_XmlRpc_Value_Exception $e) { $this->_fault = new Polycast_XmlRpc_Fault(653); $this->_fault->setEncoding($this->getEncoding()); return false; } $this->setReturnValue($value->getValue()); return true; }
/** * Load an XMLRPC fault from XML * * @param string $fault * @return boolean Returns true if successfully loaded fault response, false * if response was not a fault response * @throws Polycast_XmlRpc_Exception if no or faulty XML provided, or if fault * response does not contain either code or message */ public function loadXml($fault) { if (!is_string($fault)) { require_once 'Polycast/XmlRpc/Exception.php'; throw new Polycast_XmlRpc_Exception('Invalid XML provided to fault'); } try { $xml = @new SimpleXMLElement($fault); } catch (Exception $e) { // Not valid XML require_once 'Polycast/XmlRpc/Exception.php'; throw new Polycast_XmlRpc_Exception('Failed to parse XML fault: ' . $e->getMessage(), 500); } // Check for fault if (!$xml->fault) { // Not a fault return false; } if (!$xml->fault->value->struct) { // not a proper fault require_once 'Polycast/XmlRpc/Exception.php'; throw new Polycast_XmlRpc_Exception('Invalid fault structure', 500); } $structXml = $xml->fault->value->asXML(); $structXml = preg_replace('/<\\?xml version=.*?\\?>/i', '', $structXml); $struct = Polycast_XmlRpc_Value::getXmlRpcValue(trim($structXml), Polycast_XmlRpc_Value::XML_STRING); $struct = $struct->getValue(); if (isset($struct['faultCode'])) { $code = $struct['faultCode']; } if (isset($struct['faultString'])) { $message = $struct['faultString']; } if (empty($code) && empty($message)) { require_once 'Polycast/XmlRpc/Exception.php'; throw new Polycast_XmlRpc_Exception('Fault code and string required'); } if (empty($code)) { $code = '404'; } if (empty($message)) { if (isset($this->_internal[$code])) { $message = $this->_internal[$code]; } else { $message = 'Unknown Error'; } } $this->setCode($code); $this->setMessage($message); return true; }