Source for file Base.php
Documentation is available at Base.php
* This file loads all required libraries, defines constants used across the
* SOAP package, and defines the base classes that most other classes of this
* 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.
* @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 linebreak sequence for the Mail_Mime package. */
define('MAIL_MIMEPART_CRLF', "\r\n");
define('SOAP_LIBRARY_VERSION', '0.12.0');
define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.12.0-beta');
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');
* Supported encodings, limited by XML extension.
var $_encodings = array ('ISO-8859-1', 'US-ASCII', 'UTF-8');
* @var string $_myfaultcode
* Recent PEAR_Error object.
* @param string $faultcode Error code.
$this->_myfaultcode = $faultcode;
parent ::PEAR ('SOAP_Fault');
* Please refer to the SOAP definition for an impression of what a certain
* @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) && is_a($this, 'SOAP_Base_Object');
$code = $is_instance ? $this->_myfaultcode : 'Client';
require_once 'SOAP/Fault.php';
$fault = new SOAP_Fault($str, $code, $actorURI, $detail, $mode,
return $this->fault != null;
* 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',
// longs (64bit ints) are not supported cross-platform.
'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';
* Hash with used namespaces.
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 ();
* @param string $faultcode Error code.
$this->_resetNamespaces ();
* Sets the SOAP-ENV prefix and returns the current value.
* @param string SOAP-ENV prefix
* @return string current SOAP-ENV prefix.
static $_soapenv_prefix = 'SOAP-ENV';
$_soapenv_prefix = $prefix;
* Sets the SOAP-ENC prefix and returns the current value.
* @param string SOAP-ENC prefix
* @return string current SOAP-ENC prefix.
static $_soapenv_prefix = 'SOAP-ENC';
$_soapenv_prefix = $prefix;
* Sets the default namespace.
* @param string $namespace The default namespace.
$this->_namespace = $namespace;
function _resetNamespaces ()
$this->_namespaces = array (
'http://schemas.xmlsoap.org/soap/envelope/' => SOAP_BASE ::SOAPENVPrefix (),
'http://www.w3.org/2001/XMLSchema' => 'xsd',
'http://www.w3.org/2001/XMLSchema-instance' => 'xsi',
'http://schemas.xmlsoap.org/soap/encoding/' => SOAP_BASE ::SOAPENCPrefix ());
* 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];
* Serializes a value, array or object according to the rules set by this
* @param mixed $value The actual value.
* @param QName $name The value name.
* @param QName $type The value type.
* @param array $options A list of encoding and serialization options.
* @param array $attributes A hash of additional attributes.
* @param string $artype The type of any array elements.
function _serializeValue ($value, $name = null , $type = null ,
$options = array (), $attributes = array (),
$arrayType = $array_depth = $xmlout_value = null;
$typePrefix = $elPrefix = $xmlout_arrayType = '';
$xmlout_type = $xmlns = $ptype = $array_type_ns = '';
list ($ptype, $arrayType, $array_type_ns, $array_depth)
= $this->_wsdl->getSchemaType ($type, $name);
$ptype = $this->_getType ($value);
$type = new QName($ptype);
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]), new QName($k, $this->_section5 ? null : $name->namepace ), null , $options);
$xmlout_value .= $this->_serializeValue ($vars[$k], new QName($k, $this->_section5 ? null : $name->namespace ), false , $options);
// 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;
// Serialize each array element.
$ar_size = count($value);
foreach ($value as $array_val) {
if (is_a($array_val, 'SOAP_Value')) {
$array_type = $array_val->type;
$array_types[$array_type] = 1;
$array_type_ns = $array_val->type_namespace;
$xmlout_value .= $array_val->serialize ($this);
$array_type = $this->_getType ($array_val);
$array_types[$array_type] = 1;
if (empty ($options['keep_arrays_flat'])) {
$xmlout_value .= $this->_serializeValue ($array_val, new QName('item', $this->_section5 ? null : $name->namespace ), new QName($array_type), $options);
$xmlout_value .= $this->_serializeValue ($array_val, $name, new QName($array_type), $options, $attributes);
$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];
$array_type_prefix = SOAP_BASE ::SOAPENCPrefix ();
if ($array_type_prefix) {
$arrayType = $array_type_prefix . ':' . $arrayType;
$xmlout_arrayType = ' ' . SOAP_BASE ::SOAPENCPrefix ()
. ':arrayType="' . $arrayType;
if ($array_depth != null ) {
for ($i = 0; $i < $array_depth; $i++ ) {
$xmlout_arrayType .= '[]';
$xmlout_arrayType .= " [$ar_size]\"";
} elseif (is_a($value, 'SOAP_Value')) {
$xmlout_value = $value->serialize ($this);
} elseif ($type->name == 'string') {
} elseif ($type->name == 'rawstring') {
} elseif ($type->name == 'boolean') {
$xmlout_value = $value ? 'true' : 'false';
$elPrefix = $this->_getNamespacePrefix ($name->namespace );
$xmlout_name = $elPrefix . ':' . $name->name;
$xmlout_name = $name->name;
$xmlout_name = $name->name;
if (empty ($options['no_type_prefix'])) {
$typePrefix = $this->_getNamespacePrefix ($type->namespace );
$xmlout_type = $typePrefix . ':' . $type->name;
$xmlout_type = $type->name;
isset ($this->_typemap[$this->_XMLSchemaVersion][$type->name ])) {
$typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
$xmlout_type = $typePrefix . ':' . $type->name;
$xmlout_type = $type->name;
// 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']) &&
!PEAR ::isError ($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" .
" $xml_attr>$xmlout_value</$xmlout_name>";
} elseif ($type->name == 'Array' && !empty ($options['keep_arrays_flat'])) {
$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 mixed $value The value to inspect.
* @return string The value's SOAP type.
function _getType ($value)
if (is_a($value, 'soap_value')) {
// Hashes are always handled as structs.
if ($this->_isHash ($value)) {
// For non-wsdl structs that are all the same type
if (is_a($value1, 'SOAP_Value') &&
is_a($value2, 'SOAP_Value') &&
$value1->name != $value2->name ) {
// This is a struct, not an array.
// double is deprecated in PHP 4.2 and later.
function _multiArrayType ($value, &$type, &$size, &$xml)
// Seems we have a multi dimensional array, figure it out if we
for ($i = 0 , $c = count($value); $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, new QName('item'), new QName($type));
* 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.
// Checking the type is faster than regexp.
function _un_htmlentities ($string)
return strtr($string, $trans_tbl);
* Converts a SOAP_Value object into a PHP value.
function _decode ($soapval)
if (!is_a($soapval, 'SOAP_Value')) {
$isstruct = $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;
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 ($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);
} elseif (isset ($return->{$item->name })) {
$return->{$item->name } = array (
$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);
$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 && is_a($item, 'SOAP_Value')) {
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);
if ($soapval->type == 'boolean') {
if ($soapval->value != '0' &&
} elseif ($soapval->type &&
// If we can, set variable type.
} elseif ($soapval->type == 'Struct') {
* Creates the SOAP envelope with the SOAP envelop data.
* @param SOAP_Value $method SOAP_Value instance with the method name as
* the name, and the method arguments as the
* @param array $headers A list of additional SOAP_Header objects.
* @param string $encoding The charset of the SOAP message.
* @param array $options A list of encoding/serialization options.
* @return string The complete SOAP message.
function makeEnvelope($method, $headers, $encoding = SOAP_DEFAULT_ENCODING ,
$smsg = $header_xml = $ns_string = '';
for ($i = 0 , $c = count($headers); $i < $c; $i++ ) {
$header_xml .= $headers[$i]->serialize($this);
$header_xml = sprintf("<%s:Header>\r\n%s\r\n</%s:Header>\r\n",
SOAP_BASE ::SOAPENVPrefix (), $header_xml,
SOAP_BASE ::SOAPENVPrefix ());
if (!isset ($options['input']) || $options['input'] == 'parse') {
for ($i = 0 , $c = count($method); $i < $c; $i++ ) {
$body = sprintf("<%s:Body>%s\r\n</%s:Body>\r\n",
SOAP_BASE ::SOAPENVPrefix (), $smsg,
SOAP_BASE ::SOAPENVPrefix ());
foreach ($this->_namespaces as $k => $v) {
$ns_string .= "\r\n " . sprintf('xmlns:%s="%s"', $v, $k);
$ns_string .= "\r\n " . sprintf('xmlns="%s"', $this->_namespace );
/* If 'use' == 'literal', 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 = sprintf('<?xml version="1.0" encoding="%s"?>%s<%s:Envelope%s',
$encoding, "\r\n", SOAP_BASE ::SOAPENVPrefix (),
$xml .= "\r\n " . sprintf('%s:encodingStyle="%s"',
SOAP_BASE ::SOAPENVPrefix (),
$xml .= sprintf('>%s%s%s</%s:Envelope>' . "\r\n",
"\r\n", $header_xml, $body, SOAP_BASE ::SOAPENVPrefix ());
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);
$params['content_type'] = 'text/xml';
$params['charset'] = $encoding;
$msg->addSubPart ($xml, $params);
for ($i = 0 , $c = count($this->_attachments ); $i < $c; ++ $i) {
$msg->addSubPart ($this->_attachments [$i]['body'],
$this->_attachments [$i]);
// 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 );
$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'],
$msg .= $dime->endMessage ();
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;
} 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 , $c = count($mime_parts); $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 , -1 );
$attachments[$cid] = $p->body;
$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');
$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'];
* 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.
$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, 04 Aug 2008 20:00:11 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.
|