SOAP--Client
[ class tree: SOAP--Client ] [ index: SOAP--Client ] [ all elements ]

Source for file Client.php

Documentation is available at Client.php

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

Documentation generated on Mon, 11 Mar 2019 13:59:45 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.