/** * This method catches any native method called on the client and calls it on the rpc server instead. * It automatically parses the resulting xml and returns native php type results. * * @param $name * @param $args * * @throws RemoteException when _throwExceptions is true and the server returns an XML-RPC Fault. * * @return array|mixed when handling a multiCall and the * arguments passed do not have the correct method call information */ public function __call($name, $args) { if (isset($this->_namespace)) { $name = $this->_namespace . '.' . $name; } if ($name === 'system.multiCall' || $name == 'system.multicall') { if (!$args || is_array($args) && count($args) == 0) { // multiCall is called without arguments, so return the fetch interface object return new MultiCall($this->_rootClient, $name); } elseif (is_array($args) && count($args) == 1 && is_array($args[0]) && !isset($args[0]['methodName'])) { // multicall is called with a simple array of calls. $args = $args[0]; } $this->_rootClient->_multiCall = false; $params = []; $bound = []; foreach ($args as $key => $arg) { if (!is_a($arg, 'Call') && (!is_array($arg) || !isset($arg['methodName']))) { throw new InvalidArgumentException('Argument ' . $key . ' is not a valid Ripcord call', Ripcord::NOT_RIPCORD_CALL); } if (is_a($arg, 'Call')) { $arg->index = count($params); $params[] = $arg->encode(); } else { $arg['index'] = count($params); $params[] = ['methodName' => $arg['methodName'], 'params' => isset($arg['params']) ? (array) $arg['params'] : []]; } $bound[$key] = $arg; } $args = [$params]; $this->_rootClient->_multiCallArgs = []; } if ($this->_rootClient->_multiCall) { $call = new Call($name, $args); $this->_rootClient->_multiCallArgs[] = $call; return $call; } if ($this->_rootClient->_cloneObjects) { //workaround for php bug 50282 foreach ($args as $key => $arg) { if (is_object($arg)) { $args[$key] = clone $arg; } } } $request = xmlrpc_encode_request($name, $args, $this->_outputOptions); $response = $this->_transport->post($this->_url, $request); $result = xmlrpc_decode($response, 'utf-8'); $this->_rootClient->_request = $request; $this->_rootClient->_response = $response; if (Ripcord::isFault($result) && $this->_throwExceptions) { throw new RemoteException($result['faultString'], $result['faultCode']); } if (isset($bound) && is_array($bound)) { foreach ($bound as $key => $callObject) { if (is_a($callObject, 'Call')) { $returnValue = $result[$callObject->index]; } else { $returnValue = $result[$callObject['index']]; } if (is_array($returnValue) && count($returnValue) == 1) { // XML-RPC specification says that non-fault results must be in a single item array $returnValue = current($returnValue); } if ($this->_autoDecode) { $type = xmlrpc_get_type($returnValue); switch ($type) { case 'base64': $returnValue = Ripcord::binary($returnValue); break; case 'datetime': $returnValue = Ripcord::timestamp($returnValue); break; } } if (is_a($callObject, 'Call')) { $callObject->bound = $returnValue; } $bound[$key] = $returnValue; } $result = $bound; } return $result; }
/** * Handles the given request xml. * * @param string $request_xml The incoming request. * * @return string */ public function handle($request_xml) { $result = $this->parseRequest($request_xml); if (!$result || Ripcord::isFault($result)) { return $result; } else { $method = $result['methodName']; $params = $result['params']; } if ($method == 'system.multiCall' || $method == 'system.multicall') { // php's xml-rpc server (xmlrpc-epi) crashes on multi call, so handle it ourselves... fixed in php 5.3.2 $result = $this->multiCall($params); } else { try { $result = xmlrpc_server_call_method($this->xmlrpc, $request_xml, null, $this->outputOptions); } catch (\Exception $e) { $result = xmlrpc_encode_request(null, Ripcord::fault($e->getCode(), $e->getMessage()), $this->outputOptions); } } return $result; }