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.40.2.6 2004/12/04 00:18:31 arnaud 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 depricated.
$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
$GLOBALS['SOAP_RAW_CONVERT'] = FALSE;
#require_once 'SOAP/Fault.php';
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 informations?
$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?
* @var boolean if true debugging informations will be store in $debug_data
* @see $debug_data, SOAP_Base
var $_debug_flag = false;
* String containing debugging informations if $debug_flag is set to true
* @var string debugging informations - mostyl error messages
* @see $debug_flag, SOAP_Base
# supported encodings, limited by XML extension
var $_encodings = array ('ISO-8859-1','US-ASCII','UTF-8');
* Recent PEAR error object
* @param string error code
* @see $debug_data, _debug()
function SOAP_Base_Object ($faultcode = 'Client')
$this->_myfaultcode = $faultcode;
$this->_debug_flag = $GLOBALS['SOAP_DEBUG'];
parent ::PEAR ('SOAP_Fault');
* Please referr to the SOAP definition for an impression of what a certain parameter
* Use $debug_flag to store errors to the member variable $debug_data
* @param string error message
* @param string detailed error message.
* @see $debug_flag, $debug_data
function &_raiseSoapFault ($str, $detail = '', $actorURI = '', $code = null , $mode = null , $options = null , $skipmsg = false )
# pass through previous faults
$is_instance = isset ($this);
if (!$code) $code = $is_instance? $this->_myfaultcode: 'Client';
if ($is_instance) $this->fault = & $fault;
return $this->fault != NULL;
* maintains a string of debug data
* @param debugging message - sometimes an error message
if ($this->_debug_flag) {
* Common base class of all Soap lclasses
* @version $Id: Base.php,v 1.40.2.6 2004/12/04 00:18:31 arnaud Exp $
* @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 ('base64' => 'string','array' => 'array','Array' => 'array', 'Struct'=> 'array')
// load namespace uris into an array of uri => prefix
var $_xmlEntities = array ( '&' => '&', '<' => '<', '>' => '>', "'" => ''', '"' => '"' );
var $_doconversion = FALSE;
var $__attachments = array ();
* @var boolean defines if we use section 5 encoding, or false if this is literal
// handle type to class mapping
var $_auto_translation = false;
var $_type_translation = array ();
* @param string error code
* @see $debug_data, _debug()
$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 (see globals.php)
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)
return $this->_namespaces[$ns];
$prefix = 'ns'. count($this->_namespaces);
$this->_namespaces[$ns] = $prefix;
function _getNamespaceForPrefix ($prefix)
return $flipped[$prefix];
function _isSoapValue (&$value)
function _serializeValue (&$value, $name = '', $type = false , $elNamespace = NULL , $typeNamespace=NULL , $options=array (), $attributes = array (), $artype= '')
$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);
if (!$arrayType) $arrayType = $artype;
if (!$ptype) $ptype = $this->_getType ($value);
if (!$type) $type = $ptype;
if ($k[0 ]== '_') continue; // hide private vars
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
// should realy do, but php-soap is on it's way.
$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 array's. Basicly, it flattens array's to allow us
// to serialize multi-dimensional array's. We only do this if arrayType is set,
// which will typicaly 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 = '';
$arrayTypeQName = & new QName($arrayType);
$arrayType = $arrayTypeQName->name;
// 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);
$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);
if ($numtypes == 1 ) $arrayType = $array_type;
// using anyType is more interoperable
if ($array_type == 'Struct') {
} else if ($array_type == 'Array') {
$array_type_prefix = 'xsd';
if (!$arrayType) $arrayType = $array_type;
if (!$arrayType || $numtypes > 1 ) {
$arrayType = 'xsd:anyType'; // should reference what schema we're using
$array_type_prefix = $this->_getNamespacePrefix ($array_type_ns);
} else if (array_key_exists($arrayType, $this->_typemap[$this->_XMLSchemaVersion])) {
$array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion];
$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]\"";
} else if ($this->_isSoapValue ($value)) {
$xmlout_value = & $value->serialize ($this);
} else if ($type == 'string') {
} else if ($type == 'rawstring') {
} else if ($type == 'boolean') {
$xmlout_value = $value? 'true': 'false';
$elPrefix = $this->_getNamespacePrefix ($elNamespace);
$xmlout_name = " $elPrefix:$name";
$typePrefix = $this->_getNamespacePrefix ($typeNamespace);
$xmlout_type = " $typePrefix:$type";
} else if ($type && array_key_exists($type, $this->_typemap[$this->_XMLSchemaVersion])) {
$typePrefix = $this->_namespaces[$this->_XMLSchemaVersion];
$xmlout_type = " $typePrefix:$type";
// handle additional attributes
if (count($attributes) > 0 ) {
foreach ($attributes as $k => $v) {
$xml_attr .= ' '. $kqn->fqn (). '="'. $vqn->fqn (). '"';
// store the attachement for mime encoding
if (isset ($options['attachment']))
$this->__attachments[] = $options['attachment'];
if ($xmlout_type) $xmlout_type = " xsi:type=\"$xmlout_type\"";
$xml = " \r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType$xml_attr/>";
$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>";
* convert php type to soap type
* @return string type - soap type
function _getType (&$value) {
global $SOAP_OBJECT_STRUCT,$SOAP_RAW_CONVERT;
if (is_a($value,'soap_value')) {
// XXX hashes always get done as structs by pear::soap
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
#$value = $value?'true':'false';
$type = 'float'; // double is deprecated in 4.2 and later
if (strstr($value,'.')) $type = 'float';
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 do
for ($i=0; $i< $c; $i++ ) {
$this->_multiArrayType ($value[$i], $type, $size, $xml);
$xml .= $value->serialize ($this);
$type = $this->_getType ($value);
$xml .= $this->_serializeValue ($value,'item',$type);
function _isBase64 (&$value)
return $value[$l-1 ] == '=' && preg_match("/[A-Za-z=\/\+]+/",$value);
# XXX I realy dislike having to loop through this in php code,
# realy 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.
} else if ($this->_isSoapValue ($v)) {
// if someone has a large hash they should realy be defining the type
if ($it++ > 10 ) return FALSE;
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') {
if (isset ($this->_type_translation[$soapval->tqn ->fqn ()])) {
// this will force an error in php if the
$classname = $this->_type_translation[$soapval->tqn ->fqn ()];
} else if (isset ($this->_type_translation[$soapval->type ])) {
// this will force an error in php if the
$classname = $this->_type_translation[$soapval->type ];
} else if ($this->_auto_translation) {
$classname = $soapval->type;
} else if ($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 childs wsdl information
// /$soapval->ns/$soapval->type/$item->ns/$item->name
$child_type = $this->_wsdl->getComplexTypeChildType (
if ($child_type) $item->type = $child_type;
if (!$isstruct || $item->type == 'Array') {
if (isset ($return->{$item->name }) &&
$return->{$item->name } = & $this->_decode ($item);
} else if (isset ($return->{$item->name }) &&
$return->{$item->name }[] = & $this->_decode ($item);
$return[] = & $this->_decode ($item);
$return->{$item->name } = & $this->_decode ($item);
} else if (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)) {
$item->type = $soapval->arrayType;
$return[] = & $this->_decode ($item);
} else if (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' && strcasecmp($soapval->value ,'false') !=0 ) {
# if we can, lets set php's variable type
* creates the soap envelope with the soap envelop data
* @param string $payload soap data (in xml)
* @return associative array (headers,body)
function &_makeEnvelope (&$method, &$headers, $encoding = SOAP_DEFAULT_ENCODING ,$options = array ())
$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";
/* if use='literal', we do not put in the encodingStyle. This is denoted by
$this->_section5 being false.
XXX 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);
// XXX 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'],$attachment['cid'],NET_DIME_TYPE_MEDIA );
$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;
// XXX 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;
} else if (isset ($structure->parts )) {
$data = $structure->parts [0 ]->body;
$headers = array_merge($structure->headers ,$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'])) {
// XXX 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 ,strlen($p->headers ['content-id'])-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');
// XXX 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'; // fake it for now
$c = count($dime->parts );
for ($i = 0; $i < $c; $i++ ) {
$part = & $dime->parts [$i];
// XXX we need to handle URI's better
$id = strncmp( $part['id'], 'cid:', 4 ) ? 'cid:'. $part['id'] : $part['id'];
$attachments[$id] = $part['data'];
$this->_type_translation [$type]= $class;
* class used to handle QNAME values in XML
* @version $Id: Base.php,v 1.40.2.6 2004/12/04 00:18:31 arnaud Exp $
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
function QName($name, $namespace = '') {
if ($name && $name[0 ] == '{') {
} else if (strpos($name, ':') != FALSE ) {
# a little more magic than should be in a qname
# XXX need to re-examine this logic later
return $this->ns. ':'. $this->name;
Documentation generated on Mon, 11 Mar 2019 13:59:44 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|