home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / SOAP / Client.php < prev    next >
Encoding:
PHP Script  |  2006-04-07  |  24.6 KB  |  714 lines

  1. <?php
  2. /**
  3.  * This file contains the code for the SOAP client.
  4.  *
  5.  * PHP versions 4 and 5
  6.  *
  7.  * LICENSE: This source file is subject to version 2.02 of the PHP license,
  8.  * that is bundled with this package in the file LICENSE, and is available at
  9.  * through the world-wide-web at http://www.php.net/license/2_02.txt.  If you
  10.  * did not receive a copy of the PHP license and are unable to obtain it
  11.  * through the world-wide-web, please send a note to license@php.net so we can
  12.  * mail you a copy immediately.
  13.  *
  14.  * @category   Web Services
  15.  * @package    SOAP
  16.  * @author     Dietrich Ayala <dietrich@ganx4.com> Original Author
  17.  * @author     Shane Caraveo <Shane@Caraveo.com>   Port to PEAR and more
  18.  * @author     Chuck Hagenbuch <chuck@horde.org>   Maintenance
  19.  * @author     Jan Schneider <jan@horde.org>       Maintenance
  20.  * @copyright  2003-2005 The PHP Group
  21.  * @license    http://www.php.net/license/2_02.txt  PHP License 2.02
  22.  * @link       http://pear.php.net/package/SOAP
  23.  */
  24.  
  25. require_once 'SOAP/Value.php';
  26. require_once 'SOAP/Base.php';
  27. require_once 'SOAP/Transport.php';
  28. require_once 'SOAP/WSDL.php';
  29. require_once 'SOAP/Fault.php';
  30. require_once 'SOAP/Parser.php';
  31.  
  32. // Arnaud: the following code was taken from DataObject and adapted to suit
  33.  
  34. // this will be horrifically slow!!!!
  35. // NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer
  36. // these two are BC/FC handlers for call in PHP4/5
  37.  
  38. if (!class_exists('SOAP_Client_Overload')) {
  39.     if (substr(phpversion(), 0, 1) == 5) {
  40.         class SOAP_Client_Overload extends SOAP_Base {
  41.             function __call($method, $args)
  42.             {
  43.                 $return = null;
  44.                 $this->_call($method, $args, $return);
  45.                 return $return;
  46.             }
  47.         }
  48.     } else {
  49.         if (!function_exists('clone')) {
  50.             eval('function clone($t) { return $t; }');
  51.         }
  52.         eval('
  53.             class SOAP_Client_Overload extends SOAP_Base {
  54.                 function __call($method, $args, &$return)
  55.                 {
  56.                     return $this->_call($method, $args, $return);
  57.                 }
  58.             }');
  59.     }
  60. }
  61.  
  62. /**
  63.  * SOAP Client Class
  64.  *
  65.  * This class is the main interface for making soap requests.
  66.  *
  67.  * basic usage:<code>
  68.  *   $soapclient = new SOAP_Client( string path [ , boolean wsdl] );
  69.  *   echo $soapclient->call( string methodname [ , array parameters] );
  70.  * </code>
  71.  *
  72.  * Originally based on SOAPx4 by Dietrich Ayala
  73.  * http://dietrich.ganx4.com/soapx4
  74.  *
  75.  * @access   public
  76.  * @package  SOAP
  77.  * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  78.  * @author   Stig Bakken <ssb@fast.no> Conversion to PEAR
  79.  * @author   Dietrich Ayala <dietrich@ganx4.com> Original Author
  80.  */
  81. class SOAP_Client extends SOAP_Client_Overload
  82. {
  83.     /**
  84.      * Communication endpoint.
  85.      *
  86.      * Currently the following transport formats are supported:
  87.      *  - HTTP
  88.      *  - SMTP
  89.      *
  90.      * Example endpoints:
  91.      *   http://www.example.com/soap/server.php
  92.      *   https://www.example.com/soap/server.php
  93.      *   mailto:soap@example.com
  94.      *
  95.      * @see  SOAP_Client()
  96.      * @var $_endpoint string
  97.      */
  98.     var $_endpoint = '';
  99.  
  100.     /**
  101.      * The SOAP PORT name that is used by the client.
  102.      *
  103.      * @var $_portName string
  104.      */
  105.     var $_portName = '';
  106.  
  107.     /**
  108.      * Endpoint type e.g. 'wdsl'.
  109.      *
  110.      * @var $__endpointType string
  111.      */
  112.     var $__endpointType = '';
  113.  
  114.     /**
  115.      * The received xml.
  116.      *
  117.      * @var $xml string
  118.      */
  119.     var $xml;
  120.  
  121.     /**
  122.      * The outgoing and incoming data stream for debugging.
  123.      *
  124.      * @var $wire string
  125.      */
  126.     var $wire;
  127.     var $__last_request = null;
  128.     var $__last_response = null;
  129.  
  130.     /**
  131.      * Options.
  132.      *
  133.      * @var $__options array
  134.      */
  135.     var $__options = array('trace'=>0);
  136.  
  137.     /**
  138.      * The character encoding used for XML parser, etc.
  139.      *
  140.      * @var $_encoding string
  141.      */
  142.     var $_encoding = SOAP_DEFAULT_ENCODING;
  143.  
  144.     /**
  145.      * The array of SOAP_Headers that we are sending.
  146.      *
  147.      * @var $headersOut array
  148.      */
  149.     var $headersOut = null;
  150.  
  151.     /**
  152.      * The headers we recieved back in the response.
  153.      *
  154.      * @var $headersIn array
  155.      */
  156.     var $headersIn = null;
  157.  
  158.     /**
  159.      * Options for the HTTP_Request class (see HTTP/Request.php).
  160.      *
  161.      * @var $__proxy_params array
  162.      */
  163.     var $__proxy_params = array();
  164.  
  165.     var $_soap_transport = null;
  166.  
  167.     /**
  168.      * Constructor.
  169.      *
  170.      * @access public
  171.      *
  172.      * @param string $endpoint     An URL.
  173.      * @param boolean $wsdl        Whether the endpoint is a WSDL file.
  174.      * @param string $portName
  175.      * @param array $proxy_params  Options for the HTTP_Request class (see
  176.      *                             HTTP/Request.php)
  177.      */
  178.     function SOAP_Client($endpoint, $wsdl = false, $portName = false,
  179.                          $proxy_params = array())
  180.     {
  181.         parent::SOAP_Base('Client');
  182.  
  183.         $this->_endpoint = $endpoint;
  184.         $this->_portName = $portName;
  185.         $this->__proxy_params = $proxy_params;
  186.  
  187.         // This hack should perhaps be removed as it might cause unexpected
  188.         // behaviour.
  189.         $wsdl = $wsdl
  190.             ? $wsdl
  191.             : strtolower(substr($endpoint, -4)) == 'wsdl';
  192.  
  193.         // make values
  194.         if ($wsdl) {
  195.             $this->__endpointType = 'wsdl';
  196.             // instantiate wsdl class
  197.             $this->_wsdl =& new SOAP_WSDL($this->_endpoint,
  198.                                           $this->__proxy_params);
  199.             if ($this->_wsdl->fault) {
  200.                 $this->_raiseSoapFault($this->_wsdl->fault);
  201.             }
  202.         }
  203.     }
  204.  
  205.     function _reset()
  206.     {
  207.         $this->xml = null;
  208.         $this->wire = null;
  209.         $this->__last_request = null;
  210.         $this->__last_response = null;
  211.         $this->headersIn = null;
  212.         $this->headersOut = null;
  213.     }
  214.  
  215.     /**
  216.      * Sets the character encoding.
  217.      *
  218.      * Limited to 'UTF-8', 'US_ASCII' and 'ISO-8859-1'.
  219.      *
  220.      * @access public
  221.      *
  222.      * @param string encoding
  223.      *
  224.      * @return mixed  SOAP_Fault on error.
  225.      */
  226.     function setEncoding($encoding)
  227.     {
  228.         if (in_array($encoding, $this->_encodings)) {
  229.             $this->_encoding = $encoding;
  230.             return;
  231.         }
  232.         return $this->_raiseSoapFault('Invalid Encoding');
  233.     }
  234.  
  235.     /**
  236.      * Adds a header to the envelope.
  237.      *
  238.      * @access public
  239.      *
  240.      * @param SOAP_Header $soap_value  A SOAP_Header or an array with the
  241.      *                                 elements 'name', 'namespace',
  242.      *                                 'mustunderstand', and 'actor' to send
  243.      *                                 as a header.
  244.      */
  245.     function addHeader(&$soap_value)
  246.     {
  247.         // Add a new header to the message.
  248.         if (is_a($soap_value, 'SOAP_Header')) {
  249.             $this->headersOut[] =& $soap_value;
  250.         } elseif (is_array($soap_value)) {
  251.             // name, value, namespace, mustunderstand, actor
  252.             $this->headersOut[] =& new SOAP_Header($soap_value[0],
  253.                                                    null,
  254.                                                    $soap_value[1],
  255.                                                    $soap_value[2],
  256.                                                    $soap_value[3]);;
  257.         } else {
  258.             $this->_raiseSoapFault('Invalid parameter provided to addHeader().  Must be an array or a SOAP_Header.');
  259.         }
  260.     }
  261.  
  262.     /**
  263.      * Calls a method on the SOAP endpoint.
  264.      *
  265.      * The namespace parameter is overloaded to accept an array of options
  266.      * that can contain data necessary for various transports if it is used as
  267.      * an array, it MAY contain a namespace value and a soapaction value.  If
  268.      * it is overloaded, the soapaction parameter is ignored and MUST be
  269.      * placed in the options array.  This is done to provide backwards
  270.      * compatibility with current clients, but may be removed in the future.
  271.      * The currently supported values are:<pre>
  272.      *   namespace
  273.      *   soapaction
  274.      *   timeout (HTTP socket timeout)
  275.      *   transfer-encoding (SMTP, Content-Transfer-Encoding: header)
  276.      *   from (SMTP, From: header)
  277.      *   subject (SMTP, Subject: header)
  278.      *   headers (SMTP, hash of extra SMTP headers)
  279.      * </pre>
  280.      *
  281.      * @access public
  282.      *
  283.      * @param string $method           The method to call.
  284.      * @param array $params            The method parameters.
  285.      * @param string|array $namespace  Namespace or hash with options.
  286.      * @param string $soapAction
  287.      *
  288.      * @return mixed  The method result or a SOAP_Fault on error.
  289.      */
  290.     function &call($method, &$params, $namespace = false, $soapAction = false)
  291.     {
  292.         $this->headersIn = null;
  293.         $this->__last_request = null;
  294.         $this->__last_response = null;
  295.         $this->wire = null;
  296.         $this->xml = null;
  297.  
  298.         $soap_data =& $this->__generate($method, $params, $namespace, $soapAction);
  299.         if (PEAR::isError($soap_data)) {
  300.             return $this->_raiseSoapFault($soap_data);
  301.         }
  302.  
  303.         // __generate() may have changed the endpoint if the WSDL has more
  304.         // than one service, so we need to see if we need to generate a new
  305.         // transport to hook to a different URI.  Since the transport protocol
  306.         // can also change, we need to get an entirely new object.  This could
  307.         // probably be optimized.
  308.         if (!$this->_soap_transport ||
  309.             $this->_endpoint != $this->_soap_transport->url) {
  310.             $this->_soap_transport =& SOAP_Transport::getTransport($this->_endpoint);
  311.             if (PEAR::isError($this->_soap_transport)) {
  312.                 $fault =& $this->_soap_transport;
  313.                 $this->_soap_transport = null;
  314.                 return $this->_raiseSoapFault($fault);
  315.             }
  316.         }
  317.         $this->_soap_transport->encoding = $this->_encoding;
  318.  
  319.         // Send the message.
  320.         $transport_options = array_merge_recursive($this->__proxy_params,
  321.                                                    $this->__options);
  322.         $this->xml =& $this->_soap_transport->send($soap_data, $transport_options);
  323.  
  324.         // Save the wire information for debugging.
  325.         if ($this->__options['trace'] > 0) {
  326.             $this->__last_request =& $this->_soap_transport->outgoing_payload;
  327.             $this->__last_response =& $this->_soap_transport->incoming_payload;
  328.             $this->wire =& $this->__get_wire();
  329.         }
  330.         if ($this->_soap_transport->fault) {
  331.             return $this->_raiseSoapFault($this->xml);
  332.         }
  333.  
  334.         $this->__attachments =& $this->_soap_transport->attachments;
  335.         $this->__result_encoding = $this->_soap_transport->result_encoding;
  336.  
  337.         if (isset($this->__options['result']) &&
  338.             $this->__options['result'] != 'parse') {
  339.             return $this->xml;
  340.         }
  341.  
  342.         return $this->__parse($this->xml, $this->__result_encoding, $this->__attachments);
  343.     }
  344.  
  345.     /**
  346.      * Sets an option to use with the transport layers.
  347.      *
  348.      * For example:
  349.      * <code>
  350.      * $soapclient->setOpt('curl', CURLOPT_VERBOSE, 1)
  351.      * </code>
  352.      * to pass a specific option to curl if using an SSL connection.
  353.      *
  354.      * @access public
  355.      *
  356.      * @param string $category  Category to which the option applies or option
  357.      *                          name.
  358.      * @param string $option    An option name if $category is a category name,
  359.      *                          an option value if $category is an option name.
  360.      * @param string $value     An option value if $category is a category
  361.      *                          name.
  362.      */
  363.     function setOpt($category, $option, $value = null)
  364.     {
  365.         if (!is_null($value)) {
  366.             if (!isset($this->__options[$category])) {
  367.                 $this->__options[$category] = array();
  368.             }
  369.             $this->__options[$category][$option] = $value;
  370.         } else {
  371.             $this->__options[$category] = $option;
  372.         }
  373.     }
  374.  
  375.     /**
  376.      * Call method supporting the overload extension.
  377.      *
  378.      * If the overload extension is loaded, you can call the client class with
  379.      * a soap method name:
  380.      * <code>
  381.      * $soap = new SOAP_Client(....);
  382.      * $value = $soap->getStockQuote('MSFT');
  383.      * </code>
  384.      *
  385.      * @access public
  386.      *
  387.      * @param string $method        The method to call.
  388.      * @param array $params         The method parameters.
  389.      * @param string $return_value  Will get the method's return value
  390.      *                              assigned.
  391.      *
  392.      * @return boolean  Always true.
  393.      */
  394.     function _call($method, $params, &$return_value)
  395.     {
  396.         // Overloading lowercases the method name, we need to look into the
  397.         // wsdl and try to find the correct method name to get the correct
  398.         // case for the call.
  399.         if ($this->_wsdl) {
  400.             $this->_wsdl->matchMethod($method);
  401.         }
  402.  
  403.         $return_value =& $this->call($method, $params);
  404.  
  405.         return true;
  406.     }
  407.  
  408.     function &__getlastrequest()
  409.     {
  410.         return $this->__last_request;
  411.     }
  412.  
  413.     function &__getlastresponse()
  414.     {
  415.         return $this->__last_response;
  416.     }
  417.  
  418.     function __use($use)
  419.     {
  420.         $this->__options['use'] = $use;
  421.     }
  422.  
  423.     function __style($style)
  424.     {
  425.         $this->__options['style'] = $style;
  426.     }
  427.  
  428.     function __trace($level)
  429.     {
  430.         $this->__options['trace'] = $level;
  431.     }
  432.  
  433.     function &__generate($method, &$params, $namespace = false,
  434.                          $soapAction = false)
  435.     {
  436.         $this->fault = null;
  437.         $this->__options['input']='parse';
  438.         $this->__options['result']='parse';
  439.         $this->__options['parameters'] = false;
  440.  
  441.         if ($params && gettype($params) != 'array') {
  442.             $params = array($params);
  443.         }
  444.  
  445.         if (gettype($namespace) == 'array') {
  446.             foreach ($namespace as $optname => $opt) {
  447.                 $this->__options[strtolower($optname)] = $opt;
  448.             }
  449.             if (isset($this->__options['namespace'])) {
  450.                 $namespace = $this->__options['namespace'];
  451.             } else {
  452.                 $namespace = false;
  453.             }
  454.         } else {
  455.             // We'll place $soapAction into our array for usage in the
  456.             // transport.
  457.             $this->__options['soapaction'] = $soapAction;
  458.             $this->__options['namespace'] = $namespace;
  459.         }
  460.  
  461.         if ($this->__endpointType == 'wsdl') {
  462.             $this->_setSchemaVersion($this->_wsdl->xsd);
  463.  
  464.             // Get port name.
  465.             if (!$this->_portName) {
  466.                 $this->_portName = $this->_wsdl->getPortName($method);
  467.             }
  468.             if (PEAR::isError($this->_portName)) {
  469.                 return $this->_raiseSoapFault($this->_portName);
  470.             }
  471.  
  472.             // Get endpoint.
  473.             $this->_endpoint = $this->_wsdl->getEndpoint($this->_portName);
  474.             if (PEAR::isError($this->_endpoint)) {
  475.                 return $this->_raiseSoapFault($this->_endpoint);
  476.             }
  477.  
  478.             // Get operation data.
  479.             $opData = $this->_wsdl->getOperationData($this->_portName, $method);
  480.  
  481.             if (PEAR::isError($opData)) {
  482.                 return $this->_raiseSoapFault($opData);
  483.             }
  484.             $namespace = $opData['namespace'];
  485.             $this->__options['style'] = $opData['style'];
  486.             $this->__options['use'] = $opData['input']['use'];
  487.             $this->__options['soapaction'] = $opData['soapAction'];
  488.  
  489.             // Set input parameters.
  490.             if ($this->__options['input'] == 'parse') {
  491.                 $this->__options['parameters'] = $opData['parameters'];
  492.                 $nparams = array();
  493.                 if (isset($opData['input']['parts']) &&
  494.                     count($opData['input']['parts'])) {
  495.                     $i = 0;
  496.                     foreach ($opData['input']['parts'] as $name => $part) {
  497.                         $xmlns = '';
  498.                         $attrs = array();
  499.                         // Is the name a complex type?
  500.                         if (isset($part['element'])) {
  501.                             $xmlns = $this->_wsdl->namespaces[$part['namespace']];
  502.                             $part = $this->_wsdl->elements[$part['namespace']][$part['type']];
  503.                             $name = $part['name'];
  504.                         }
  505.                         if (isset($params[$name]) ||
  506.                             $this->_wsdl->getDataHandler($name, $part['namespace'])) {
  507.                             $nparams[$name] =& $params[$name];
  508.                         } else {
  509.                             // We now force an associative array for
  510.                             // parameters if using WSDL.
  511.                             return $this->_raiseSoapFault("The named parameter $name is not in the call parameters.");
  512.                         }
  513.                         if (gettype($nparams[$name]) != 'object' ||
  514.                             !is_a($nparams[$name], 'SOAP_Value')) {
  515.                             // Type is likely a qname, split it apart, and get
  516.                             // the type namespace from WSDL.
  517.                             $qname =& new QName($part['type']);
  518.                             if ($qname->ns) {
  519.                                 $type_namespace = $this->_wsdl->namespaces[$qname->ns];
  520.                             } elseif (isset($part['namespace'])) {
  521.                                 $type_namespace = $this->_wsdl->namespaces[$part['namespace']];
  522.                             } else {
  523.                                 $type_namespace = null;
  524.                             }
  525.                             $qname->namespace = $type_namespace;
  526.                             $type = $qname->name;
  527.                             $pqname = $name;
  528.                             if ($xmlns) {
  529.                                 $pqname = '{' . $xmlns . '}' . $name;
  530.                             }
  531.                             $nparams[$name] =& new SOAP_Value($pqname,
  532.                                                               $qname->fqn(),
  533.                                                               $nparams[$name],
  534.                                                               $attrs);
  535.                         } else {
  536.                             // WSDL fixups to the SOAP value.
  537.                         }
  538.                     }
  539.                 }
  540.                 $params =& $nparams;
  541.                 unset($nparams);
  542.             }
  543.         } else {
  544.             $this->_setSchemaVersion(SOAP_XML_SCHEMA_VERSION);
  545.         }
  546.  
  547.         // Serialize the message.
  548.         $this->_section5 = (isset($this->__options['use']) &&
  549.                             $this->__options['use'] == 'literal');
  550.  
  551.         if (!isset($this->__options['style']) ||
  552.             $this->__options['style'] == 'rpc') {
  553.             $this->__options['style'] = 'rpc';
  554.             $this->docparams = true;
  555.             $mqname =& new QName($method, $namespace);
  556.             $methodValue =& new SOAP_Value($mqname->fqn(), 'Struct', $params);
  557.             $soap_msg =& $this->_makeEnvelope($methodValue,
  558.                                               $this->headersOut,
  559.                                               $this->_encoding,
  560.                                               $this->__options);
  561.         } else {
  562.             if (!$params) {
  563.                 $mqname =& new QName($method, $namespace);
  564.                 $mynull = null;
  565.                 $params =& new SOAP_Value($mqname->fqn(), 'Struct', $mynull);
  566.             } elseif ($this->__options['input'] == 'parse') {
  567.                 if (is_array($params)) {
  568.                     $nparams = array();
  569.                     $keys = array_keys($params);
  570.                     foreach ($keys as $k) {
  571.                         if (gettype($params[$k]) != 'object') {
  572.                             $nparams[] =& new SOAP_Value($k,
  573.                                                          false,
  574.                                                          $params[$k]);
  575.                         } else {
  576.                             $nparams[] =& $params[$k];
  577.                         }
  578.                     }
  579.                     $params =& $nparams;
  580.                 }
  581.                 if ($this->__options['parameters']) {
  582.                     $mqname =& new QName($method, $namespace);
  583.                     $params =& new SOAP_Value($mqname->fqn(),
  584.                                               'Struct',
  585.                                               $params);
  586.                 }
  587.             }
  588.             $soap_msg =& $this->_makeEnvelope($params,
  589.                                               $this->headersOut,
  590.                                               $this->_encoding,
  591.                                               $this->__options);
  592.         }
  593.         unset($this->headersOut);
  594.  
  595.         if (PEAR::isError($soap_msg)) {
  596.             return $this->_raiseSoapFault($soap_msg);
  597.         }
  598.  
  599.         // Handle MIME or DIME encoding.
  600.         // TODO: DIME encoding should move to the transport, do it here for
  601.         // now and for ease of getting it done.
  602.         if (count($this->__attachments)) {
  603.             if ((isset($this->__options['attachments']) &&
  604.                  $this->__options['attachments'] == 'Mime') ||
  605.                 isset($this->__options['Mime'])) {
  606.                 $soap_msg =& $this->_makeMimeMessage($soap_msg,
  607.                                                      $this->_encoding);
  608.             } else {
  609.                 // default is dime
  610.                 $soap_msg =& $this->_makeDIMEMessage($soap_msg,
  611.                                                      $this->_encoding);
  612.                 $this->__options['headers']['Content-Type'] = 'application/dime';
  613.             }
  614.             if (PEAR::isError($soap_msg)) {
  615.                 return $this->_raiseSoapFault($soap_msg);
  616.             }
  617.         }
  618.  
  619.         // Instantiate client.
  620.         if (is_array($soap_msg)) {
  621.             $soap_data =& $soap_msg['body'];
  622.             if (count($soap_msg['headers'])) {
  623.                 if (isset($this->__options['headers'])) {
  624.                     $this->__options['headers'] = array_merge($this->__options['headers'], $soap_msg['headers']);
  625.                 } else {
  626.                     $this->__options['headers'] = $soap_msg['headers'];
  627.                 }
  628.             }
  629.         } else {
  630.             $soap_data =& $soap_msg;
  631.         }
  632.  
  633.         return $soap_data;
  634.     }
  635.  
  636.     function &__parse(&$response, $encoding, &$attachments)
  637.     {
  638.         // Parse the response.
  639.         $response =& new SOAP_Parser($response, $encoding, $attachments);
  640.         if ($response->fault) {
  641.             return $this->_raiseSoapFault($response->fault);
  642.         }
  643.  
  644.         // Return array of parameters.
  645.         $return =& $response->getResponse();
  646.         $headers =& $response->getHeaders();
  647.         if ($headers) {
  648.             $this->headersIn =& $this->__decodeResponse($headers, false);
  649.         }
  650.  
  651.         return $this->__decodeResponse($return);
  652.     }
  653.  
  654.     function &__decodeResponse(&$response, $shift = true)
  655.     {
  656.         if (!$response) {
  657.             return null;
  658.         }
  659.  
  660.         // Check for valid response.
  661.         if (PEAR::isError($response)) {
  662.             return $this->_raiseSoapFault($response);
  663.         } elseif (!is_a($response, 'soap_value')) {
  664.             return $this->_raiseSoapFault("Didn't get SOAP_Value object back from client");
  665.         }
  666.  
  667.         // Decode to native php datatype.
  668.         $returnArray =& $this->_decode($response);
  669.  
  670.         // Fault?
  671.         if (PEAR::isError($returnArray)) {
  672.             return $this->_raiseSoapFault($returnArray);
  673.         }
  674.  
  675.         if (is_object($returnArray) &&
  676.             strcasecmp(get_class($returnArray), 'stdClass') == 0) {
  677.             $returnArray = get_object_vars($returnArray);
  678.         }
  679.         if (is_array($returnArray)) {
  680.             if (isset($returnArray['faultcode']) ||
  681.                 isset($returnArray['SOAP-ENV:faultcode'])) {
  682.                 $faultcode = $faultstring = $faultdetail = $faultactor = '';
  683.                 foreach ($returnArray as $k => $v) {
  684.                     if (stristr($k, 'faultcode')) $faultcode = $v;
  685.                     if (stristr($k, 'faultstring')) $faultstring = $v;
  686.                     if (stristr($k, 'detail')) $faultdetail = $v;
  687.                     if (stristr($k, 'faultactor')) $faultactor = $v;
  688.                 }
  689.                 return $this->_raiseSoapFault($faultstring, $faultdetail, $faultactor, $faultcode);
  690.             }
  691.             // Return array of return values.
  692.             if ($shift && count($returnArray) == 1) {
  693.                 return array_shift($returnArray);
  694.             }
  695.             return $returnArray;
  696.         }
  697.         return $returnArray;
  698.     }
  699.  
  700.     function __get_wire()
  701.     {
  702.         if ($this->__options['trace'] > 0 &&
  703.             ($this->__last_request || $this->__last_response)) {
  704.             return "OUTGOING:\n\n" .
  705.                 $this->__last_request .
  706.                 "\n\nINCOMING\n\n" .
  707.                 preg_replace("/></",">\r\n<", $this->__last_response);
  708.         }
  709.  
  710.         return null;
  711.     }
  712.  
  713. }
  714.