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

Source for file Base.php

Documentation is available at Base.php

  1. <?php
  2. /**
  3.  * This file loads all required libraries, defines constants used across the
  4.  * SOAP package, and defines the base classes that most other classes of this
  5.  * package extend.
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: This source file is subject to version 2.02 of the PHP license,
  10.  * that is bundled with this package in the file LICENSE, and is available at
  11.  * through the world-wide-web at http://www.php.net/license/2_02.txt.  If you
  12.  * did not receive a copy of the PHP license and are unable to obtain it
  13.  * through the world-wide-web, please send a note to license@php.net so we can
  14.  * mail you a copy immediately.
  15.  *
  16.  * @category   Web Services
  17.  * @package    SOAP
  18.  * @author     Dietrich Ayala <dietrich@ganx4.com> Original Author
  19.  * @author     Shane Caraveo <Shane@Caraveo.com>   Port to PEAR and more
  20.  * @author     Chuck Hagenbuch <chuck@horde.org>   Maintenance
  21.  * @author     Jan Schneider <jan@horde.org>       Maintenance
  22.  * @copyright  2003-2007 The PHP Group
  23.  * @license    http://www.php.net/license/2_02.txt  PHP License 2.02
  24.  * @link       http://pear.php.net/package/SOAP
  25.  */
  26.  
  27. /** Define linebreak sequence for the Mail_Mime package. */
  28. define('MAIL_MIMEPART_CRLF'"\r\n");
  29.  
  30. require_once 'PEAR.php';
  31.  
  32. if (!defined('INF')) {
  33.     define('INF'1.8e307);
  34. }
  35. if (!defined('NAN')) {
  36.     define('NAN'0.0);
  37. }
  38.  
  39. define('SOAP_LIBRARY_VERSION''0.12.0');
  40. define('SOAP_LIBRARY_NAME',    'PEAR-SOAP 0.12.0-beta');
  41.  
  42. // Set schema version.
  43. define('SOAP_XML_SCHEMA_VERSION',  'http://www.w3.org/2001/XMLSchema');
  44. define('SOAP_XML_SCHEMA_INSTANCE''http://www.w3.org/2001/XMLSchema-instance');
  45. define('SOAP_XML_SCHEMA_1999',     'http://www.w3.org/1999/XMLSchema');
  46. define('SOAP_SCHEMA',              'http://schemas.xmlsoap.org/wsdl/soap/');
  47. define('SOAP_SCHEMA_ENCODING',     'http://schemas.xmlsoap.org/soap/encoding/');
  48. define('SOAP_ENVELOP',             'http://schemas.xmlsoap.org/soap/envelope/');
  49.  
  50. define('SCHEMA_DISCO',             'http://schemas.xmlsoap.org/disco/');
  51. define('SCHEMA_DISCO_SCL',         'http://schemas.xmlsoap.org/disco/scl/');
  52.  
  53. define('SCHEMA_SOAP',              'http://schemas.xmlsoap.org/wsdl/soap/');
  54. define('SCHEMA_SOAP12',            'http://schemas.xmlsoap.org/wsdl/soap12/');
  55. define('SCHEMA_SOAP_HTTP',         'http://schemas.xmlsoap.org/soap/http');
  56. define('SCHEMA_WSDL_HTTP',         'http://schemas.xmlsoap.org/wsdl/http/');
  57. define('SCHEMA_MIME',              'http://schemas.xmlsoap.org/wsdl/mime/');
  58. define('SCHEMA_WSDL',              'http://schemas.xmlsoap.org/wsdl/');
  59. define('SCHEMA_DIME',              'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/');
  60. define('SCHEMA_CONTENT',           'http://schemas.xmlsoap.org/ws/2002/04/content-type/');
  61. define('SCHEMA_REF',               'http://schemas.xmlsoap.org/ws/2002/04/reference/');
  62.  
  63. define('SOAP_DEFAULT_ENCODING',  'UTF-8');
  64.  
  65. /**
  66.  * @package SOAP
  67.  */
  68. class SOAP_Base_Object extends PEAR
  69. {
  70.  
  71.     /**
  72.      * Supported encodings, limited by XML extension.
  73.      *
  74.      * @var array $_encodings 
  75.      */
  76.     var $_encodings = array('ISO-8859-1''US-ASCII''UTF-8');
  77.  
  78.     /**
  79.      * Fault code.
  80.      *
  81.      * @var string $_myfaultcode 
  82.      */
  83.     var $_myfaultcode '';
  84.  
  85.     /**
  86.      * Recent PEAR_Error object.
  87.      *
  88.      * @var PEAR_Error $fault 
  89.      */
  90.     var $fault = null;
  91.  
  92.     /**
  93.      * Constructor.
  94.      *
  95.      * @param string $faultcode  Error code.
  96.      */
  97.     function SOAP_Base_Object($faultcode 'Client')
  98.     {
  99.         $this->_myfaultcode $faultcode;
  100.         parent::PEAR('SOAP_Fault');
  101.     }
  102.  
  103.     /**
  104.      * Raises a SOAP error.
  105.      *
  106.      * Please refer to the SOAP definition for an impression of what a certain
  107.      * parameter stands for.
  108.      *
  109.      * @param string|object $str  Error message or object.
  110.      * @param string $detail      Detailed error message.
  111.      * @param string $actorURI 
  112.      * @param mixed $code 
  113.      * @param mixed $mode 
  114.      * @param mixed $options 
  115.      * @param boolean $skipmsg 
  116.      */
  117.     function &_raiseSoapFault($str$detail ''$actorURI ''$code = null,
  118.                               $mode = null$options = null$skipmsg = false)
  119.     {
  120.         // Pass through previous faults.
  121.         $is_instance = isset($this&& is_a($this'SOAP_Base_Object');
  122.         if (is_object($str)) {
  123.             $fault $str;
  124.         else {
  125.             if (!$code{
  126.                 $code $is_instance $this->_myfaultcode 'Client';
  127.             }
  128.             require_once 'SOAP/Fault.php';
  129.             $fault = new SOAP_Fault($str$code$actorURI$detail$mode,
  130.                                     $options);
  131.         }
  132.         if ($is_instance{
  133.             $this->fault = $fault;
  134.         }
  135.  
  136.         return $fault;
  137.     }
  138.  
  139.     function _isfault()
  140.     {
  141.         return $this->fault != null;
  142.     }
  143.  
  144.     function &_getfault()
  145.     {
  146.         return $this->fault;
  147.     }
  148.  
  149. }
  150.  
  151. /**
  152.  * Common base class of all SOAP classes.
  153.  *
  154.  * @access   public
  155.  * @package  SOAP
  156.  * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  157.  */
  158. class SOAP_Base extends SOAP_Base_Object
  159. {
  160.     var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema',
  161.                             'http://www.w3.org/1999/XMLSchema');
  162.     var $_XMLSchemaVersion 'http://www.w3.org/2001/XMLSchema';
  163.  
  164.     // load types into typemap array
  165.     var $_typemap = array(
  166.         'http://www.w3.org/2001/XMLSchema' => array(
  167.             'string' => 'string',
  168.             'boolean' => 'boolean',
  169.             'float' => 'float',
  170.             'double' => 'float',
  171.             'decimal' => 'float',
  172.             'duration' => 'integer',
  173.             'dateTime' => 'string',
  174.             'time' => 'string',
  175.             'date' => 'string',
  176.             'gYearMonth' => 'integer',
  177.             'gYear' => 'integer',
  178.             'gMonthDay' => 'integer',
  179.             'gDay' => 'integer',
  180.             'gMonth' => 'integer',
  181.             'hexBinary' => 'string',
  182.             'base64Binary' => 'string',
  183.             // derived datatypes
  184.             'normalizedString' => 'string',
  185.             'token' => 'string',
  186.             'language' => 'string',
  187.             'NMTOKEN' => 'string',
  188.             'NMTOKENS' => 'string',
  189.             'Name' => 'string',
  190.             'NCName' => 'string',
  191.             'ID' => 'string',
  192.             'IDREF' => 'string',
  193.             'IDREFS' => 'string',
  194.             'ENTITY' => 'string',
  195.             'ENTITIES' => 'string',
  196.             'integer' => 'integer',
  197.             'nonPositiveInteger' => 'integer',
  198.             'negativeInteger' => 'integer',
  199.             // longs (64bit ints) are not supported cross-platform.
  200.             'long' => 'string',
  201.             'int' => 'integer',
  202.             'short' => 'integer',
  203.             'byte' => 'string',
  204.             'nonNegativeInteger' => 'integer',
  205.             'unsignedLong' => 'integer',
  206.             'unsignedInt' => 'integer',
  207.             'unsignedShort' => 'integer',
  208.             'unsignedByte' => 'integer',
  209.             'positiveInteger'  => 'integer',
  210.             'anyType' => 'string',
  211.             'anyURI' => 'string',
  212.             'QName' => 'string'
  213.         ),
  214.         'http://www.w3.org/1999/XMLSchema' => array(
  215.             'i4' => 'integer',
  216.             'int' => 'integer',
  217.             'boolean' => 'boolean',
  218.             'string' => 'string',
  219.             'double' => 'float',
  220.             'float' => 'float',
  221.             'dateTime' => 'string',
  222.             'timeInstant' => 'string',
  223.             'base64Binary' => 'string',
  224.             'base64' => 'string',
  225.             'ur-type' => 'string'
  226.         ),
  227.         'http://schemas.xmlsoap.org/soap/encoding/' => array(
  228.             'base64' => 'string',
  229.             'array' => 'array',
  230.             'Array' => 'array',
  231.             'Struct' => 'array')
  232.     );
  233.  
  234.     /**
  235.      * Default class name to use for decoded response objects.
  236.      *
  237.      * @var string $_defaultObjectClassname 
  238.      */
  239.     var $_defaultObjectClassname 'stdClass';
  240.  
  241.     /**
  242.      * Hash with used namespaces.
  243.      *
  244.      * @var array 
  245.      */
  246.     var $_namespaces;
  247.  
  248.     /**
  249.      * The default namespace.
  250.      *
  251.      * @var string 
  252.      */
  253.     var $_namespace;
  254.  
  255.     var $_xmlEntities = array('&' => '&amp;',
  256.                               '<' => '&lt;',
  257.                               '>' => '&gt;',
  258.                               "'" => '&apos;',
  259.                               '"' => '&quot;');
  260.  
  261.     var $_doconversion = false;
  262.  
  263.     var $_attachments = array();
  264.  
  265.     var $_wsdl = null;
  266.  
  267.     /**
  268.      * True if we use section 5 encoding, or false if this is literal.
  269.      *
  270.      * @var boolean $_section5 
  271.      */
  272.     var $_section5 = true;
  273.  
  274.     // Handle type to class mapping.
  275.     var $_auto_translation = false;
  276.     var $_type_translation = array();
  277.  
  278.     /**
  279.      * Constructor.
  280.      *
  281.      * @param string $faultcode  Error code.
  282.      */
  283.     function SOAP_Base($faultcode 'Client')
  284.     {
  285.         parent::SOAP_Base_Object($faultcode);
  286.         $this->_resetNamespaces();
  287.     }
  288.  
  289.     /**
  290.      * Sets the SOAP-ENV prefix and returns the current value.
  291.      *
  292.      * @access public
  293.      *
  294.      * @param string SOAP-ENV prefix
  295.      *
  296.      * @return string current SOAP-ENV prefix.
  297.      */
  298.     function SOAPENVPrefix($prefix = null)
  299.     {
  300.         static $_soapenv_prefix 'SOAP-ENV';
  301.         if (!is_null($prefix)) {
  302.             $_soapenv_prefix $prefix;
  303.         }
  304.         return $_soapenv_prefix;
  305.     }
  306.  
  307.     /**
  308.      * Sets the SOAP-ENC prefix and returns the current value.
  309.      *
  310.      * @access public
  311.      *
  312.      * @param string SOAP-ENC prefix
  313.      *
  314.      * @return string current SOAP-ENC prefix.
  315.      */
  316.     function SOAPENCPrefix($prefix = null)
  317.     {
  318.         static $_soapenv_prefix 'SOAP-ENC';
  319.         if (!is_null($prefix)) {
  320.             $_soapenv_prefix $prefix;
  321.         }
  322.         return $_soapenv_prefix;
  323.     }
  324.  
  325.     /**
  326.      * Sets the default namespace.
  327.      *
  328.      * @param string $namespace  The default namespace.
  329.      */
  330.     function setDefaultNamespace($namespace)
  331.     {
  332.         $this->_namespace $namespace;
  333.     }
  334.  
  335.     function _resetNamespaces()
  336.     {
  337.         $this->_namespaces = array(
  338.             'http://schemas.xmlsoap.org/soap/envelope/' => SOAP_BASE::SOAPENVPrefix(),
  339.             'http://www.w3.org/2001/XMLSchema' => 'xsd',
  340.             'http://www.w3.org/2001/XMLSchema-instance' => 'xsi',
  341.             'http://schemas.xmlsoap.org/soap/encoding/' => SOAP_BASE::SOAPENCPrefix());
  342.     }
  343.  
  344.     /**
  345.      * Sets the schema version used in the SOAP message.
  346.      *
  347.      * @access private
  348.      * @see $_XMLSchema
  349.      *
  350.      * @param string $schemaVersion  The schema version.
  351.      */
  352.     function _setSchemaVersion($schemaVersion)
  353.     {
  354.         if (!in_array($schemaVersion$this->_XMLSchema)) {
  355.             return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion");
  356.         }
  357.         $this->_XMLSchemaVersion $schemaVersion;
  358.         $tmpNS array_flip($this->_namespaces);
  359.         $tmpNS['xsd'$this->_XMLSchemaVersion;
  360.         $tmpNS['xsi'$this->_XMLSchemaVersion '-instance';
  361.         $this->_namespaces array_flip($tmpNS);
  362.     }
  363.  
  364.     function _getNamespacePrefix($ns)
  365.     {
  366.         if ($this->_namespace && $ns == $this->_namespace{
  367.             return '';
  368.         }
  369.         if (isset($this->_namespaces[$ns])) {
  370.             return $this->_namespaces[$ns];
  371.         }
  372.         $prefix 'ns' count($this->_namespaces);
  373.         $this->_namespaces[$ns$prefix;
  374.         return $prefix;
  375.     }
  376.  
  377.     function _getNamespaceForPrefix($prefix)
  378.     {
  379.         $flipped array_flip($this->_namespaces);
  380.         if (isset($flipped[$prefix])) {
  381.             return $flipped[$prefix];
  382.         }
  383.         return null;
  384.     }
  385.  
  386.     /**
  387.      * Serializes a value, array or object according to the rules set by this
  388.      * object.
  389.      *
  390.      * @see SOAP_Value
  391.      *
  392.      * @param mixed $value       The actual value.
  393.      * @param QName $name        The value name.
  394.      * @param QName $type        The value type.
  395.      * @param array $options     A list of encoding and serialization options.
  396.      * @param array $attributes  A hash of additional attributes.
  397.      * @param string $artype     The type of any array elements.
  398.      */
  399.     function _serializeValue($value$name = null$type = null,
  400.                              $options = array()$attributes = array(),
  401.                              $artype '')
  402.     {
  403.         $namespaces  = array();
  404.         $arrayType   $array_depth $xmlout_value = null;
  405.         $typePrefix  $elPrefix $xmlout_arrayType '';
  406.         $xmlout_type $xmlns $ptype $array_type_ns '';
  407.  
  408.         if (!$name->name || is_numeric($name->name)) {
  409.             $name->name = 'item';
  410.         }
  411.  
  412.         if ($this->_wsdl{
  413.             list($ptype$arrayType$array_type_ns$array_depth)
  414.                 = $this->_wsdl->getSchemaType($type$name);
  415.         }
  416.  
  417.         if (!$arrayType{
  418.             $arrayType $artype;
  419.         }
  420.         if (!$ptype{
  421.             $ptype $this->_getType($value);
  422.         }
  423.         if (!$type{
  424.             $type = new QName($ptype);
  425.         }
  426.  
  427.         if (strcasecmp($ptype'Struct'== 0 ||
  428.             strcasecmp($type->name'Struct'== 0{
  429.             // Struct
  430.             $vars is_object($valueget_object_vars($value$value;
  431.             if (is_array($vars)) {
  432.                 foreach (array_keys($varsas $k{
  433.                     // Hide private vars.
  434.                     if ($k[0== '_'{
  435.                         continue;
  436.                     }
  437.  
  438.                     if (is_object($vars[$k])) {
  439.                         if (is_a($vars[$k]'SOAP_Value')) {
  440.                             $xmlout_value .= $vars[$k]->serialize($this);
  441.                         else {
  442.                             // XXX get the members and serialize them instead
  443.                             // converting to an array is more overhead than we
  444.                             // should really do.
  445.                             $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k])new QName($k$this->_section5 ? null : $name->namepace)null$options);
  446.                         }
  447.                     else {
  448.                         $xmlout_value .= $this->_serializeValue($vars[$k]new QName($k$this->_section5 ? null : $name->namespace)false$options);
  449.                     }
  450.                 }
  451.             }
  452.         elseif (strcasecmp($ptype'Array'== 0 ||
  453.                   strcasecmp($type->name'Array'== 0{
  454.             // Array.
  455.             $type = new QName('Array'SOAP_SCHEMA_ENCODING);
  456.             $numtypes = 0;
  457.             $value = (array)$value;
  458.             // XXX this will be slow on larger arrays.  Basically, it flattens
  459.             // arrays to allow us to serialize multi-dimensional arrays.  We
  460.             // only do this if arrayType is set, which will typically only
  461.             // happen if we are using WSDL
  462.             if (isset($options['flatten']||
  463.                 ($arrayType &&
  464.                  (strchr($arrayType','|| strstr($arrayType'][')))) {
  465.                 $numtypes $this->_multiArrayType($value$arrayType,
  466.                                                    $ar_size$xmlout_value);
  467.             }
  468.  
  469.             $array_type $array_type_prefix '';
  470.             if ($numtypes != 1{
  471.                 $arrayTypeQName = new QName($arrayType);
  472.                 $arrayType $arrayTypeQName->name;
  473.                 $array_types = array();
  474.                 $array_val = null;
  475.  
  476.                 // Serialize each array element.
  477.                 $ar_size count($value);
  478.                 foreach ($value as $array_val{
  479.                     if (is_a($array_val'SOAP_Value')) {
  480.                         $array_type $array_val->type;
  481.                         $array_types[$array_type= 1;
  482.                         $array_type_ns $array_val->type_namespace;
  483.                         $xmlout_value .= $array_val->serialize($this);
  484.                     else {
  485.                         $array_type $this->_getType($array_val);
  486.                         $array_types[$array_type= 1;
  487.                         if (empty($options['keep_arrays_flat'])) {
  488.                             $xmlout_value .= $this->_serializeValue($array_valnew QName('item'$this->_section5 ? null : $name->namespace)new QName($array_type)$options);
  489.                         else {
  490.                             $xmlout_value .= $this->_serializeValue($array_val$namenew QName($array_type)$options$attributes);
  491.                         }
  492.                     }
  493.                 }
  494.  
  495.                 if (!$arrayType{
  496.                     $numtypes count($array_types);
  497.                     if ($numtypes == 1{
  498.                         $arrayType $array_type;
  499.                     }
  500.                     // Using anyType is more interoperable.
  501.                     if ($array_type == 'Struct'{
  502.                         $array_type '';
  503.                     elseif ($array_type == 'Array'{
  504.                         $arrayType 'anyType';
  505.                         $array_type_prefix 'xsd';
  506.                     else {
  507.                         if (!$arrayType{
  508.                             $arrayType $array_type;
  509.                         }
  510.                     }
  511.                 }
  512.             }
  513.             if (!$arrayType || $numtypes > 1{
  514.                 // Should reference what schema we're using.
  515.                 $arrayType 'xsd:anyType';
  516.             else {
  517.                 if ($array_type_ns{
  518.                     $array_type_prefix $this->_getNamespacePrefix($array_type_ns);
  519.                 elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) {
  520.                     $array_type_prefix $this->_namespaces[$this->_XMLSchemaVersion];
  521.                 elseif (isset($this->_typemap[SOAP_SCHEMA_ENCODING][$arrayType])) {
  522.                     $array_type_prefix = SOAP_BASE::SOAPENCPrefix();
  523.                 }
  524.                 if ($array_type_prefix{
  525.                     $arrayType $array_type_prefix ':' $arrayType;
  526.                 }
  527.             }
  528.  
  529.             $xmlout_arrayType ' ' . SOAP_BASE::SOAPENCPrefix()
  530.                 . ':arrayType="' $arrayType;
  531.             if ($array_depth != null{
  532.                 for ($i = 0; $i $array_depth$i++{
  533.                     $xmlout_arrayType .= '[]';
  534.                 }
  535.             }
  536.             $xmlout_arrayType .= "[$ar_size]\"";
  537.         elseif (is_a($value'SOAP_Value')) {
  538.             $xmlout_value $value->serialize($this);
  539.         elseif ($type->name == 'string'{
  540.             $xmlout_value htmlspecialchars($value);
  541.         elseif ($type->name == 'rawstring'{
  542.             $xmlout_value $value;
  543.         elseif ($type->name == 'boolean'{
  544.             $xmlout_value $value 'true' 'false';
  545.         else {
  546.             $xmlout_value $value;
  547.         }
  548.  
  549.         // Add namespaces.
  550.         if ($name->namespace{
  551.             $elPrefix $this->_getNamespacePrefix($name->namespace);
  552.             if ($elPrefix{
  553.                 $xmlout_name $elPrefix ':' $name->name;
  554.             else {
  555.                 $xmlout_name $name->name;
  556.             }
  557.         else {
  558.             $xmlout_name $name->name;
  559.         }
  560.  
  561.         if ($type->namespace{
  562.             $typePrefix = false;
  563.             if (empty($options['no_type_prefix'])) {
  564.                 $typePrefix $this->_getNamespacePrefix($type->namespace);
  565.             }
  566.             if ($typePrefix{
  567.                 $xmlout_type $typePrefix ':' $type->name;
  568.             else {
  569.                 $xmlout_type $type->name;
  570.             }
  571.         elseif ($type->name &&
  572.                   isset($this->_typemap[$this->_XMLSchemaVersion][$type->name])) {
  573.             $typePrefix $this->_namespaces[$this->_XMLSchemaVersion];
  574.             if ($typePrefix{
  575.                 $xmlout_type $typePrefix ':' $type->name;
  576.             else {
  577.                 $xmlout_type $type->name;
  578.             }
  579.         }
  580.  
  581.         // Handle additional attributes.
  582.         $xml_attr '';
  583.         if (count($attributes)) {
  584.             foreach ($attributes as $k => $v{
  585.                 $kqn = new QName($k);
  586.                 $vqn = new QName($v);
  587.                 $xml_attr .= ' ' $kqn->fqn('="' $vqn->fqn('"';
  588.             }
  589.         }
  590.  
  591.         // Store the attachment for mime encoding.
  592.         if (isset($options['attachment']&&
  593.             !PEAR::isError($options['attachment'])) {
  594.             $this->_attachments[$options['attachment'];
  595.         }
  596.  
  597.         if ($this->_section5{
  598.             if ($xmlout_type{
  599.                 $xmlout_type = " xsi:type=\"$xmlout_type\"";
  600.             }
  601.             if (is_null($xmlout_value)) {
  602.                 $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" .
  603.                     "$xml_attr xsi:nil=\"true\"/>";
  604.             else {
  605.                 $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" .
  606.                     "$xml_attr>$xmlout_value</$xmlout_name>";
  607.             }
  608.         elseif ($type->name == 'Array' && !empty($options['keep_arrays_flat'])) {
  609.             $xml $xmlout_value;
  610.         else {
  611.             if (is_null($xmlout_value)) {
  612.                 $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>";
  613.             else {
  614.                 $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" .
  615.                     $xmlout_value . "</$xmlout_name>";
  616.             }
  617.         }
  618.  
  619.         return $xml;
  620.     }
  621.  
  622.     /**
  623.      * Converts a PHP type to a SOAP type.
  624.      *
  625.      * @param mixed $value  The value to inspect.
  626.      *
  627.      * @return string  The value's SOAP type.
  628.      */
  629.     function _getType($value)
  630.     {
  631.         $type gettype($value);
  632.         switch ($type{
  633.         case 'object':
  634.             if (is_a($value'soap_value')) {
  635.                 $type $value->type;
  636.             else {
  637.                 $type 'Struct';
  638.             }
  639.             break;
  640.  
  641.         case 'array':
  642.             // Hashes are always handled as structs.
  643.             if ($this->_isHash($value)) {
  644.                 $type 'Struct';
  645.                 break;
  646.             }
  647.             if (count($value> 1{
  648.                 // For non-wsdl structs that are all the same type
  649.                 reset($value);
  650.                 $value1 next($value);
  651.                 $value2 next($value);
  652.                 if (is_a($value1'SOAP_Value'&&
  653.                     is_a($value2'SOAP_Value'&&
  654.                     $value1->name != $value2->name{
  655.                     // This is a struct, not an array.
  656.                     $type 'Struct';
  657.                     break;
  658.                 }
  659.             }
  660.             $type 'Array';
  661.             break;
  662.  
  663.         case 'integer':
  664.         case 'long':
  665.             $type 'int';
  666.             break;
  667.  
  668.         case 'boolean':
  669.             break;
  670.  
  671.         case 'double':
  672.             // double is deprecated in PHP 4.2 and later.
  673.             $type 'float';
  674.             break;
  675.  
  676.         case 'null':
  677.             $type '';
  678.             break;
  679.  
  680.         case 'string':
  681.         default:
  682.             break;
  683.         }
  684.  
  685.         return $type;
  686.     }
  687.  
  688.     function _multiArrayType($value&$type&$size&$xml)
  689.     {
  690.         if (is_array($value)) {
  691.             // Seems we have a multi dimensional array, figure it out if we
  692.             // do.
  693.             for ($i = 0$c count($value)$i $c; ++$i{
  694.                 $this->_multiArrayType($value[$i]$type$size$xml);
  695.             }
  696.  
  697.             $sz count($value);
  698.             if ($size{
  699.                 $size $sz ',' $size;
  700.             else {
  701.                 $size $sz;
  702.             }
  703.             return 1;
  704.         elseif (is_object($value)) {
  705.             $type $value->type;
  706.             $xml .= $value->serialize($this);
  707.         else {
  708.             $type $this->_getType($value);
  709.             $xml .= $this->_serializeValue($valuenew QName('item')new QName($type));
  710.         }
  711.         $size = null;
  712.  
  713.         return 1;
  714.     }
  715.  
  716.     /**
  717.      * Returns whether a type is a base64 type.
  718.      *
  719.      * @param string $type  A type name.
  720.      *
  721.      * @return boolean  True if the type name is a base64 type.
  722.      */
  723.     function _isBase64Type($type)
  724.     {
  725.         return $type == 'base64' || $type == 'base64Binary';
  726.     }
  727.  
  728.     /**
  729.      * Returns whether an array is a hash.
  730.      *
  731.      * @param array $a  An array to check.
  732.      *
  733.      * @return boolean  True if the specified array is a hash.
  734.      */
  735.     function _isHash($a)
  736.     {
  737.         foreach (array_keys($aas $k{
  738.             // Checking the type is faster than regexp.
  739.             if (!is_int($k)) {
  740.                 return true;
  741.             }
  742.         }
  743.         return false;
  744.     }
  745.  
  746.     function _un_htmlentities($string)
  747.     {
  748.         $trans_tbl get_html_translation_table(HTML_ENTITIES);
  749.         $trans_tbl array_flip($trans_tbl);
  750.         return strtr($string$trans_tbl);
  751.     }
  752.  
  753.     /**
  754.      * Converts a SOAP_Value object into a PHP value.
  755.      */
  756.     function _decode($soapval)
  757.     {
  758.         if (!is_a($soapval'SOAP_Value')) {
  759.             return $soapval;
  760.         }
  761.  
  762.         if (is_array($soapval->value)) {
  763.             $isstruct $soapval->type != 'Array';
  764.             if ($isstruct{
  765.                 $classname $this->_defaultObjectClassname;
  766.                 if (isset($this->_type_translation[$soapval->tqn->fqn()])) {
  767.                     // This will force an error in PHP if the class does not
  768.                     // exist.
  769.                     $classname $this->_type_translation[$soapval->tqn->fqn()];
  770.                 elseif (isset($this->_type_translation[$soapval->type])) {
  771.                     // This will force an error in PHP if the class does not
  772.                     // exist.
  773.                     $classname $this->_type_translation[$soapval->type];
  774.                 elseif ($this->_auto_translation{
  775.                     if (class_exists($soapval->type)) {
  776.                         $classname $soapval->type;
  777.                     elseif ($this->_wsdl{
  778.                         $t $this->_wsdl->getComplexTypeNameForElement($soapval->name$soapval->namespace);
  779.                         if ($t && class_exists($t)) {
  780.                             $classname $t;
  781.                         }
  782.                     }
  783.                 }
  784.                 $return = new $classname;
  785.             else {
  786.                 $return = array();
  787.             }
  788.  
  789.             foreach ($soapval->value as $item{
  790.                 if ($isstruct{
  791.                     if ($this->_wsdl{
  792.                         // Get this child's WSDL information.
  793.                         // /$soapval->ns/$soapval->type/$item->ns/$item->name
  794.                         $child_type $this->_wsdl->getComplexTypeChildType(
  795.                             $soapval->namespace,
  796.                             $soapval->name,
  797.                             $item->namespace,
  798.                             $item->name);
  799.                         if ($child_type{
  800.                             $item->type = $child_type;
  801.                         }
  802.                     }
  803.                     if ($item->type == 'Array'{
  804.                         if (isset($return->{$item->name}&&
  805.                             is_object($return->{$item->name})) {
  806.                             $return->{$item->name$this->_decode($item);
  807.                         elseif (isset($return->{$item->name}&&
  808.                                   is_array($return->{$item->name})) {
  809.                             $return->{$item->name}[$this->_decode($item);
  810.                         elseif (isset($return->{$item->name})) {
  811.                             $return->{$item->name= array(
  812.                                 $return->{$item->name},
  813.                                 $this->_decode($item)
  814.                             );
  815.                         elseif (is_array($return)) {
  816.                             $return[$this->_decode($item);
  817.                         else {
  818.                             $return->{$item->name$this->_decode($item);
  819.                         }
  820.                     elseif (isset($return->{$item->name})) {
  821.                         $d $this->_decode($item);
  822.                         if (count(get_object_vars($return)) == 1{
  823.                             $isstruct = false;
  824.                             $return = array($return->{$item->name}$d);
  825.                         else {
  826.                             $return->{$item->name= array($return->{$item->name}$d);
  827.                         }
  828.                     else {
  829.                         $return->{$item->name$this->_decode($item);
  830.                     }
  831.                     // Set the attributes as members in the class.
  832.                     if (method_exists($return'__set_attribute')) {
  833.                         foreach ($soapval->attributes as $key => $value{
  834.                             call_user_func_array(array(&$return,
  835.                                                        '__set_attribute'),
  836.                                                  array($key$value));
  837.                         }
  838.                     }
  839.                 else {
  840.                     if ($soapval->arrayType && is_a($item'SOAP_Value')) {
  841.                         if ($this->_isBase64Type($item->type&&
  842.                             !$this->_isBase64Type($soapval->arrayType)) {
  843.                             // Decode the value if we're losing the base64
  844.                             // type information.
  845.                             $item->value = base64_decode($item->value);
  846.                         }
  847.                         $item->type = $soapval->arrayType;
  848.                     }
  849.                     $return[$this->_decode($item);
  850.                 }
  851.             }
  852.  
  853.             return $return;
  854.         }
  855.  
  856.         if ($soapval->type == 'boolean'{
  857.             if ($soapval->value != '0' &&
  858.                 strcasecmp($soapval->value'false'!= 0{
  859.                 $soapval->value = true;
  860.             else {
  861.                 $soapval->value = false;
  862.             }
  863.         elseif ($soapval->type &&
  864.                   isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) {
  865.             // If we can, set variable type.
  866.             settype($soapval->value,
  867.                     $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]);
  868.         elseif ($soapval->type == 'Struct'{
  869.             $soapval->value = null;
  870.         }
  871.  
  872.         return $soapval->value;
  873.     }
  874.  
  875.     /**
  876.      * Creates the SOAP envelope with the SOAP envelop data.
  877.      *
  878.      * @param SOAP_Value $method  SOAP_Value instance with the method name as
  879.      *                             the name, and the method arguments as the
  880.      *                             value.
  881.      * @param array $headers      A list of additional SOAP_Header objects.
  882.      * @param string $encoding    The charset of the SOAP message.
  883.      * @param array $options      A list of encoding/serialization options.
  884.      *
  885.      * @return string  The complete SOAP message.
  886.      */
  887.     function makeEnvelope($method$headers$encoding = SOAP_DEFAULT_ENCODING,
  888.                           $options = array())
  889.     {
  890.         $smsg $header_xml $ns_string '';
  891.  
  892.         if ($headers{
  893.             for ($i = 0$c count($headers)$i $c$i++{
  894.                 $header_xml .= $headers[$i]->serialize($this);
  895.             }
  896.             $header_xml sprintf("<%s:Header>\r\n%s\r\n</%s:Header>\r\n",
  897.                                   SOAP_BASE::SOAPENVPrefix()$header_xml,
  898.                                   SOAP_BASE::SOAPENVPrefix());
  899.         }
  900.  
  901.         if (!isset($options['input']|| $options['input'== 'parse'{
  902.             if (is_array($method)) {
  903.                 for ($i = 0$c count($method)$i $c$i++{
  904.                     $smsg .= $method[$i]->serialize($this);
  905.                 }
  906.             else {
  907.                 $smsg $method->serialize($this);
  908.             }
  909.         else {
  910.             $smsg $method;
  911.         }
  912.         $body sprintf("<%s:Body>%s\r\n</%s:Body>\r\n",
  913.                         SOAP_BASE::SOAPENVPrefix()$smsg,
  914.                         SOAP_BASE::SOAPENVPrefix());
  915.  
  916.         foreach ($this->_namespaces as $k => $v{
  917.             $ns_string .= "\r\n " sprintf('xmlns:%s="%s"'$v$k);
  918.         }
  919.         if ($this->_namespace{
  920.             $ns_string .= "\r\n " sprintf('xmlns="%s"'$this->_namespace);
  921.         }
  922.  
  923.         /* If 'use' == 'literal', do not put in the encodingStyle.  This is
  924.          * denoted by $this->_section5 being false.  'use' can be defined at a
  925.          * more granular level than we are dealing with here, so this does not
  926.          * work for all services. */
  927.         $xml sprintf('<?xml version="1.0" encoding="%s"?>%s<%s:Envelope%s',
  928.                        $encoding"\r\n"SOAP_BASE::SOAPENVPrefix(),
  929.                        $ns_string);
  930.         if ($this->_section5{
  931.             $xml .= "\r\n " sprintf('%s:encodingStyle="%s"',
  932.                                       SOAP_BASE::SOAPENVPrefix(),
  933.                                       SOAP_SCHEMA_ENCODING);
  934.         }
  935.         $xml .= sprintf('>%s%s%s</%s:Envelope>' "\r\n",
  936.                         "\r\n"$header_xml$bodySOAP_BASE::SOAPENVPrefix());
  937.  
  938.         return $xml;
  939.     }
  940.  
  941.     function _makeMimeMessage($xml$encoding = SOAP_DEFAULT_ENCODING)
  942.     {
  943.         if (!@include_once 'Mail/mimePart.php'{
  944.             return $this->_raiseSoapFault('MIME messages are unsupported, the Mail_Mime package is not installed');
  945.         }
  946.  
  947.         // Encode any attachments.  See http://www.w3.org/TR/SOAP-attachments
  948.         // Now we have to mime encode the message.
  949.         $params = array('content_type' => 'multipart/related; type="text/xml"');
  950.         $msg = new Mail_mimePart(''$params);
  951.  
  952.         // Add the xml part.
  953.         $params['content_type''text/xml';
  954.         $params['charset'$encoding;
  955.         $msg->addSubPart($xml$params);
  956.  
  957.         // Add the attachements
  958.         for ($i = 0$c count($this->_attachments)$i $c; ++$i{
  959.             $msg->addSubPart($this->_attachments[$i]['body'],
  960.                              $this->_attachments[$i]);
  961.         }
  962.  
  963.         return $msg->encode();
  964.     }
  965.  
  966.     // TODO: this needs to be used from the Transport system.
  967.     function _makeDIMEMessage($xml)
  968.     {
  969.         if (!@include_once 'Net/DIME.php'{
  970.             return $this->_raiseSoapFault('DIME messages are unsupported, the Net_DIME package is not installed');
  971.         }
  972.  
  973.         // Encode any attachments.  See
  974.         // http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt
  975.         // Now we have to DIME encode the message
  976.         $dime = new Net_DIME_Message();
  977.         $msg $dime->encodeData($xmlSOAP_ENVELOPnullNET_DIME_TYPE_URI);
  978.  
  979.         // Add the attachments.
  980.         $c count($this->_attachments);
  981.         for ($i = 0; $i $c$i++{
  982.             $msg .= $dime->encodeData($this->_attachments[$i]['body'],
  983.                                       $this->_attachments[$i]['content_type'],
  984.                                       $this->_attachments[$i]['cid'],
  985.                                       NET_DIME_TYPE_MEDIA);
  986.         }
  987.         $msg .= $dime->endMessage();
  988.  
  989.         return $msg;
  990.     }
  991.  
  992.     function _decodeMimeMessage(&$data&$headers&$attachments)
  993.     {
  994.         if (!@include_once 'Mail/mimeDecode.php'{
  995.             return $this->_raiseSoapFault('MIME messages are unsupported, the Mail_Mime package is not installed');
  996.         }
  997.  
  998.         $params['include_bodies'= true;
  999.         $params['decode_bodies']  = true;
  1000.         $params['decode_headers'= true;
  1001.  
  1002.         // Lame thing to have to do for decoding.
  1003.         $decoder = new Mail_mimeDecode($data);
  1004.         $structure $decoder->decode($params);
  1005.  
  1006.         if (isset($structure->body)) {
  1007.             $data $structure->body;
  1008.             $headers $structure->headers;
  1009.  
  1010.             return;
  1011.         elseif (isset($structure->parts)) {
  1012.             $data $structure->parts[0]->body;
  1013.             $headers array_merge($structure->headers,
  1014.                                    $structure->parts[0]->headers);
  1015.             if (count($structure->parts<= 1{
  1016.                 return;
  1017.             }
  1018.  
  1019.             $mime_parts array_splice($structure->parts1);
  1020.             // Prepare the parts for the SOAP parser.
  1021.             for ($i = 0$c count($mime_parts)$i $c$i++{
  1022.                 $p $mime_parts[$i];
  1023.                 if (isset($p->headers['content-location'])) {
  1024.                     // TODO: modify location per SwA note section 3
  1025.                     // http://www.w3.org/TR/SOAP-attachments
  1026.                     $attachments[$p->headers['content-location']] $p->body;
  1027.                 else {
  1028.                     $cid 'cid:' substr($p->headers['content-id']1-1);
  1029.                     $attachments[$cid$p->body;
  1030.                 }
  1031.             }
  1032.  
  1033.             return;
  1034.         }
  1035.  
  1036.         $this->_raiseSoapFault('Mime parsing error''''''Server');
  1037.     }
  1038.  
  1039.     function _decodeDIMEMessage(&$data&$headers&$attachments)
  1040.     {
  1041.         if (!@include_once 'Net/DIME.php'{
  1042.             return $this->_raiseSoapFault('DIME messages are unsupported, the Net_DIME package is not installed');
  1043.         }
  1044.  
  1045.         // This SHOULD be moved to the transport layer, e.g. PHP itself should
  1046.         // handle parsing DIME ;)
  1047.         $dime = new Net_DIME_Message();
  1048.         $err $dime->decodeData($data);
  1049.         if (PEAR::isError($err)) {
  1050.             $this->_raiseSoapFault('Failed to decode the DIME message!''''''Server');
  1051.             return;
  1052.         }
  1053.         if (strcasecmp($dime->parts[0]['type']SOAP_ENVELOP!= 0{
  1054.             $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!''''''Server');
  1055.             return;
  1056.         }
  1057.  
  1058.         $data $dime->parts[0]['data'];
  1059.         // Fake it for now.
  1060.         $headers['content-type''text/xml';
  1061.         $c count($dime->parts);
  1062.         for ($i = 0; $i $c$i++{
  1063.             $part =$dime->parts[$i];
  1064.             // We need to handle URI's better.
  1065.             $id strncmp($part['id']'cid:'4)
  1066.                 ? 'cid:' $part['id']
  1067.                 : $part['id'];
  1068.             $attachments[$id$part['data'];
  1069.         }
  1070.     }
  1071.  
  1072.     /**
  1073.      * Explicitly sets the translation for a specific class.
  1074.      *
  1075.      * Auto translation works for all cases, but opens ANY class in the script
  1076.      * to be used as a data type, and may not be desireable.
  1077.      *
  1078.      * @param string $type   A SOAP type.
  1079.      * @param string $class  A PHP class name.
  1080.      */
  1081.     function setTypeTranslation($type$class = null)
  1082.     {
  1083.         $tq = new QName($type);
  1084.         if (!$class{
  1085.             $class $tq->name;
  1086.         }
  1087.         $this->_type_translation[$type]=$class;
  1088.     }
  1089.  
  1090. }
  1091.  
  1092. /**
  1093.  * Class used to handle QNAME values in XML.
  1094.  *
  1095.  * @package  SOAP
  1096.  * @author   Shane Caraveo <shane@php.net> Conversion to PEAR and updates
  1097.  */
  1098. class QName
  1099. {
  1100.     var $name = '';
  1101.     var $ns = '';
  1102.     var $namespace = '';
  1103.  
  1104.     function QName($name$namespace '')
  1105.     {
  1106.         if ($name && $name[0== '{'{
  1107.             preg_match('/\{(.*?)\}(.*)/'$name$m);
  1108.             $this->name = $m[2];
  1109.             $this->namespace = $m[1];
  1110.         elseif (substr_count($name':'== 1{
  1111.             $s explode(':'$name);
  1112.             $s array_reverse($s);
  1113.             $this->name = $s[0];
  1114.             $this->ns = $s[1];
  1115.             $this->namespace = $namespace;
  1116.         else {
  1117.             $this->name = $name;
  1118.             $this->namespace = $namespace;
  1119.         }
  1120.  
  1121.         // A little more magic than should be in a qname.
  1122.         $p strpos($this->name'[');
  1123.         if ($p{
  1124.             // TODO: Need to re-examine this logic later.
  1125.             // Chop off [].
  1126.             $this->arraySize explode(','substr($this->name$p + 1-$p - 2));
  1127.             $this->arrayInfo substr($this->name$p);
  1128.             $this->name = substr($this->name0$p);
  1129.         }
  1130.     }
  1131.  
  1132.     function fqn()
  1133.     {
  1134.         if ($this->namespace{
  1135.             return '{' $this->namespace . '}' $this->name;
  1136.         elseif ($this->ns{
  1137.             return $this->ns . ':' $this->name;
  1138.         }
  1139.         return $this->name;
  1140.     }
  1141.  
  1142. }

Documentation generated on Mon, 04 Aug 2008 20:00:11 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.