home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / SOAP / Client.php < prev    next >
Encoding:
PHP Script  |  2007-12-20  |  27.8 KB  |  859 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(zend_version(), 0, 1) > 1) {
  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.  * or, if using PHP 5+ or the overload extension:<code>
  72.  *   $soapclient = new SOAP_Client( string path [ , boolean wsdl] );
  73.  *   echo $soapclient->methodname( [ array parameters] );
  74.  * </code>
  75.  *
  76.  * Originally based on SOAPx4 by Dietrich Ayala
  77.  * http://dietrich.ganx4.com/soapx4
  78.  *
  79.  * @access   public
  80.  * @package  SOAP
  81.  * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  82.  * @author   Stig Bakken <ssb@fast.no> Conversion to PEAR
  83.  * @author   Dietrich Ayala <dietrich@ganx4.com> Original Author
  84.  */
  85. class SOAP_Client extends SOAP_Client_Overload
  86. {
  87.     /**
  88.      * Communication endpoint.
  89.      *
  90.      * Currently the following transport formats are supported:
  91.      *  - HTTP
  92.      *  - SMTP
  93.      *
  94.      * Example endpoints:
  95.      *   http://www.example.com/soap/server.php
  96.      *   https://www.example.com/soap/server.php
  97.      *   mailto:soap@example.com
  98.      *
  99.      * @see SOAP_Client()
  100.      * @var string
  101.      */
  102.     var $_endpoint = '';
  103.  
  104.     /**
  105.      * The SOAP PORT name that is used by the client.
  106.      *
  107.      * @var string
  108.      */
  109.     var $_portName = '';
  110.  
  111.     /**
  112.      * Endpoint type e.g. 'wdsl'.
  113.      *
  114.      * @var string
  115.      */
  116.     var $_endpointType = '';
  117.  
  118.     /**
  119.      * The received xml.
  120.      *
  121.      * @var string
  122.      */
  123.     var $xml;
  124.  
  125.     /**
  126.      * The outgoing and incoming data stream for debugging.
  127.      *
  128.      * @var string
  129.      */
  130.     var $wire;
  131.  
  132.     /**
  133.      * The outgoing data stream for debugging.
  134.      *
  135.      * @var string
  136.      */
  137.     var $_last_request = null;
  138.  
  139.     /**
  140.      * The incoming data stream for debugging.
  141.      *
  142.      * @var string
  143.      */
  144.     var $_last_response = null;
  145.  
  146.     /**
  147.      * Options.
  148.      *
  149.      * @var array
  150.      */
  151.     var $_options = array('trace' => false);
  152.  
  153.     /**
  154.      * The character encoding used for XML parser, etc.
  155.      *
  156.      * @var string
  157.      */
  158.     var $_encoding = SOAP_DEFAULT_ENCODING;
  159.  
  160.     /**
  161.      * The array of SOAP_Headers that we are sending.
  162.      *
  163.      * @var array
  164.      */
  165.     var $headersOut = null;
  166.  
  167.     /**
  168.      * The headers we recieved back in the response.
  169.      *
  170.      * @var array
  171.      */
  172.     var $headersIn = null;
  173.  
  174.     /**
  175.      * Options for the HTTP_Request class (see HTTP/Request.php).
  176.      *
  177.      * @var array
  178.      */
  179.     var $_proxy_params = array();
  180.  
  181.     /**
  182.      * The SOAP_Transport instance.
  183.      *
  184.      * @var SOAP_Transport
  185.      */
  186.     var $_soap_transport = null;
  187.  
  188.     /**
  189.      * Constructor.
  190.      *
  191.      * @access public
  192.      *
  193.      * @param string $endpoint       An URL.
  194.      * @param boolean $wsdl          Whether the endpoint is a WSDL file.
  195.      * @param string $portName       The service's port name to use.
  196.      * @param array $proxy_params    Options for the HTTP_Request class
  197.      *                               @see HTTP_Request
  198.      * @param boolean|string $cache  Use WSDL caching? The cache directory if
  199.      *                               a string.
  200.      */
  201.     function SOAP_Client($endpoint, $wsdl = false, $portName = false,
  202.                          $proxy_params = array(), $cache = false)
  203.     {
  204.         parent::SOAP_Base('Client');
  205.  
  206.         $this->_endpoint = $endpoint;
  207.         $this->_portName = $portName;
  208.         $this->_proxy_params = $proxy_params;
  209.  
  210.         // This hack should perhaps be removed as it might cause unexpected
  211.         // behaviour.
  212.         $wsdl = $wsdl
  213.             ? $wsdl
  214.             : strtolower(substr($endpoint, -4)) == 'wsdl';
  215.  
  216.         // make values
  217.         if ($wsdl) {
  218.             $this->_endpointType = 'wsdl';
  219.             // instantiate wsdl class
  220.             $this->_wsdl =& new SOAP_WSDL($this->_endpoint,
  221.                                           $this->_proxy_params,
  222.                                           $cache);
  223.             if ($this->_wsdl->fault) {
  224.                 $this->_raiseSoapFault($this->_wsdl->fault);
  225.             }
  226.         }
  227.     }
  228.  
  229.     function _reset()
  230.     {
  231.         $this->xml = null;
  232.         $this->wire = null;
  233.         $this->_last_request = null;
  234.         $this->_last_response = null;
  235.         $this->headersIn = null;
  236.         $this->headersOut = null;
  237.     }
  238.  
  239.     /**
  240.      * Sets the character encoding.
  241.      *
  242.      * Limited to 'UTF-8', 'US_ASCII' and 'ISO-8859-1'.
  243.      *
  244.      * @access public
  245.      *
  246.      * @param string encoding
  247.      *
  248.      * @return mixed  SOAP_Fault on error.
  249.      */
  250.     function setEncoding($encoding)
  251.     {
  252.         if (in_array($encoding, $this->_encodings)) {
  253.             $this->_encoding = $encoding;
  254.             return;
  255.         }
  256.         return $this->_raiseSoapFault('Invalid Encoding');
  257.     }
  258.  
  259.     /**
  260.      * Adds a header to the envelope.
  261.      *
  262.      * @access public
  263.      *
  264.      * @param SOAP_Header $soap_value  A SOAP_Header or an array with the
  265.      *                                 elements 'name', 'namespace',
  266.      *                                 'mustunderstand', and 'actor' to send
  267.      *                                 as a header.
  268.      */
  269.     function addHeader(&$soap_value)
  270.     {
  271.         // Add a new header to the message.
  272.         if (is_a($soap_value, 'SOAP_Header')) {
  273.             $this->headersOut[] =& $soap_value;
  274.         } elseif (is_array($soap_value)) {
  275.             // name, value, namespace, mustunderstand, actor
  276.             $this->headersOut[] =& new SOAP_Header($soap_value[0],
  277.                                                    null,
  278.                                                    $soap_value[1],
  279.                                                    $soap_value[2],
  280.                                                    $soap_value[3]);;
  281.         } else {
  282.             $this->_raiseSoapFault('Invalid parameter provided to addHeader().  Must be an array or a SOAP_Header.');
  283.         }
  284.     }
  285.  
  286.     /**
  287.      * Calls a method on the SOAP endpoint.
  288.      *
  289.      * The namespace parameter is overloaded to accept an array of options
  290.      * that can contain data necessary for various transports if it is used as
  291.      * an array, it MAY contain a namespace value and a soapaction value.  If
  292.      * it is overloaded, the soapaction parameter is ignored and MUST be
  293.      * placed in the options array.  This is done to provide backwards
  294.      * compatibility with current clients, but may be removed in the future.
  295.      * The currently supported values are:<pre>
  296.      *   namespace
  297.      *   soapaction
  298.      *   timeout (HTTP socket timeout)
  299.      *   transfer-encoding (SMTP, Content-Transfer-Encoding: header)
  300.      *   from (SMTP, From: header)
  301.      *   subject (SMTP, Subject: header)
  302.      *   headers (SMTP, hash of extra SMTP headers)
  303.      * </pre>
  304.      *
  305.      * @access public
  306.      *
  307.      * @param string $method           The method to call.
  308.      * @param array $params            The method parameters.
  309.      * @param string|array $namespace  Namespace or hash with options.
  310.      * @param string $soapAction
  311.      *
  312.      * @return mixed  The method result or a SOAP_Fault on error.
  313.      */
  314.     function &call($method, &$params, $namespace = false, $soapAction = false)
  315.     {
  316.         $this->headersIn = null;
  317.         $this->_last_request = null;
  318.         $this->_last_response = null;
  319.         $this->wire = null;
  320.         $this->xml = null;
  321.  
  322.         $soap_data =& $this->_generate($method, $params, $namespace, $soapAction);
  323.         if (PEAR::isError($soap_data)) {
  324.             $fault =& $this->_raiseSoapFault($soap_data);
  325.             return $fault;
  326.         }
  327.  
  328.         // _generate() may have changed the endpoint if the WSDL has more
  329.         // than one service, so we need to see if we need to generate a new
  330.         // transport to hook to a different URI.  Since the transport protocol
  331.         // can also change, we need to get an entirely new object.  This could
  332.         // probably be optimized.
  333.         if (!$this->_soap_transport ||
  334.             $this->_endpoint != $this->_soap_transport->url) {
  335.             $this->_soap_transport =& SOAP_Transport::getTransport($this->_endpoint);
  336.             if (PEAR::isError($this->_soap_transport)) {
  337.                 $fault =& $this->_soap_transport;
  338.                 $this->_soap_transport = null;
  339.                 $fault =& $this->_raiseSoapFault($fault);
  340.                 return $fault;
  341.             }
  342.         }
  343.         $this->_soap_transport->encoding = $this->_encoding;
  344.  
  345.         // Send the message.
  346.         $transport_options = array_merge_recursive($this->_proxy_params,
  347.                                                    $this->_options);
  348.         $this->xml = $this->_soap_transport->send($soap_data, $transport_options);
  349.  
  350.         // Save the wire information for debugging.
  351.         if ($this->_options['trace']) {
  352.             $this->_last_request = $this->_soap_transport->outgoing_payload;
  353.             $this->_last_response = $this->_soap_transport->incoming_payload;
  354.             $this->wire = $this->getWire();
  355.         }
  356.         if ($this->_soap_transport->fault) {
  357.             $fault =& $this->_raiseSoapFault($this->xml);
  358.             return $fault;
  359.         }
  360.  
  361.         if (isset($this->_options['result']) &&
  362.             $this->_options['result'] != 'parse') {
  363.             return $this->xml;
  364.         }
  365.  
  366.         $this->__result_encoding = $this->_soap_transport->result_encoding;
  367.  
  368.         $result = &$this->parseResponse($this->xml, $this->__result_encoding,
  369.                                         $this->_soap_transport->attachments);
  370.         return $result;
  371.     }
  372.  
  373.     /**
  374.      * Sets an option to use with the transport layers.
  375.      *
  376.      * For example:
  377.      * <code>
  378.      * $soapclient->setOpt('curl', CURLOPT_VERBOSE, 1)
  379.      * </code>
  380.      * to pass a specific option to curl if using an SSL connection.
  381.      *
  382.      * @access public
  383.      *
  384.      * @param string $category  Category to which the option applies or option
  385.      *                          name.
  386.      * @param string $option    An option name if $category is a category name,
  387.      *                          an option value if $category is an option name.
  388.      * @param string $value     An option value if $category is a category
  389.      *                          name.
  390.      */
  391.     function setOpt($category, $option, $value = null)
  392.     {
  393.         if (!is_null($value)) {
  394.             if (!isset($this->_options[$category])) {
  395.                 $this->_options[$category] = array();
  396.             }
  397.             $this->_options[$category][$option] = $value;
  398.         } else {
  399.             $this->_options[$category] = $option;
  400.         }
  401.     }
  402.  
  403.     /**
  404.      * Call method supporting the overload extension.
  405.      *
  406.      * If the overload extension is loaded, you can call the client class with
  407.      * a soap method name:
  408.      * <code>
  409.      * $soap = new SOAP_Client(....);
  410.      * $value = $soap->getStockQuote('MSFT');
  411.      * </code>
  412.      *
  413.      * @access public
  414.      *
  415.      * @param string $method        The method to call.
  416.      * @param array $params         The method parameters.
  417.      * @param mixed $return_value   Will get the method's return value
  418.      *                              assigned.
  419.      *
  420.      * @return boolean  Always true.
  421.      */
  422.     function _call($method, $params, &$return_value)
  423.     {
  424.         // Overloading lowercases the method name, we need to look into the
  425.         // WSDL and try to find the correct method name to get the correct
  426.         // case for the call.
  427.         if ($this->_wsdl) {
  428.             $this->_wsdl->matchMethod($method);
  429.         }
  430.  
  431.         $return_value =& $this->call($method, $params);
  432.  
  433.         return true;
  434.     }
  435.  
  436.     /**
  437.      * @deprecated Use getLastRequest().
  438.      */
  439.     function &__getlastrequest()
  440.     {
  441.         $request = $this->getLastRequest();
  442.         return $request;
  443.     }
  444.  
  445.     /**
  446.      * Returns the XML content of the last SOAP request.
  447.      *
  448.      * @return string  The last request.
  449.      */
  450.     function getLastRequest()
  451.     {
  452.         return $this->_last_request;
  453.     }
  454.  
  455.     /**
  456.      * @deprecated Use getLastResponse().
  457.      */
  458.     function &__getlastresponse()
  459.     {
  460.         $response =& $this->getLastResponse;
  461.         return $response;
  462.     }
  463.  
  464.     /**
  465.      * Returns the XML content of the last SOAP response.
  466.      *
  467.      * @return string  The last response.
  468.      */
  469.     function getLastResponse()
  470.     {
  471.         return $this->_last_response;
  472.     }
  473.  
  474.     /**
  475.      * @deprecated Use setUse().
  476.      */
  477.     function __use($use)
  478.     {
  479.         $this->setUse($use);
  480.     }
  481.  
  482.     /**
  483.      * Sets the SOAP encoding.
  484.      *
  485.      * @param string $use  Either 'literal' or 'encoded' (section 5).
  486.      */
  487.     function setUse($use)
  488.     {
  489.         $this->_options['use'] = $use;
  490.     }
  491.  
  492.     /**
  493.      * @deprecated Use setStyle().
  494.      */
  495.     function __style($style)
  496.     {
  497.         $this->setStyle($style);
  498.     }
  499.  
  500.     /**
  501.      * Sets the SOAP encoding style.
  502.      *
  503.      * @param string $style  Either 'document' or 'rpc'.
  504.      */
  505.     function setStyle($style)
  506.     {
  507.         $this->_options['style'] = $style;
  508.     }
  509.  
  510.     /**
  511.      * @deprecated Use setTrace().
  512.      */
  513.     function __trace($level)
  514.     {
  515.         $this->setTrace($level);
  516.     }
  517.  
  518.     /**
  519.      * Sets whether to trace the traffic on the transport level.
  520.      *
  521.      * @see getWire()
  522.      *
  523.      * @param boolean $trace
  524.      */
  525.     function setTrace($trace)
  526.     {
  527.         $this->_options['trace'] = $trace;
  528.     }
  529.  
  530.     function &_generate($method, &$params, $namespace = false,
  531.                         $soapAction = false)
  532.     {
  533.         $this->fault = null;
  534.         $this->_options['input'] = 'parse'; 
  535.         $this->_options['result'] = 'parse';
  536.         $this->_options['parameters'] = false;
  537.  
  538.         if ($params && gettype($params) != 'array') {
  539.             $params = array($params);
  540.         }
  541.  
  542.         if (gettype($namespace) == 'array') {
  543.             foreach ($namespace as $optname => $opt) {
  544.                 $this->_options[strtolower($optname)] = $opt;
  545.             }
  546.             if (isset($this->_options['namespace'])) {
  547.                 $namespace = $this->_options['namespace'];
  548.             } else {
  549.                 $namespace = false;
  550.             }
  551.         } else {
  552.             // We'll place $soapAction into our array for usage in the
  553.             // transport.
  554.             $this->_options['soapaction'] = $soapAction;
  555.             $this->_options['namespace'] = $namespace;
  556.         }
  557.  
  558.         if ($this->_endpointType == 'wsdl') {
  559.             $this->_setSchemaVersion($this->_wsdl->xsd);
  560.  
  561.             // Get port name.
  562.             if (!$this->_portName) {
  563.                 $this->_portName = $this->_wsdl->getPortName($method);
  564.             }
  565.             if (PEAR::isError($this->_portName)) {
  566.                 $fault =& $this->_raiseSoapFault($this->_portName);
  567.                 return $fault;
  568.             }
  569.  
  570.             // Get endpoint.
  571.             $this->_endpoint = $this->_wsdl->getEndpoint($this->_portName);
  572.             if (PEAR::isError($this->_endpoint)) {
  573.                 $fault =& $this->_raiseSoapFault($this->_endpoint);
  574.                 return $fault;
  575.             }
  576.  
  577.             // Get operation data.
  578.             $opData = $this->_wsdl->getOperationData($this->_portName, $method);
  579.  
  580.             if (PEAR::isError($opData)) {
  581.                 $fault =& $this->_raiseSoapFault($opData);
  582.                 return $fault;
  583.             }
  584.             $namespace = $opData['namespace'];
  585.             $this->_options['style'] = $opData['style'];
  586.             $this->_options['use'] = $opData['input']['use'];
  587.             $this->_options['soapaction'] = $opData['soapAction'];
  588.  
  589.             // Set input parameters.
  590.             if ($this->_options['input'] == 'parse') {
  591.                 $this->_options['parameters'] = $opData['parameters'];
  592.                 $nparams = array();
  593.                 if (isset($opData['input']['parts']) &&
  594.                     count($opData['input']['parts'])) {
  595.                     $i = 0;
  596.                     foreach ($opData['input']['parts'] as $name => $part) {
  597.                         $xmlns = '';
  598.                         $attrs = array();
  599.                         // Is the name a complex type?
  600.                         if (isset($part['element'])) {
  601.                             $xmlns = $this->_wsdl->namespaces[$part['namespace']];
  602.                             $part = $this->_wsdl->elements[$part['namespace']][$part['type']];
  603.                             $name = $part['name'];
  604.                         }
  605.                         if (isset($params[$name]) ||
  606.                             $this->_wsdl->getDataHandler($name, $part['namespace'])) {
  607.                             $nparams[$name] =& $params[$name];
  608.                         } else {
  609.                             // We now force an associative array for
  610.                             // parameters if using WSDL.
  611.                             $fault =& $this->_raiseSoapFault("The named parameter $name is not in the call parameters.");
  612.                             return $fault;
  613.                         }
  614.                         if (gettype($nparams[$name]) != 'object' ||
  615.                             !is_a($nparams[$name], 'SOAP_Value')) {
  616.                             // Type is likely a qname, split it apart, and get
  617.                             // the type namespace from WSDL.
  618.                             $qname =& new QName($part['type']);
  619.                             if ($qname->ns) {
  620.                                 $type_namespace = $this->_wsdl->namespaces[$qname->ns];
  621.                             } elseif (isset($part['namespace'])) {
  622.                                 $type_namespace = $this->_wsdl->namespaces[$part['namespace']];
  623.                             } else {
  624.                                 $type_namespace = null;
  625.                             }
  626.                             $qname->namespace = $type_namespace;
  627.                             $type = $qname->name;
  628.                             $pqname = $name;
  629.                             if ($xmlns) {
  630.                                 $pqname = '{' . $xmlns . '}' . $name;
  631.                             }
  632.                             $nparams[$name] =& new SOAP_Value($pqname,
  633.                                                               $qname->fqn(),
  634.                                                               $nparams[$name],
  635.                                                               $attrs);
  636.                         } else {
  637.                             // WSDL fixups to the SOAP value.
  638.                         }
  639.                     }
  640.                 }
  641.                 $params =& $nparams;
  642.                 unset($nparams);
  643.             }
  644.         } else {
  645.             $this->_setSchemaVersion(SOAP_XML_SCHEMA_VERSION);
  646.         }
  647.  
  648.         // Serialize the message.
  649.         $this->_section5 = (!isset($this->_options['use']) ||
  650.                             $this->_options['use'] != 'literal');
  651.  
  652.         if (!isset($this->_options['style']) ||
  653.             $this->_options['style'] == 'rpc') {
  654.             $this->_options['style'] = 'rpc';
  655.             $this->docparams = true;
  656.             $mqname =& new QName($method, $namespace);
  657.             $methodValue =& new SOAP_Value($mqname->fqn(), 'Struct', $params);
  658.             $soap_msg = $this->makeEnvelope($methodValue,
  659.                                             $this->headersOut,
  660.                                             $this->_encoding,
  661.                                             $this->_options);
  662.         } else {
  663.             if (!$params) {
  664.                 $mqname =& new QName($method, $namespace);
  665.                 $mynull = null;
  666.                 $params =& new SOAP_Value($mqname->fqn(), 'Struct', $mynull);
  667.             } elseif ($this->_options['input'] == 'parse') {
  668.                 if (is_array($params)) {
  669.                     $nparams = array();
  670.                     $keys = array_keys($params);
  671.                     foreach ($keys as $k) {
  672.                         if (gettype($params[$k]) != 'object') {
  673.                             $nparams[] =& new SOAP_Value($k,
  674.                                                          false,
  675.                                                          $params[$k]);
  676.                         } else {
  677.                             $nparams[] =& $params[$k];
  678.                         }
  679.                     }
  680.                     $params =& $nparams;
  681.                 }
  682.                 if ($this->_options['parameters']) {
  683.                     $mqname =& new QName($method, $namespace);
  684.                     $params =& new SOAP_Value($mqname->fqn(),
  685.                                               'Struct',
  686.                                               $params);
  687.                 }
  688.             }
  689.             $soap_msg = $this->makeEnvelope($params,
  690.                                             $this->headersOut,
  691.                                             $this->_encoding,
  692.                                             $this->_options);
  693.         }
  694.         unset($this->headersOut);
  695.  
  696.         if (PEAR::isError($soap_msg)) {
  697.             $fault =& $this->_raiseSoapFault($soap_msg);
  698.             return $fault;
  699.         }
  700.  
  701.         // Handle MIME or DIME encoding.
  702.         // TODO: DIME encoding should move to the transport, do it here for
  703.         // now and for ease of getting it done.
  704.         if (count($this->_attachments)) {
  705.             if ((isset($this->_options['attachments']) &&
  706.                  $this->_options['attachments'] == 'Mime') ||
  707.                 isset($this->_options['Mime'])) {
  708.                 $soap_msg =& $this->_makeMimeMessage($soap_msg,
  709.                                                      $this->_encoding);
  710.             } else {
  711.                 // default is dime
  712.                 $soap_msg =& $this->_makeDIMEMessage($soap_msg,
  713.                                                      $this->_encoding);
  714.                 $this->_options['headers']['Content-Type'] = 'application/dime';
  715.             }
  716.             if (PEAR::isError($soap_msg)) {
  717.                 $fault =& $this->_raiseSoapFault($soap_msg);
  718.                 return $fault;
  719.             }
  720.         }
  721.  
  722.         // Instantiate client.
  723.         if (is_array($soap_msg)) {
  724.             $soap_data =& $soap_msg['body'];
  725.             if (count($soap_msg['headers'])) {
  726.                 if (isset($this->_options['headers'])) {
  727.                     $this->_options['headers'] = array_merge($this->_options['headers'], $soap_msg['headers']);
  728.                 } else {
  729.                     $this->_options['headers'] = $soap_msg['headers'];
  730.                 }
  731.             }
  732.         } else {
  733.             $soap_data =& $soap_msg;
  734.         }
  735.  
  736.         return $soap_data;
  737.     }
  738.  
  739.     /**
  740.      * @deprecated Use parseResponse().
  741.      */
  742.     function &__parse(&$response, $encoding, &$attachments)
  743.     {
  744.         return $this->parseResponse($response, $encoding, $attachments);
  745.     }
  746.  
  747.     /**
  748.      * Parses a SOAP response.
  749.      *
  750.      * @see SOAP_Parser::
  751.      *
  752.      * @param string $response    XML content of SOAP response.
  753.      * @param string $encoding    Character set encoding, defaults to 'UTF-8'.
  754.      * @param array $attachments  List of attachments.
  755.      */
  756.     function &parseResponse(&$response, $encoding, &$attachments)
  757.     {
  758.         // Parse the response.
  759.         $response =& new SOAP_Parser($response, $encoding, $attachments);
  760.         if ($response->fault) {
  761.             $fault =& $this->_raiseSoapFault($response->fault);
  762.             return $fault;
  763.         }
  764.  
  765.         // Return array of parameters.
  766.         $return =& $response->getResponse();
  767.         $headers =& $response->getHeaders();
  768.         if ($headers) {
  769.             $this->headersIn =& $this->_decodeResponse($headers, false);
  770.         }
  771.  
  772.         $decoded = &$this->_decodeResponse($return);
  773.         return $decoded;
  774.     }
  775.  
  776.     function &_decodeResponse(&$response, $shift = true)
  777.     {
  778.         if (!$response) {
  779.             $decoded = null;
  780.             return $decoded;
  781.         }
  782.  
  783.         // Check for valid response.
  784.         if (PEAR::isError($response)) {
  785.             $fault =& $this->_raiseSoapFault($response);
  786.             return $fault;
  787.         } elseif (!is_a($response, 'soap_value')) {
  788.             $fault =& $this->_raiseSoapFault("Didn't get SOAP_Value object back from client");
  789.             return $fault;
  790.         }
  791.  
  792.         // Decode to native php datatype.
  793.         $returnArray =& $this->_decode($response);
  794.  
  795.         // Fault?
  796.         if (PEAR::isError($returnArray)) {
  797.             $fault =& $this->_raiseSoapFault($returnArray);
  798.             return $fault;
  799.         }
  800.  
  801.         if (is_object($returnArray) &&
  802.             strcasecmp(get_class($returnArray), 'stdClass') == 0) {
  803.             $returnArray = get_object_vars($returnArray);
  804.         }
  805.         if (is_array($returnArray)) {
  806.             if (isset($returnArray['faultcode']) ||
  807.                 isset($returnArray['SOAP-ENV:faultcode'])) {
  808.                 $faultcode = $faultstring = $faultdetail = $faultactor = '';
  809.                 foreach ($returnArray as $k => $v) {
  810.                     if (stristr($k, 'faultcode')) $faultcode = $v;
  811.                     if (stristr($k, 'faultstring')) $faultstring = $v;
  812.                     if (stristr($k, 'detail')) $faultdetail = $v;
  813.                     if (stristr($k, 'faultactor')) $faultactor = $v;
  814.                 }
  815.                 $fault =& $this->_raiseSoapFault($faultstring, $faultdetail, $faultactor, $faultcode);
  816.                 return $fault;
  817.             }
  818.             // Return array of return values.
  819.             if ($shift && count($returnArray) == 1) {
  820.                 $decoded = array_shift($returnArray);
  821.                 return $decoded;
  822.             }
  823.             return $returnArray;
  824.         }
  825.         return $returnArray;
  826.     }
  827.  
  828.     /**
  829.      * @deprecated Use getWire().
  830.      */
  831.     function __get_wire()
  832.     {
  833.         return $this->getWire();
  834.     }
  835.  
  836.     /**
  837.      * Returns the outgoing and incoming traffic on the transport level.
  838.      *
  839.      * Tracing has to be enabled.
  840.      *
  841.      * @see setTrace()
  842.      *
  843.      * @return string  The complete traffic between the client and the server.
  844.      */
  845.     function getWire()
  846.     {
  847.         if ($this->_options['trace'] &&
  848.             ($this->_last_request || $this->_last_response)) {
  849.             return "OUTGOING:\n\n" .
  850.                 $this->_last_request .
  851.                 "\n\nINCOMING\n\n" .
  852.                 preg_replace("/></",">\r\n<", $this->_last_response);
  853.         }
  854.  
  855.         return null;
  856.     }
  857.  
  858. }
  859.