Spaces:
Sleeping
Sleeping
| /** | |
| * This file loads all required libraries, defines constants used across the | |
| * SOAP package, and defines the base classes that most other classes of this | |
| * package extend. | |
| * | |
| * PHP versions 4 and 5 | |
| * | |
| * LICENSE: This source file is subject to version 2.02 of the PHP license, | |
| * that is bundled with this package in the file LICENSE, and is available at | |
| * through the world-wide-web at http://www.php.net/license/2_02.txt. If you | |
| * did not receive a copy of the PHP license and are unable to obtain it | |
| * through the world-wide-web, please send a note to license@php.net so we can | |
| * mail you a copy immediately. | |
| * | |
| * @category Web Services | |
| * @package SOAP | |
| * @author Dietrich Ayala <dietrich@ganx4.com> Original Author | |
| * @author Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more | |
| * @author Chuck Hagenbuch <chuck@horde.org> Maintenance | |
| * @author Jan Schneider <jan@horde.org> Maintenance | |
| * @copyright 2003-2007 The PHP Group | |
| * @license http://www.php.net/license/2_02.txt PHP License 2.02 | |
| * @link http://pear.php.net/package/SOAP | |
| */ | |
| define('MAIL_MIMEPART_CRLF', "\r\n"); | |
| require_once 'PEAR.php'; | |
| if (!defined('INF')) { | |
| define('INF', 1.8e307); | |
| } | |
| if (!defined('NAN')) { | |
| define('NAN', 0.0); | |
| } | |
| define('SOAP_LIBRARY_VERSION', '0.11.0'); | |
| define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.11.0-beta'); | |
| // Set schema version. | |
| define('SOAP_XML_SCHEMA_VERSION', 'http://www.w3.org/2001/XMLSchema'); | |
| define('SOAP_XML_SCHEMA_INSTANCE', 'http://www.w3.org/2001/XMLSchema-instance'); | |
| define('SOAP_XML_SCHEMA_1999', 'http://www.w3.org/1999/XMLSchema'); | |
| define('SOAP_SCHEMA', 'http://schemas.xmlsoap.org/wsdl/soap/'); | |
| define('SOAP_SCHEMA_ENCODING', 'http://schemas.xmlsoap.org/soap/encoding/'); | |
| define('SOAP_ENVELOP', 'http://schemas.xmlsoap.org/soap/envelope/'); | |
| define('SCHEMA_DISCO', 'http://schemas.xmlsoap.org/disco/'); | |
| define('SCHEMA_DISCO_SCL', 'http://schemas.xmlsoap.org/disco/scl/'); | |
| define('SCHEMA_SOAP', 'http://schemas.xmlsoap.org/wsdl/soap/'); | |
| define('SCHEMA_SOAP12', 'http://schemas.xmlsoap.org/wsdl/soap12/'); | |
| define('SCHEMA_SOAP_HTTP', 'http://schemas.xmlsoap.org/soap/http'); | |
| define('SCHEMA_WSDL_HTTP', 'http://schemas.xmlsoap.org/wsdl/http/'); | |
| define('SCHEMA_MIME', 'http://schemas.xmlsoap.org/wsdl/mime/'); | |
| define('SCHEMA_WSDL', 'http://schemas.xmlsoap.org/wsdl/'); | |
| define('SCHEMA_DIME', 'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/'); | |
| define('SCHEMA_CONTENT', 'http://schemas.xmlsoap.org/ws/2002/04/content-type/'); | |
| define('SCHEMA_REF', 'http://schemas.xmlsoap.org/ws/2002/04/reference/'); | |
| define('SOAP_DEFAULT_ENCODING', 'UTF-8'); | |
| class SOAP_Base_Object extends PEAR | |
| { | |
| /** | |
| * Supported encodings, limited by XML extension. | |
| * | |
| * @var array $_encodings | |
| */ | |
| var $_encodings = array('ISO-8859-1', 'US-ASCII', 'UTF-8'); | |
| /** | |
| * Fault code. | |
| * | |
| * @var string $_myfaultcode | |
| */ | |
| var $_myfaultcode = ''; | |
| /** | |
| * Recent PEAR_Error object. | |
| * | |
| * @var PEAR_Error $fault | |
| */ | |
| var $fault = null; | |
| /** | |
| * Constructor. | |
| * | |
| * @param string $faultcode Error code. | |
| */ | |
| function SOAP_Base_Object($faultcode = 'Client') | |
| { | |
| $this->_myfaultcode = $faultcode; | |
| parent::PEAR('SOAP_Fault'); | |
| } | |
| /** | |
| * Raises a SOAP error. | |
| * | |
| * Please refer to the SOAP definition for an impression of what a certain | |
| * parameter stands for. | |
| * | |
| * @param string|object $str Error message or object. | |
| * @param string $detail Detailed error message. | |
| * @param string $actorURI | |
| * @param mixed $code | |
| * @param mixed $mode | |
| * @param mixed $options | |
| * @param boolean $skipmsg | |
| */ | |
| function &_raiseSoapFault($str, $detail = '', $actorURI = '', $code = null, | |
| $mode = null, $options = null, $skipmsg = false) | |
| { | |
| // Pass through previous faults. | |
| $is_instance = isset($this) && is_a($this, 'SOAP_Base_Object'); | |
| if (is_object($str)) { | |
| $fault =& $str; | |
| } else { | |
| if (!$code) { | |
| $code = $is_instance ? $this->_myfaultcode : 'Client'; | |
| } | |
| require_once 'SOAP/Fault.php'; | |
| $fault = new SOAP_Fault($str, | |
| $code, | |
| $actorURI, | |
| $detail, | |
| $mode, | |
| $options); | |
| } | |
| if ($is_instance) { | |
| $this->fault =& $fault; | |
| } | |
| return $fault; | |
| } | |
| function _isfault() | |
| { | |
| return $this->fault != null; | |
| } | |
| function &_getfault() | |
| { | |
| return $this->fault; | |
| } | |
| } | |
| /** | |
| * Common base class of all SOAP classes. | |
| * | |
| * @access public | |
| * @package SOAP | |
| * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates | |
| */ | |
| class SOAP_Base extends SOAP_Base_Object | |
| { | |
| var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema', | |
| 'http://www.w3.org/1999/XMLSchema'); | |
| var $_XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; | |
| // load types into typemap array | |
| var $_typemap = array( | |
| 'http://www.w3.org/2001/XMLSchema' => array( | |
| 'string' => 'string', | |
| 'boolean' => 'boolean', | |
| 'float' => 'float', | |
| 'double' => 'float', | |
| 'decimal' => 'float', | |
| 'duration' => 'integer', | |
| 'dateTime' => 'string', | |
| 'time' => 'string', | |
| 'date' => 'string', | |
| 'gYearMonth' => 'integer', | |
| 'gYear' => 'integer', | |
| 'gMonthDay' => 'integer', | |
| 'gDay' => 'integer', | |
| 'gMonth' => 'integer', | |
| 'hexBinary' => 'string', | |
| 'base64Binary' => 'string', | |
| // derived datatypes | |
| 'normalizedString' => 'string', | |
| 'token' => 'string', | |
| 'language' => 'string', | |
| 'NMTOKEN' => 'string', | |
| 'NMTOKENS' => 'string', | |
| 'Name' => 'string', | |
| 'NCName' => 'string', | |
| 'ID' => 'string', | |
| 'IDREF' => 'string', | |
| 'IDREFS' => 'string', | |
| 'ENTITY' => 'string', | |
| 'ENTITIES' => 'string', | |
| 'integer' => 'integer', | |
| 'nonPositiveInteger' => 'integer', | |
| 'negativeInteger' => 'integer', | |
| // longs (64bit ints) are not supported cross-platform. | |
| 'long' => 'string', | |
| 'int' => 'integer', | |
| 'short' => 'integer', | |
| 'byte' => 'string', | |
| 'nonNegativeInteger' => 'integer', | |
| 'unsignedLong' => 'integer', | |
| 'unsignedInt' => 'integer', | |
| 'unsignedShort' => 'integer', | |
| 'unsignedByte' => 'integer', | |
| 'positiveInteger' => 'integer', | |
| 'anyType' => 'string', | |
| 'anyURI' => 'string', | |
| 'QName' => 'string' | |
| ), | |
| 'http://www.w3.org/1999/XMLSchema' => array( | |
| 'i4' => 'integer', | |
| 'int' => 'integer', | |
| 'boolean' => 'boolean', | |
| 'string' => 'string', | |
| 'double' => 'float', | |
| 'float' => 'float', | |
| 'dateTime' => 'string', | |
| 'timeInstant' => 'string', | |
| 'base64Binary' => 'string', | |
| 'base64' => 'string', | |
| 'ur-type' => 'string' | |
| ), | |
| 'http://schemas.xmlsoap.org/soap/encoding/' => array( | |
| 'base64' => 'string', | |
| 'array' => 'array', | |
| 'Array' => 'array', | |
| 'Struct' => 'array') | |
| ); | |
| /** | |
| * Default class name to use for decoded response objects. | |
| * | |
| * @var string $_defaultObjectClassname | |
| */ | |
| var $_defaultObjectClassname = 'stdClass'; | |
| /** | |
| * Hash with used namespaces. | |
| * | |
| * @array | |
| */ | |
| var $_namespaces; | |
| /** | |
| * The default namespace. | |
| * | |
| * @string | |
| */ | |
| var $_namespace; | |
| var $_xmlEntities = array('&' => '&', | |
| '<' => '<', | |
| '>' => '>', | |
| "'" => ''', | |
| '"' => '"'); | |
| var $_doconversion = false; | |
| var $_attachments = array(); | |
| var $_wsdl = null; | |
| /** | |
| * True if we use section 5 encoding, or false if this is literal. | |
| * | |
| * @var boolean $_section5 | |
| */ | |
| var $_section5 = true; | |
| // Handle type to class mapping. | |
| var $_auto_translation = false; | |
| var $_type_translation = array(); | |
| /** | |
| * Constructor. | |
| * | |
| * @param string $faultcode Error code. | |
| */ | |
| function SOAP_Base($faultcode = 'Client') | |
| { | |
| parent::SOAP_Base_Object($faultcode); | |
| $this->_resetNamespaces(); | |
| } | |
| /** | |
| * Sets the default namespace. | |
| * | |
| * @param string $namespace The default namespace. | |
| */ | |
| function setDefaultNamespace($namespace) | |
| { | |
| $this->_namespace = $namespace; | |
| } | |
| function _resetNamespaces() | |
| { | |
| $this->_namespaces = array( | |
| 'http://schemas.xmlsoap.org/soap/envelope/' => 'SOAP-ENV', | |
| 'http://www.w3.org/2001/XMLSchema' => 'xsd', | |
| 'http://www.w3.org/2001/XMLSchema-instance' => 'xsi', | |
| 'http://schemas.xmlsoap.org/soap/encoding/' => 'SOAP-ENC'); | |
| } | |
| /** | |
| * Sets the schema version used in the SOAP message. | |
| * | |
| * @access private | |
| * @see $_XMLSchema | |
| * | |
| * @param string $schemaVersion The schema version. | |
| */ | |
| function _setSchemaVersion($schemaVersion) | |
| { | |
| if (!in_array($schemaVersion, $this->_XMLSchema)) { | |
| return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion"); | |
| } | |
| $this->_XMLSchemaVersion = $schemaVersion; | |
| $tmpNS = array_flip($this->_namespaces); | |
| $tmpNS['xsd'] = $this->_XMLSchemaVersion; | |
| $tmpNS['xsi'] = $this->_XMLSchemaVersion . '-instance'; | |
| $this->_namespaces = array_flip($tmpNS); | |
| } | |
| function _getNamespacePrefix($ns) | |
| { | |
| if ($this->_namespace && $ns == $this->_namespace) { | |
| return ''; | |
| } | |
| if (isset($this->_namespaces[$ns])) { | |
| return $this->_namespaces[$ns]; | |
| } | |
| $prefix = 'ns' . count($this->_namespaces); | |
| $this->_namespaces[$ns] = $prefix; | |
| return $prefix; | |
| } | |
| function _getNamespaceForPrefix($prefix) | |
| { | |
| $flipped = array_flip($this->_namespaces); | |
| if (isset($flipped[$prefix])) { | |
| return $flipped[$prefix]; | |
| } | |
| return null; | |
| } | |
| function _isSoapValue(&$value) | |
| { | |
| return is_a($value, 'SOAP_Value'); | |
| } | |
| function _serializeValue(&$value, $name = '', $type = false, | |
| $elNamespace = null, $typeNamespace = null, | |
| $options = array(), $attributes = array(), | |
| $artype = '') | |
| { | |
| $namespaces = array(); | |
| $arrayType = $array_depth = $xmlout_value = null; | |
| $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = ''; | |
| $xmlout_type = $xmlns = $ptype = $array_type_ns = ''; | |
| if (!$name || is_numeric($name)) { | |
| $name = 'item'; | |
| } | |
| if ($this->_wsdl) { | |
| list($ptype, $arrayType, $array_type_ns, $array_depth) | |
| = $this->_wsdl->getSchemaType($type, $name, $typeNamespace); | |
| } | |
| if (!$arrayType) { | |
| $arrayType = $artype; | |
| } | |
| if (!$ptype) { | |
| $ptype = $this->_getType($value); | |
| } | |
| if (!$type) { | |
| $type = $ptype; | |
| } | |
| if (strcasecmp($ptype, 'Struct') == 0 || | |
| strcasecmp($type, 'Struct') == 0) { | |
| // Struct | |
| $vars = null; | |
| if (is_object($value)) { | |
| $vars = get_object_vars($value); | |
| } else { | |
| $vars = &$value; | |
| } | |
| if (is_array($vars)) { | |
| foreach (array_keys($vars) as $k) { | |
| // Hide private vars. | |
| if ($k[0] == '_') { | |
| continue; | |
| } | |
| if (is_object($vars[$k])) { | |
| if (is_a($vars[$k], 'SOAP_Value')) { | |
| $xmlout_value .= $vars[$k]->serialize($this); | |
| } else { | |
| // XXX get the members and serialize them instead | |
| // converting to an array is more overhead than we | |
| // should really do. | |
| $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k]), $k, false, $this->_section5 ? null : $elNamespace); | |
| } | |
| } else { | |
| $xmlout_value .= $this->_serializeValue($vars[$k], $k, false, $this->_section5 ? null : $elNamespace); | |
| } | |
| } | |
| } | |
| } elseif (strcasecmp($ptype, 'Array') == 0 || | |
| strcasecmp($type, 'Array') == 0) { | |
| // Array. | |
| $typeNamespace = SOAP_SCHEMA_ENCODING; | |
| $orig_type = $type; | |
| $type = 'Array'; | |
| $numtypes = 0; | |
| $value = (array)$value; | |
| // XXX this will be slow on larger arrays. Basically, it flattens | |
| // arrays to allow us to serialize multi-dimensional arrays. We | |
| // only do this if arrayType is set, which will typically only | |
| // happen if we are using WSDL | |
| if (isset($options['flatten']) || | |
| ($arrayType && | |
| (strchr($arrayType, ',') || strstr($arrayType, '][')))) { | |
| $numtypes = $this->_multiArrayType($value, $arrayType, | |
| $ar_size, $xmlout_value); | |
| } | |
| $array_type = $array_type_prefix = ''; | |
| if ($numtypes != 1) { | |
| $arrayTypeQName = new QName($arrayType); | |
| $arrayType = $arrayTypeQName->name; | |
| $array_types = array(); | |
| $array_val = null; | |
| // Serialize each array element. | |
| $ar_size = count($value); | |
| foreach ($value as $array_val) { | |
| if ($this->_isSoapValue($array_val)) { | |
| $array_type = $array_val->type; | |
| $array_types[$array_type] = 1; | |
| $array_type_ns = $array_val->type_namespace; | |
| $xmlout_value .= $array_val->serialize($this); | |
| } else { | |
| $array_type = $this->_getType($array_val); | |
| $array_types[$array_type] = 1; | |
| $xmlout_value .= $this->_serializeValue($array_val, 'item', $array_type, $this->_section5 ? null : $elNamespace); | |
| } | |
| } | |
| $xmlout_offset = ' SOAP-ENC:offset="[0]"'; | |
| if (!$arrayType) { | |
| $numtypes = count($array_types); | |
| if ($numtypes == 1) { | |
| $arrayType = $array_type; | |
| } | |
| // Using anyType is more interoperable. | |
| if ($array_type == 'Struct') { | |
| $array_type = ''; | |
| } elseif ($array_type == 'Array') { | |
| $arrayType = 'anyType'; | |
| $array_type_prefix = 'xsd'; | |
| } else { | |
| if (!$arrayType) { | |
| $arrayType = $array_type; | |
| } | |
| } | |
| } | |
| } | |
| if (!$arrayType || $numtypes > 1) { | |
| // Should reference what schema we're using. | |
| $arrayType = 'xsd:anyType'; | |
| } else { | |
| if ($array_type_ns) { | |
| $array_type_prefix = $this->_getNamespacePrefix($array_type_ns); | |
| } elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) { | |
| $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion]; | |
| } | |
| if ($array_type_prefix) { | |
| $arrayType = $array_type_prefix . ':' . $arrayType; | |
| } | |
| } | |
| $xmlout_arrayType = ' SOAP-ENC:arrayType="' . $arrayType; | |
| if ($array_depth != null) { | |
| for ($i = 0; $i < $array_depth; $i++) { | |
| $xmlout_arrayType .= '[]'; | |
| } | |
| } | |
| $xmlout_arrayType .= "[$ar_size]\""; | |
| } elseif ($this->_isSoapValue($value)) { | |
| $xmlout_value = $value->serialize($this); | |
| } elseif ($type == 'string') { | |
| $xmlout_value = htmlspecialchars($value); | |
| } elseif ($type == 'rawstring') { | |
| $xmlout_value =& $value; | |
| } elseif ($type == 'boolean') { | |
| $xmlout_value = $value ? 'true' : 'false'; | |
| } else { | |
| $xmlout_value =& $value; | |
| } | |
| // Add namespaces. | |
| if ($elNamespace) { | |
| $elPrefix = $this->_getNamespacePrefix($elNamespace); | |
| if ($elPrefix) { | |
| $xmlout_name = "$elPrefix:$name"; | |
| } else { | |
| $xmlout_name = $name; | |
| } | |
| } else { | |
| $xmlout_name = $name; | |
| } | |
| if ($typeNamespace) { | |
| $typePrefix = $this->_getNamespacePrefix($typeNamespace); | |
| if ($typePrefix) { | |
| $xmlout_type = "$typePrefix:$type"; | |
| } else { | |
| $xmlout_type = $type; | |
| } | |
| } elseif ($type && | |
| isset($this->_typemap[$this->_XMLSchemaVersion][$type])) { | |
| $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion]; | |
| if ($typePrefix) { | |
| $xmlout_type = "$typePrefix:$type"; | |
| } else { | |
| $xmlout_type = $type; | |
| } | |
| } | |
| // Handle additional attributes. | |
| $xml_attr = ''; | |
| if (count($attributes)) { | |
| foreach ($attributes as $k => $v) { | |
| $kqn = new QName($k); | |
| $vqn = new QName($v); | |
| $xml_attr .= ' ' . $kqn->fqn() . '="' . $vqn->fqn() . '"'; | |
| } | |
| } | |
| // Store the attachment for mime encoding. | |
| if (isset($options['attachment']) && | |
| !PEAR::isError($options['attachment'])) { | |
| $this->_attachments[] = $options['attachment']; | |
| } | |
| if ($this->_section5) { | |
| if ($xmlout_type) { | |
| $xmlout_type = " xsi:type=\"$xmlout_type\""; | |
| } | |
| if (is_null($xmlout_value)) { | |
| $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" . | |
| "$xml_attr xsi:nil=\"true\"/>"; | |
| } else { | |
| $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" . | |
| "$xmlout_offset$xml_attr>$xmlout_value</$xmlout_name>"; | |
| } | |
| } else { | |
| if (is_null($xmlout_value)) { | |
| $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>"; | |
| } else { | |
| $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" . | |
| $xmlout_value . "</$xmlout_name>"; | |
| } | |
| } | |
| return $xml; | |
| } | |
| /** | |
| * Converts a PHP type to a SOAP type. | |
| * | |
| * @access private | |
| * | |
| * @param string $value The value to inspect. | |
| * | |
| * @return string The value's SOAP type. | |
| */ | |
| function _getType(&$value) | |
| { | |
| $type = gettype($value); | |
| switch ($type) { | |
| case 'object': | |
| if (is_a($value, 'soap_value')) { | |
| $type = $value->type; | |
| } else { | |
| $type = 'Struct'; | |
| } | |
| break; | |
| case 'array': | |
| // Hashes are always handled as structs. | |
| if ($this->_isHash($value)) { | |
| $type = 'Struct'; | |
| } else { | |
| $ar_size = count($value); | |
| reset($value); | |
| $key1 = key($value); | |
| if ($ar_size > 0 && is_a($key1, 'SOAP_Value')) { | |
| // FIXME: for non-wsdl structs that are all the same type | |
| $key2 = key($value); | |
| if ($ar_size > 1 && | |
| $this->_isSoapValue($key1) && | |
| $this->_isSoapValue($key2) && | |
| $key1->name != $key2->name) { | |
| // This is a struct, not an array. | |
| $type = 'Struct'; | |
| } else { | |
| $type = 'Array'; | |
| } | |
| } else { | |
| $type = 'Array'; | |
| } | |
| } | |
| break; | |
| case 'integer': | |
| case 'long': | |
| $type = 'int'; | |
| break; | |
| case 'boolean': | |
| break; | |
| case 'double': | |
| // double is deprecated in PHP 4.2 and later. | |
| $type = 'float'; | |
| break; | |
| case 'null': | |
| $type = ''; | |
| break; | |
| case 'string': | |
| default: | |
| break; | |
| } | |
| return $type; | |
| } | |
| function _multiArrayType($value, &$type, &$size, &$xml) | |
| { | |
| if (is_array($value)) { | |
| // Seems we have a multi dimensional array, figure it out if we | |
| // do. | |
| for ($i = 0, $c = count($value); $i < $c; ++$i) { | |
| $this->_multiArrayType($value[$i], $type, $size, $xml); | |
| } | |
| $sz = count($value); | |
| if ($size) { | |
| $size = $sz . ',' . $size; | |
| } else { | |
| $size = $sz; | |
| } | |
| return 1; | |
| } elseif (is_object($value)) { | |
| $type = $value->type; | |
| $xml .= $value->serialize($this); | |
| } else { | |
| $type = $this->_getType($value); | |
| $xml .= $this->_serializeValue($value, 'item', $type); | |
| } | |
| $size = null; | |
| return 1; | |
| } | |
| /** | |
| * Returns whether a type is a base64 type. | |
| * | |
| * @param string $type A type name. | |
| * | |
| * @return boolean True if the type name is a base64 type. | |
| */ | |
| function _isBase64Type($type) | |
| { | |
| return $type == 'base64' || $type == 'base64Binary'; | |
| } | |
| /** | |
| * Returns whether an array is a hash. | |
| * | |
| * @param array $a An array to check. | |
| * | |
| * @return boolean True if the specified array is a hash. | |
| */ | |
| function _isHash(&$a) | |
| { | |
| // I really dislike having to loop through this in PHP code, really | |
| // large arrays will be slow. We need a C function to do this. | |
| $it = 0; | |
| foreach ($a as $k => $v) { | |
| // Checking the type is faster than regexp. | |
| if (!is_int($k)) { | |
| return true; | |
| } | |
| // If someone has a large hash they should really be defining the | |
| // type. | |
| if ($it++ > 10) { | |
| $this->_raiseSoapFault('Large associative array passed where a SOAP_Value was expected'); | |
| return false; | |
| } | |
| } | |
| return false; | |
| } | |
| function _un_htmlentities($string) | |
| { | |
| $trans_tbl = get_html_translation_table(HTML_ENTITIES); | |
| $trans_tbl = array_flip($trans_tbl); | |
| return strtr($string, $trans_tbl); | |
| } | |
| /** | |
| * Converts a SOAP_Value object into a StdClass PHP object | |
| */ | |
| function &_decode(&$soapval) | |
| { | |
| if (!$this->_isSoapValue($soapval)) { | |
| return $soapval; | |
| } elseif (is_array($soapval->value)) { | |
| if ($soapval->type != 'Array') { | |
| $classname = $this->_defaultObjectClassname; | |
| if (isset($this->_type_translation[$soapval->tqn->fqn()])) { | |
| // This will force an error in PHP if the class does not | |
| // exist. | |
| $classname = $this->_type_translation[$soapval->tqn->fqn()]; | |
| } elseif (isset($this->_type_translation[$soapval->type])) { | |
| // This will force an error in PHP if the class does not | |
| // exist. | |
| $classname = $this->_type_translation[$soapval->type]; | |
| } elseif ($this->_auto_translation) { | |
| if (class_exists($soapval->type)) { | |
| $classname = $soapval->type; | |
| } elseif ($this->_wsdl) { | |
| $t = $this->_wsdl->getComplexTypeNameForElement($soapval->name, $soapval->namespace); | |
| if ($t && class_exists($t)) { | |
| $classname = $t; | |
| } | |
| } | |
| } | |
| $return = new $classname; | |
| } else { | |
| $return = array(); | |
| } | |
| $counter = 1; | |
| $isstruct = !is_array($return); | |
| foreach ($soapval->value as $item) { | |
| if (is_object($return)) { | |
| if ($this->_wsdl) { | |
| // Get this child's WSDL information. | |
| // /$soapval->ns/$soapval->type/$item->ns/$item->name | |
| $child_type = $this->_wsdl->getComplexTypeChildType( | |
| $soapval->namespace, | |
| $soapval->name, | |
| $item->namespace, | |
| $item->name); | |
| if ($child_type) { | |
| $item->type = $child_type; | |
| } | |
| } | |
| if (!$isstruct || $item->type == 'Array') { | |
| if (isset($return->{$item->name}) && | |
| is_object($return->{$item->name})) { | |
| $return->{$item->name} =& $this->_decode($item); | |
| } elseif (isset($return->{$item->name}) && | |
| is_array($return->{$item->name})) { | |
| $return->{$item->name}[] = $this->_decode($item); | |
| } elseif (isset($return->{$item->name})) { | |
| $return->{$item->name} = array( | |
| $return->{$item->name}, | |
| $this->_decode($item) | |
| ); | |
| } elseif (is_array($return)) { | |
| $return[] =& $this->_decode($item); | |
| } else { | |
| $return->{$item->name} =& $this->_decode($item); | |
| } | |
| } elseif (isset($return->{$item->name})) { | |
| //$isstruct = false; | |
| if (count(get_object_vars($return)) == 1) { | |
| $d =& $this->_decode($item); | |
| $return = array($return->{$item->name}, $d); | |
| } else { | |
| $d =& $this->_decode($item); | |
| $return->{$item->name} = array($return->{$item->name}, $d); | |
| } | |
| } else { | |
| $return->{$item->name} =& $this->_decode($item); | |
| } | |
| // Set the attributes as members in the class. | |
| if (method_exists($return, '__set_attribute')) { | |
| foreach ($soapval->attributes as $key => $value) { | |
| call_user_func_array(array(&$return, | |
| '__set_attribute'), | |
| array($key, $value)); | |
| } | |
| } | |
| } else { | |
| if ($soapval->arrayType && $this->_isSoapValue($item)) { | |
| if ($this->_isBase64Type($item->type) && | |
| !$this->_isBase64Type($soapval->arrayType)) { | |
| // Decode the value if we're losing the base64 | |
| // type information. | |
| $item->value = base64_decode($item->value); | |
| } | |
| $item->type = $soapval->arrayType; | |
| } | |
| if (!$isstruct) { | |
| $return[] = $this->_decode($item); | |
| } elseif (isset($return[$item->name])) { | |
| $isstruct = false; | |
| $d =& $this->_decode($item); | |
| $return = array($return[$item->name], $d); | |
| } else { | |
| $return[$item->name] = $this->_decode($item); | |
| } | |
| } | |
| } | |
| return $return; | |
| } | |
| if ($soapval->type == 'boolean') { | |
| if ($soapval->value != '0' && | |
| strcasecmp($soapval->value, 'false') != 0) { | |
| $soapval->value = true; | |
| } else { | |
| $soapval->value = false; | |
| } | |
| } elseif ($soapval->type && | |
| isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) { | |
| // If we can, set variable type. | |
| settype($soapval->value, | |
| $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]); | |
| } | |
| return $soapval->value; | |
| } | |
| /** | |
| * Creates the SOAP envelope with the SOAP envelop data. | |
| * | |
| * @param mixed $method | |
| * @param array $headers | |
| * @param string $encoding | |
| * @param array $options | |
| * | |
| * @return string | |
| */ | |
| function makeEnvelope(&$method, &$headers, | |
| $encoding = SOAP_DEFAULT_ENCODING, | |
| $options = array()) | |
| { | |
| $smsg = $header_xml = $ns_string = ''; | |
| if ($headers) { | |
| $c = count($headers); | |
| for ($i = 0; $i < $c; $i++) { | |
| $header_xml .= $headers[$i]->serialize($this); | |
| } | |
| $header_xml = "<SOAP-ENV:Header>\r\n$header_xml\r\n</SOAP-ENV:Header>\r\n"; | |
| } | |
| if (!isset($options['input']) || $options['input'] == 'parse') { | |
| if (is_array($method)) { | |
| $c = count($method); | |
| for ($i = 0; $i < $c; $i++) { | |
| $smsg .= $method[$i]->serialize($this); | |
| } | |
| } else { | |
| $smsg = $method->serialize($this); | |
| } | |
| } else { | |
| $smsg = $method; | |
| } | |
| $body = "<SOAP-ENV:Body>\r\n" . $smsg . "\r\n</SOAP-ENV:Body>\r\n"; | |
| foreach ($this->_namespaces as $k => $v) { | |
| $ns_string .= " xmlns:$v=\"$k\"\r\n"; | |
| } | |
| if ($this->_namespace) { | |
| $ns_string .= " xmlns=\"{$this->_namespace}\"\r\n"; | |
| } | |
| /* If 'use' == 'literal', we do not put in the encodingStyle. This is | |
| * denoted by $this->_section5 being false. 'use' can be defined at a | |
| * more granular level than we are dealing with here, so this does not | |
| * work for all services. */ | |
| $xml = "<?xml version=\"1.0\" encoding=\"$encoding\"?>\r\n\r\n". | |
| "<SOAP-ENV:Envelope $ns_string". | |
| ($this->_section5 ? ' SOAP-ENV:encodingStyle="' . SOAP_SCHEMA_ENCODING . '"' : ''). | |
| ">\r\n". | |
| "$header_xml$body</SOAP-ENV:Envelope>\r\n"; | |
| return $xml; | |
| } | |
| function _makeMimeMessage($xml, $encoding = SOAP_DEFAULT_ENCODING) | |
| { | |
| if (!@include_once 'Mail/mimePart.php') { | |
| return $this->_raiseSoapFault('MIME messages are unsupported, the Mail_Mime package is not installed'); | |
| } | |
| // Encode any attachments. See http://www.w3.org/TR/SOAP-attachments | |
| // Now we have to mime encode the message. | |
| $params = array('content_type' => 'multipart/related; type="text/xml"'); | |
| $msg = new Mail_mimePart('', $params); | |
| // Add the xml part. | |
| $params['content_type'] = 'text/xml'; | |
| $params['charset'] = $encoding; | |
| $params['encoding'] = 'base64'; | |
| $msg->addSubPart($xml, $params); | |
| // Add the attachements | |
| for ($i = 0, $c = count($this->_attachments); $i < $c; ++$i) { | |
| $msg->addSubPart($this->_attachments[$i]['body'], | |
| $this->_attachments[$i]); | |
| } | |
| return $msg->encode(); | |
| } | |
| // TODO: this needs to be used from the Transport system. | |
| function _makeDIMEMessage($xml) | |
| { | |
| if (!@include_once 'Net/DIME.php') { | |
| return $this->_raiseSoapFault('DIME messages are unsupported, the Net_DIME package is not installed'); | |
| } | |
| // Encode any attachments. See | |
| // http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt | |
| // Now we have to DIME encode the message | |
| $dime = new Net_DIME_Message(); | |
| $msg = $dime->encodeData($xml, SOAP_ENVELOP, null, NET_DIME_TYPE_URI); | |
| // Add the attachments. | |
| $c = count($this->_attachments); | |
| for ($i = 0; $i < $c; $i++) { | |
| $msg .= $dime->encodeData($this->_attachments[$i]['body'], | |
| $this->_attachments[$i]['content_type'], | |
| $this->_attachments[$i]['cid'], | |
| NET_DIME_TYPE_MEDIA); | |
| } | |
| $msg .= $dime->endMessage(); | |
| return $msg; | |
| } | |
| function _decodeMimeMessage(&$data, &$headers, &$attachments) | |
| { | |
| if (!@include_once 'Mail/mimeDecode.php') { | |
| return $this->_raiseSoapFault('MIME messages are unsupported, the Mail_Mime package is not installed'); | |
| } | |
| $params['include_bodies'] = true; | |
| $params['decode_bodies'] = true; | |
| $params['decode_headers'] = true; | |
| // Lame thing to have to do for decoding. | |
| $decoder = new Mail_mimeDecode($data); | |
| $structure = $decoder->decode($params); | |
| if (isset($structure->body)) { | |
| $data = $structure->body; | |
| $headers = $structure->headers; | |
| return; | |
| } elseif (isset($structure->parts)) { | |
| $data = $structure->parts[0]->body; | |
| $headers = array_merge($structure->headers, | |
| $structure->parts[0]->headers); | |
| if (count($structure->parts) > 1) { | |
| $mime_parts = array_splice($structure->parts,1); | |
| // Prepare the parts for the SOAP parser. | |
| $c = count($mime_parts); | |
| for ($i = 0; $i < $c; $i++) { | |
| $p =& $mime_parts[$i]; | |
| if (isset($p->headers['content-location'])) { | |
| // TODO: modify location per SwA note section 3 | |
| // http://www.w3.org/TR/SOAP-attachments | |
| $attachments[$p->headers['content-location']] = $p->body; | |
| } else { | |
| $cid = 'cid:' . substr($p->headers['content-id'], 1, -1); | |
| $attachments[$cid] = $p->body; | |
| } | |
| } | |
| } | |
| return; | |
| } | |
| $this->_raiseSoapFault('Mime parsing error', '', '', 'Server'); | |
| } | |
| function _decodeDIMEMessage(&$data, &$headers, &$attachments) | |
| { | |
| if (!@include_once 'Net/DIME.php') { | |
| return $this->_raiseSoapFault('DIME messages are unsupported, the Net_DIME package is not installed'); | |
| } | |
| // This SHOULD be moved to the transport layer, e.g. PHP itself should | |
| // handle parsing DIME ;) | |
| $dime = new Net_DIME_Message(); | |
| $err = $dime->decodeData($data); | |
| if (PEAR::isError($err)) { | |
| $this->_raiseSoapFault('Failed to decode the DIME message!', '', '', 'Server'); | |
| return; | |
| } | |
| if (strcasecmp($dime->parts[0]['type'], SOAP_ENVELOP) != 0) { | |
| $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!', '', '', 'Server'); | |
| return; | |
| } | |
| $data = $dime->parts[0]['data']; | |
| // Fake it for now. | |
| $headers['content-type'] = 'text/xml'; | |
| $c = count($dime->parts); | |
| for ($i = 0; $i < $c; $i++) { | |
| $part =& $dime->parts[$i]; | |
| // We need to handle URI's better. | |
| $id = strncmp($part['id'], 'cid:', 4) | |
| ? 'cid:' . $part['id'] | |
| : $part['id']; | |
| $attachments[$id] = $part['data']; | |
| } | |
| } | |
| /** | |
| * @deprecated Use setTypeTranslation(). | |
| */ | |
| function __set_type_translation($type, $class = null) | |
| { | |
| $this->setTypeTranslation($type, $class); | |
| } | |
| /** | |
| * Explicitly sets the translation for a specific class. | |
| * | |
| * Auto translation works for all cases, but opens ANY class in the script | |
| * to be used as a data type, and may not be desireable. | |
| * | |
| * @param string $type A SOAP type. | |
| * @param string $class A PHP class name. | |
| */ | |
| function setTypeTranslation($type, $class = null) | |
| { | |
| $tq = new QName($type); | |
| if (!$class) { | |
| $class = $tq->name; | |
| } | |
| $this->_type_translation[$type]=$class; | |
| } | |
| } | |
| /** | |
| * Class used to handle QNAME values in XML. | |
| * | |
| * @access public | |
| * @package SOAP | |
| * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates | |
| */ | |
| class QName | |
| { | |
| var $name = ''; | |
| var $ns = ''; | |
| var $namespace=''; | |
| function QName($name, $namespace = '') | |
| { | |
| if ($name && $name[0] == '{') { | |
| preg_match('/\{(.*?)\}(.*)/', $name, $m); | |
| $this->name = $m[2]; | |
| $this->namespace = $m[1]; | |
| } elseif (substr_count($name, ':') == 1) { | |
| $s = explode(':', $name); | |
| $s = array_reverse($s); | |
| $this->name = $s[0]; | |
| $this->ns = $s[1]; | |
| $this->namespace = $namespace; | |
| } else { | |
| $this->name = $name; | |
| $this->namespace = $namespace; | |
| } | |
| // A little more magic than should be in a qname. | |
| $p = strpos($this->name, '['); | |
| if ($p) { | |
| // TODO: Need to re-examine this logic later. | |
| // Chop off []. | |
| $this->arraySize = explode(',', substr($this->name, $p + 1, -$p - 2)); | |
| $this->arrayInfo = substr($this->name, $p); | |
| $this->name = substr($this->name, 0, $p); | |
| } | |
| } | |
| function fqn() | |
| { | |
| if ($this->namespace) { | |
| return '{' . $this->namespace . '}' . $this->name; | |
| } elseif ($this->ns) { | |
| return $this->ns . ':' . $this->name; | |
| } | |
| return $this->name; | |
| } | |
| } | |