home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / SOAP / Base.php next >
Encoding:
PHP Script  |  2008-07-02  |  37.9 KB  |  1,117 lines

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