/** * Calls a method on the SOAP endpoint. * * The namespace parameter is overloaded to accept an array of options * that can contain data necessary for various transports if it is used as * an array, it MAY contain a namespace value and a soapaction value. If * it is overloaded, the soapaction parameter is ignored and MUST be * placed in the options array. This is done to provide backwards * compatibility with current clients, but may be removed in the future. * The currently supported values are: * - 'namespace' * - 'soapaction' * - 'timeout': HTTP socket timeout * - 'transfer-encoding': SMTP transport, Content-Transfer-Encoding: header * - 'from': SMTP transport, From: header * - 'subject': SMTP transport, Subject: header * - 'headers': SMTP transport, hash of extra SMTP headers * - 'attachments': what encoding to use for attachments (Mime, Dime) * - 'trace': whether to trace the SOAP communication * - 'style': 'document' or 'rpc'; when set to 'document' the parameters * are not wrapped inside a tag with the SOAP action name * - 'use': 'literal' for literal encoding, anything else for section 5 * encoding; when set to 'literal' SOAP types will be omitted. * - 'keep_arrays_flat': use the tag name multiple times for each element * when passing in an array in literal mode * - 'no_type_prefix': supress adding of the namespace prefix * * @access public * * @param string $method The method to call. * @param array $params The method parameters. * @param string|array $namespace Namespace or hash with options. Note: * most options need to be repeated for * SOAP_Value instances. * @param string $soapAction * * @return mixed The method result or a SOAP_Fault on error. */ function call($method, $params, $namespace = false, $soapAction = false) { $this->headersIn = null; $this->_last_request = null; $this->_last_response = null; $this->wire = null; $this->xml = null; $soap_data = $this->_generate($method, $params, $namespace, $soapAction); if (PEAR::isError($soap_data)) { $fault = $this->_raiseSoapFault($soap_data); return $fault; } // _generate() may have changed the endpoint if the WSDL has more // than one service, so we need to see if we need to generate a new // transport to hook to a different URI. Since the transport protocol // can also change, we need to get an entirely new object. This could // probably be optimized. if (!$this->_soap_transport || $this->_endpoint != $this->_soap_transport->url) { $this->_soap_transport = SOAP_Transport::getTransport($this->_endpoint); if (PEAR::isError($this->_soap_transport)) { $fault = $this->_raiseSoapFault($this->_soap_transport); $this->_soap_transport = null; return $fault; } } $this->_soap_transport->encoding = $this->_encoding; // Send the message. $transport_options = array_merge_recursive($this->_proxy_params, $this->_options); $this->xml = $this->_soap_transport->send($soap_data, $transport_options); // Save the wire information for debugging. if ($this->_options['trace']) { $this->_last_request = $this->_soap_transport->outgoing_payload; $this->_last_response = $this->_soap_transport->incoming_payload; $this->wire = $this->getWire(); } if ($this->_soap_transport->fault) { $fault = $this->_raiseSoapFault($this->xml); return $fault; } if (isset($this->_options['result']) && $this->_options['result'] != 'parse') { return $this->xml; } $this->__result_encoding = $this->_soap_transport->result_encoding; $result = $this->parseResponse($this->xml, $this->__result_encoding, $this->_soap_transport->attachments); return $result; }
/** * SOAP_Client::call * * @param string method * @param array params * @param string namespace (not required if using wsdl) * @param string soapAction (not required if using wsdl) * * @return array of results * @access public */ function call($method, $params = array(), $namespace = false, $soapAction = false) { $this->fault = null; if ($this->endpointType == 'wsdl') { $this->setSchemaVersion($this->wsdl->xsd); // get portName if (!$this->portName) { $this->portName = $this->wsdl->getPortName($method); if (PEAR::isError($this->portName)) { return $this->raiseSoapFault($this->portName); } } $namespace = $this->wsdl->getNamespace($this->portName, $method); // get endpoint $this->endpoint = $this->wsdl->getEndpoint($this->portName); if (PEAR::isError($this->endpoint)) { return $this->raiseSoapFault($this->endpoint); } $this->debug("endpoint: {$this->endpoint}"); $this->debug("portName: {$this->portName}"); // get operation data $opData = $this->wsdl->getOperationData($this->portName, $method); if (PEAR::isError($opData)) { return $this->raiseSoapFault($opData); } $soapAction = $opData['soapAction']; // set input params $nparams = array(); if (count($opData['input']['parts']) > 0) { $i = 0; reset($params); foreach ($opData['input']['parts'] as $name => $type) { if (isset($params[$name])) { $nparams[$name] = $params[$name]; } else { // XXX assuming it's an array, not a hash // XXX this is pretty pethetic, but "fixes" a problem where // paremeter names do not match correctly $nparams[$name] = current($params); next($params); } if (gettype($nparams[$name]) != 'object' && get_class($nparams[$name]) != 'soap_value') { // type is a qname likely, split it apart, and get the type namespace from wsdl $qname = new QName($type); if ($qname->ns) { $type_namespace = $this->wsdl->namespaces[$qname->ns]; } else { $type_namespace = NULL; } $type = $qname->name; $nparams[$name] = new SOAP_Value($name, $type, $nparams[$name], $namespace, $type_namespace, $this->wsdl); } } } $params = $nparams; } $this->debug("soapAction: {$soapAction}"); $this->debug("namespace: {$namespace}"); // make message $soapmsg = new SOAP_Message($method, $params, $namespace, NULL, $this->wsdl); if ($soapmsg->fault) { return $this->raiseSoapFault($soapmsg->fault); } // serialize the message $soap_data = $soapmsg->serialize(); $this->debug("soap_data " . $soap_data); if (PEAR::isError($soap_data)) { return $this->raiseSoapFault($soap_data); } $this->debug('<xmp>' . $soap_data . '</xmp>'); // instantiate client $dbg = "calling server at '{$this->endpoint}'..."; $soap_transport = new SOAP_Transport($this->endpoint, $this->debug_flag); if ($soap_transport->fault) { return $this->raiseSoapFault($soap_transport->fault); } $this->debug($dbg . 'instantiated client successfully'); $this->debug("endpoint: {$this->endpoint}<br>\n"); // send $dbg = "sending msg w/ soapaction '{$soapAction}'..."; // send the message $this->response = $soap_transport->send($soap_data, $soapAction); if ($soap_transport->fault) { return $this->raiseSoapFault($this->response); } // parse the response $return = $soapmsg->parseResponse($this->response); $this->debug($soap_transport->debug_data); $this->debug($dbg . 'sent message successfully and got a(n) ' . gettype($return) . ' back'); // check for valid response if (PEAR::isError($return)) { return $this->raiseSoapFault($return); } else { if (strcasecmp(get_class($return), 'SOAP_Value') != 0) { return $this->raiseSoapFault("didn't get SOAP_Value object back from client"); } } // decode to native php datatype $returnArray = $return->decode(); // fault? if (PEAR::isError($returnArray)) { return $this->raiseSoapFault($returnArray); } if (is_array($returnArray)) { if (isset($returnArray['faultcode']) || isset($returnArray['SOAP-ENV:faultcode'])) { foreach ($returnArray as $k => $v) { if (stristr($k, 'faultcode')) { $this->faultcode = $v; } if (stristr($k, 'faultstring')) { $this->faultstring = $v; } if (stristr($k, 'faultdetail')) { $this->faultdetail = $v; } if (stristr($k, 'faultactor')) { $this->faultactor = $v; } } return $this->raiseSoapFault($this->faultstring, $this->faultdetail, $this->faultactor, $this->faultcode); } // return array of return values if (count($returnArray) == 1) { return array_shift($returnArray); } return $returnArray; } return $returnArray; }