Source for file Base.php
Documentation is available at Base.php
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2003 The PHP Group |
// +----------------------------------------------------------------------+
// | 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. |
// +----------------------------------------------------------------------+
// | Authors: Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more |
// | Authors: Dietrich Ayala <dietrich@ganx4.com> Original Author |
// +----------------------------------------------------------------------+
// $Id: Base.php,v 1.49 2005/05/28 23:07:51 yunosh Exp $
* SOAP_OBJECT_STRUCT makes PEAR::SOAP use objects for SOAP structures rather
* than arrays. This has been done to provide a closer match to php-soap. If
* the old behaviour is needed, set to false. The old behaviour is
* @global bool $GLOBALS['SOAP_OBJECT_STRUCT']
$GLOBALS['SOAP_OBJECT_STRUCT'] = true;
* SOAP_RAW_CONVERT makes PEAR::SOAP attempt to determine what SOAP type a PHP
* string COULD be. This may result in slightly better interoperability when
* you are not using WSDL, and are being lazy and not using SOAP_Value to
* define types for your values.
* @global bool $GLOBALS['SOAP_RAW_CONVERT']
$GLOBALS['SOAP_RAW_CONVERT'] = false;
require_once 'SOAP/Type/dateTime.php';
require_once 'SOAP/Type/hexBinary.php';
$GLOBALS['SOAP_options'] = array ();
@include_once 'Mail/mimePart.php';
@include_once 'Mail/mimeDecode.php';
$GLOBALS['SOAP_options']['Mime'] = 1;
define('MAIL_MIMEPART_CRLF', "\r\n");
@include_once 'Net/DIME.php';
$GLOBALS['SOAP_options']['DIME'] = 1;
* Enable debugging information?
* @global bool $GLOBALS['SOAP_DEBUG']
$GLOBALS['SOAP_DEBUG'] = false;
die ("requires PHP 4.1 or higher\n");
define('SOAP_LIBRARY_VERSION', '0.8.0RC4');
define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.8.0RC4-devel');
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_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');
function is_a(&$object, $class_name)
/* PHP5 doesn't define this? */
function __constructor () {}
class SOAP_Base_Object extends PEAR
* Store debugging information in $_debug_data?
* @see $debug_data, SOAP_Base
* @var boolean $_debug_flag
var $_debug_flag = false;
* String containing debugging information if $_debug_flag is true.
* @see $debug_flag, SOAP_Base
* @var string $_debug_data
* Supported encodings, limited by XML extension.
var $_encodings = array ('ISO-8859-1', 'US-ASCII', 'UTF-8');
* @var string $_myfaultcode
* Recent PEAR_Error object.
* @see $debug_data, _debug()
* @param string $faultcode Error code.
function SOAP_Base_Object ($faultcode = 'Client')
$this->_myfaultcode = $faultcode;
$this->_debug_flag = $GLOBALS['SOAP_DEBUG'];
parent ::PEAR ('SOAP_Fault');
* Please refer to the SOAP definition for an impression of what a certain
* Use $debug_flag to store errors to the member variable $debug_data
* @see $debug_flag, $debug_data, SOAP_Fault
* @param string|object $str Error message or object.
* @param string $detail Detailed error message.
* @param string $actorURI
* @param boolean $skipmsg
function &_raiseSoapFault ($str, $detail = '', $actorURI = '', $code = null ,
$mode = null , $options = null , $skipmsg = false )
// Pass through previous faults.
$is_instance = isset ($this);
$code = $is_instance ? $this->_myfaultcode : 'Client';
return $this->fault != null;
* Adds a string to the debug data.
* @param string $string Debugging message.
if ($this->_debug_flag) {
$this->_debug_data .= get_class($this) . ': ' .
* Common base class of all SOAP classes.
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
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
'http://www.w3.org/2001/XMLSchema' => array (
'gYearMonth' => 'integer',
'gMonthDay' => 'integer',
'base64Binary' => 'string',
'normalizedString' => 'string',
'nonPositiveInteger' => 'integer',
'negativeInteger' => 'integer',
'nonNegativeInteger' => 'integer',
'unsignedLong' => 'integer',
'unsignedInt' => 'integer',
'unsignedShort' => 'integer',
'unsignedByte' => 'integer',
'positiveInteger' => 'integer',
'http://www.w3.org/1999/XMLSchema' => array (
'timeInstant' => 'string',
'base64Binary' => 'string',
'http://schemas.xmlsoap.org/soap/encoding/' => array (
* Default class name to use for decoded response objects.
* @var string $_defaultObjectClassname
var $_defaultObjectClassname = 'stdClass';
// Load namespace URIs into an array of URI => prefix.
var $_xmlEntities = array ('&' => '&',
var $_doconversion = false;
var $__attachments = array ();
* True if we use section 5 encoding, or false if this is literal.
* @var boolean $_section5
// Handle type to class mapping.
var $_auto_translation = false;
var $_type_translation = array ();
* Holds references to all elements that have been serialized already.
* @var array $_serialized
var $_serialized = array ();
* @see $debug_data, _debug()
* @param string $faultcode Error code.
$this->_resetNamespaces ();
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.
* @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['xsd'] = $this->_XMLSchemaVersion;
$tmpNS['xsi'] = $this->_XMLSchemaVersion . '-instance';
function _getNamespacePrefix ($ns)
if ($this->_namespace && $ns == $this->_namespace) {
if (isset ($this->_namespaces[$ns])) {
return $this->_namespaces[$ns];
$prefix = 'ns' . count($this->_namespaces);
$this->_namespaces[$ns] = $prefix;
function _getNamespaceForPrefix ($prefix)
if (isset ($flipped[$prefix])) {
return $flipped[$prefix];
function _isSoapValue (&$value)
return is_a($value, 'SOAP_Value');
function _serializeValue (&$value, $name = '', $type = false ,
$elNamespace = null , $typeNamespace = null ,
$options = array (), $attributes = array (),
$arrayType = $array_depth = $xmlout_value = null;
$typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = '';
$xmlout_type = $xmlns = $ptype = $array_type_ns = '';
list ($ptype, $arrayType, $array_type_ns, $array_depth)
= $this->_wsdl->getSchemaType ($type, $name, $typeNamespace);
$ptype = $this->_getType ($value);
if ($k[0 ] == '_') continue;
if (is_a($vars[$k], 'SOAP_Value')) {
$xmlout_value .= $vars[$k]->serialize ($this);
// XXX get the members and serialize them instead
// converting to an array is more overhead than we
$xmlout_value .= $this->_serializeValue (get_object_vars($vars[$k]), $k, false , $this->_section5 ? null : $elNamespace);
$xmlout_value .= $this->_serializeValue ($vars[$k], $k, false , $this->_section5 ? null : $elNamespace);
// 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']) ||
$numtypes = $this->_multiArrayType ($value, $arrayType,
$ar_size, $xmlout_value);
$array_type = $array_type_prefix = '';
$arrayTypeQName = & new QName($arrayType);
$arrayType = $arrayTypeQName->name;
// Protect against recursive arrays.
$count_serialized = count($this->_serialized);
for ($i = 0; $i < $count_serialized; $i++ ) {
if ($this->_serialized[$i] === $value) {
$this->_serialized[count($this->_serialized)] = & $value;
// 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 .= $this->_serializeValue ($array_val, $array_val->name , $array_type, $array_type_ns);
$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]"';
$numtypes = count($array_types);
$arrayType = $array_type;
// Using anyType is more interoperable.
if ($array_type == 'Struct') {
} elseif ($array_type == 'Array') {
$array_type_prefix = 'xsd';
$arrayType = $array_type;
if (!$arrayType || $numtypes > 1 ) {
// Should reference what schema we're using.
$arrayType = 'xsd:anyType';
$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') {
} elseif ($type == 'rawstring') {
} elseif ($type == 'boolean') {
$xmlout_value = $value ? 'true' : 'false';
$elPrefix = $this->_getNamespacePrefix ($elNamespace);
$xmlout_name = " $elPrefix:$name";
$typePrefix = $this->_getNamespacePrefix ($typeNamespace);
$xmlout_type = " $typePrefix:$type";
isset ($this->_typemap[$this->_XMLSchemaVersion][$type])) {
$typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
$xmlout_type = " $typePrefix:$type";
// Handle additional attributes.
if (count($attributes)) {
foreach ($attributes as $k => $v) {
$xml_attr .= ' ' . $kqn->fqn () . '="' . $vqn->fqn () . '"';
// Store the attachment for mime encoding.
if (isset ($options['attachment'])) {
$this->__attachments[] = $options['attachment'];
$xmlout_type = " xsi:type=\"$xmlout_type\"";
$xml = " \r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" .
" $xml_attr xsi:nil=\"true\"/>";
$xml = " \r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" .
" $xmlout_offset$xml_attr>$xmlout_value</$xmlout_name>";
$xml = " \r\n<$xmlout_name$xmlns$xml_attr/>";
$xml = " \r\n<$xmlout_name$xmlns$xml_attr>" .
$xmlout_value . " </$xmlout_name>";
* Converts a PHP type to a SOAP type.
* @param string $value The value to inspect.
* @return string The value's SOAP type.
function _getType (&$value)
global $SOAP_OBJECT_STRUCT, $SOAP_RAW_CONVERT;
if (is_a($value, 'soap_value')) {
// Hashes are always handled as structs.
if ($this->_isHash ($value)) {
$ar_size = count($value);
if ($ar_size > 0 && is_a($key1, 'SOAP_Value')) {
// FIXME: for non-wsdl structs that are all the same type
$this->_isSoapValue ($key1) &&
$this->_isSoapValue ($key2) &&
$key1->name != $key2->name ) {
// This is a struct, not an array.
// double is deprecated in PHP 4.2 and later.
if (SOAP_Type_hexBinary ::is_hexbin ($value)) {
if ($this->_isBase64 ($value)) {
$dt = & new SOAP_Type_dateTime ($value);
if ($dt->toUnixtime () != -1 ) {
function _multiArrayType (&$value, &$type, &$size, &$xml)
// Seems we have a multi dimensional array, figure it out if we
for ($i = 0; $i < $c; $i++ ) {
$this->_multiArrayType ($value[$i], $type, $size, $xml);
$size = $sz. ',' . $size;
$xml .= $value->serialize ($this);
$type = $this->_getType ($value);
$xml .= $this->_serializeValue ($value, 'item', $type);
* Returns whether a string is base64 encoded data.
* @param string $value The string to check.
* @return boolean True if the specified value seems to be base64 encoded.
function _isBase64 (&$value)
return $value[$l - 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.
// 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.
foreach ($a as $k => $v) {
// Checking the type is faster than regexp.
} elseif ($this->_isSoapValue ($v)) {
// If someone has a large hash they should really be defining the
function &_un_htmlentities ($string)
return strtr($string, $trans_tbl);
function &_decode (&$soapval)
global $SOAP_OBJECT_STRUCT;
if (!$this->_isSoapValue ($soapval)) {
if ($SOAP_OBJECT_STRUCT && $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
$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
$classname = $this->_type_translation[$soapval->type ];
} elseif ($this->_auto_translation) {
$classname = $soapval->type;
} elseif ($this->_wsdl) {
$t = $this->_wsdl->getComplexTypeNameForElement ($soapval->name , $soapval->namespace );
$return = & new $classname;
$isstruct = !$SOAP_OBJECT_STRUCT || !is_array($return);
foreach ($soapval->value as $item) {
// Get this child's WSDL information.
// /$soapval->ns/$soapval->type/$item->ns/$item->name
$child_type = $this->_wsdl->getComplexTypeChildType (
$item->type = $child_type;
if (!$isstruct || $item->type == 'Array') {
if (isset ($return->{$item->name }) &&
$return->{$item->name } = & $this->_decode ($item);
} elseif (isset ($return->{$item->name }) &&
$return->{$item->name }[] = & $this->_decode ($item);
$return[] = & $this->_decode ($item);
$return->{$item->name } = & $this->_decode ($item);
} elseif (isset ($return->{$item->name })) {
$d = & $this->_decode ($item);
$return = array ($return->{$item->name }, $d);
$d = & $this->_decode ($item);
$return->{$item->name } = array ($return->{$item->name }, $d);
$return->{$item->name } = & $this->_decode ($item);
// Set the attributes as members in the class.
foreach ($soapval->attributes as $key => $value) {
if ($soapval->arrayType && $this->_isSoapValue ($item)) {
if ($this->_isBase64Type ($item->type ) &&
!$this->_isBase64Type ($soapval->arrayType )) {
// Decode the value if we're losing the base64
$item->type = $soapval->arrayType;
$return[] = & $this->_decode ($item);
} elseif (isset ($return[$item->name ])) {
$d = & $this->_decode ($item);
$return = array ($return[$item->name ], $d);
$return[$item->name ] = & $this->_decode ($item);
if ($soapval->type == 'boolean') {
if ($soapval->value != '0' &&
} elseif ($soapval->type &&
// If we can, set variable type.
if ($this->_isBase64Type ($soapval->type )) {
* Creates the SOAP envelope with the SOAP envelop data.
* @param string $encoding
function &_makeEnvelope (&$method, &$headers,
$encoding = SOAP_DEFAULT_ENCODING ,
$smsg = $header_xml = $ns_string = '';
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') {
for ($i = 0; $i < $c; $i++ ) {
$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";
$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".
" $header_xml$body</SOAP-ENV:Envelope>\r\n";
function &_makeMimeMessage (&$xml, $encoding = SOAP_DEFAULT_ENCODING )
if (!isset ($SOAP_options['Mime'])) {
return $this->_raiseSoapFault ('Mime 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);
$params['content_type'] = 'text/xml';
$params['charset'] = $encoding;
$params['encoding'] = 'base64';
$msg->addSubPart ($xml, $params);
$c = count($this->__attachments );
for ($i = 0; $i < $c; $i++ ) {
$attachment = & $this->__attachments [$i];
$msg->addSubPart ($attachment['body'], $attachment);
// TODO: this needs to be used from the Transport system.
function &_makeDIMEMessage (&$xml)
if (!isset ($SOAP_options['DIME'])) {
return $this->_raiseSoapFault ('DIME 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 );
$c = count($this->__attachments );
for ($i = 0; $i < $c; $i++ ) {
$attachment = & $this->__attachments [$i];
$msg .= $dime->encodeData ($attachment['body'],
$attachment['content_type'],
$msg .= $dime->endMessage ();
function _decodeMimeMessage (&$data, &$headers, &$attachments)
if (!isset ($SOAP_options['Mime'])) {
$this->_raiseSoapFault ('Mime Unsupported, install PEAR::Mail::Mime', '', '', 'Server');
$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;
} elseif (isset ($structure->parts )) {
$data = $structure->parts [0 ]->body;
$structure->parts [0 ]->headers );
if (count($structure->parts ) > 1 ) {
// Prepare the parts for the SOAP parser.
for ($i = 0; $i < $c; $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;
$cid = 'cid:' . substr($p->headers ['content-id'], 1 , -2 );
$attachments[$cid] = $p->body;
$this->_raiseSoapFault ('Mime parsing error', '', '', 'Server');
function _decodeDIMEMessage (&$data, &$headers, &$attachments)
if (!isset ($SOAP_options['DIME'])) {
$this->_raiseSoapFault ('DIME Unsupported, install PEAR::Net::DIME', '', '', 'Server');
// 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');
$this->_raiseSoapFault ('DIME record 1 is not a SOAP envelop!', '', '', 'Server');
$data = $dime->parts [0 ]['data'];
$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 )
$attachments[$id] = $part['data'];
$this->_type_translation [$type]= $class;
* Class used to handle QNAME values in XML.
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
function QName($name, $namespace = '')
if ($name && $name[0 ] == '{') {
// A little more magic than should be in a qname.
// TODO: Need to re-examine this logic later.
return $this->ns . ':' . $this->name;
Documentation generated on Mon, 11 Mar 2019 14:20:02 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|