晋太元中,武陵人捕鱼为业。缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷。渔人甚异之,复前行,欲穷其林。 林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田、美池、桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。 见渔人,乃大惊,问所从来。具答之。便要还家,设酒杀鸡作食。村中闻有此人,咸来问讯。自云先世避秦时乱,率妻子邑人来此绝境,不复出焉,遂与外人间隔。问今是何世,乃不知有汉,无论魏晋。此人一一为具言所闻,皆叹惋。余人各复延至其家,皆出酒食。停数日,辞去。此中人语云:“不足为外人道也。”(间隔 一作:隔绝) 既出,得其船,便扶向路,处处志之。及郡下,诣太守,说如此。太守即遣人随其往,寻向所志,遂迷,不复得路。 南阳刘子骥,高尚士也,闻之,欣然规往。未果,寻病终。后遂无问津者。
|
Server : Apache System : Linux srv.rainic.com 4.18.0-553.47.1.el8_10.x86_64 #1 SMP Wed Apr 2 05:45:37 EDT 2025 x86_64 User : rainic ( 1014) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/stando/www/wp-content/plugins/persian-gravity-forms/includes/lib/ |
Upload File : |
<?php
/*
$Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
NuSOAP - Web Services Toolkit for PHP
Copyright (c) 2002 NuSphere Corporation
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The NuSOAP project home is:
http://sourceforge.net/projects/nusoap/
The primary support for NuSOAP is the Help forum on the project home page.
If you have any questions or comments, please email:
Dietrich Ayala
dietrich@ganx4.com
http://dietrich.ganx4.com/nusoap
NuSphere Corporation
http://www.nusphere.com
*/
/*
* Some of the standards implmented in whole or part by NuSOAP:
*
* SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
* WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
* SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
* XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
* Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
* XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
* RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
* RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
* RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
*/
/* load classes
// necessary classes
require_once('class.soapclient.php');
require_once('class.soap_val.php');
require_once('class.soap_parser.php');
require_once('class.soap_fault.php');
// transport classes
require_once('class.soap_transport_http.php');
// optional add-on classes
require_once('class.xmlschema.php');
require_once('class.wsdl.php');
// server class
require_once('class.soap_server.php');*/
// class variable emulation
// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
/**
*
* nusoap_base
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
//error_reporting( '0' );
class nusoap_base {
/**
* Identification for HTTP headers.
*
* @var string
* @access private
*/
var $title = 'NuSOAP';
/**
* Version for HTTP headers.
*
* @var string
* @access private
*/
var $version = '0.9.5';
/**
* CVS revision for HTTP headers.
*
* @var string
* @access private
*/
var $revision = '$Revision: 1.123 $';
/**
* Current error string (manipulated by getError/setError)
*
* @var string
* @access private
*/
var $error_str = '';
/**
* Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
*
* @var string
* @access private
*/
var $debug_str = '';
/**
* toggles automatic encoding of special characters as entities
* (should always be true, I think)
*
* @var boolean
* @access private
*/
var $charencoding = true;
/**
* the debug level for this instance
*
* @var integer
* @access private
*/
var $debugLevel;
/**
* set schema version
*
* @var string
* @access public
*/
var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
/**
* charset encoding for outgoing messages
*
* @var string
* @access public
*/
var $soap_defencoding = 'ISO-8859-1';
//var $soap_defencoding = 'UTF-8';
/**
* namespaces in an array of prefix => uri
*
* this is "seeded" by a set of constants, but it may be altered by code
*
* @var array
* @access public
*/
var $namespaces = array(
'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
'xsd' => 'http://www.w3.org/2001/XMLSchema',
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
);
/**
* namespaces used in the current context, e.g. during serialization
*
* @var array
* @access private
*/
var $usedNamespaces = array();
/**
* XML Schema types in an array of uri => (array of xml type => php type)
* is this legacy yet?
* no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
* @var array
* @access public
*/
var $typemap = array(
'http://www.w3.org/2001/XMLSchema' => array(
'string' => 'string',
'boolean' => 'boolean',
'float' => 'double',
'double' => 'double',
'decimal' => 'double',
'duration' => '',
'dateTime' => 'string',
'time' => 'string',
'date' => 'string',
'gYearMonth' => '',
'gYear' => '',
'gMonthDay' => '',
'gDay' => '',
'gMonth' => '',
'hexBinary' => 'string',
'base64Binary' => 'string',
// abstract "any" types
'anyType' => 'string',
'anySimpleType' => 'string',
// derived datatypes
'normalizedString' => 'string',
'token' => 'string',
'language' => '',
'NMTOKEN' => '',
'NMTOKENS' => '',
'Name' => '',
'NCName' => '',
'ID' => '',
'IDREF' => '',
'IDREFS' => '',
'ENTITY' => '',
'ENTITIES' => '',
'integer' => 'integer',
'nonPositiveInteger' => 'integer',
'negativeInteger' => 'integer',
'long' => 'integer',
'int' => 'integer',
'short' => 'integer',
'byte' => 'integer',
'nonNegativeInteger' => 'integer',
'unsignedLong' => '',
'unsignedInt' => '',
'unsignedShort' => '',
'unsignedByte' => '',
'positiveInteger' => ''
),
'http://www.w3.org/2000/10/XMLSchema' => array(
'i4' => '',
'int' => 'integer',
'boolean' => 'boolean',
'string' => 'string',
'double' => 'double',
'float' => 'double',
'dateTime' => 'string',
'timeInstant' => 'string',
'base64Binary' => 'string',
'base64' => 'string',
'ur-type' => 'array'
),
'http://www.w3.org/1999/XMLSchema' => array(
'i4' => '',
'int' => 'integer',
'boolean' => 'boolean',
'string' => 'string',
'double' => 'double',
'float' => 'double',
'dateTime' => 'string',
'timeInstant' => 'string',
'base64Binary' => 'string',
'base64' => 'string',
'ur-type' => 'array'
),
'http://soapinterop.org/xsd' => array( 'SOAPStruct' => 'struct' ),
'http://schemas.xmlsoap.org/soap/encoding/' => array(
'base64' => 'string',
'array' => 'array',
'Array' => 'array'
),
'http://xml.apache.org/xml-soap' => array( 'Map' )
);
/**
* XML entities to convert
*
* @var array
* @access public
* @deprecated
* @see expandEntities
*/
var $xmlEntities = array(
'quot' => '"',
'amp' => '&',
'lt' => '<',
'gt' => '>',
'apos' => "'"
);
/**
* constructor
*
* @access public
*/
function nusoap_base() {
$this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
}
/**
* gets the global debug level, which applies to future instances
*
* @return integer Debug level 0-9, where 0 turns off
* @access public
*/
function getGlobalDebugLevel() {
return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
}
/**
* sets the global debug level, which applies to future instances
*
* @param int $level Debug level 0-9, where 0 turns off
*
* @access public
*/
function setGlobalDebugLevel( $level ) {
$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
}
/**
* gets the debug level for this instance
*
* @return int Debug level 0-9, where 0 turns off
* @access public
*/
function getDebugLevel() {
return $this->debugLevel;
}
/**
* sets the debug level for this instance
*
* @param int $level Debug level 0-9, where 0 turns off
*
* @access public
*/
function setDebugLevel( $level ) {
$this->debugLevel = $level;
}
/**
* adds debug data to the instance debug string with formatting
*
* @param string $string debug data
*
* @access private
*/
function debug( $string ) {
if ( $this->debugLevel > 0 ) {
$this->appendDebug( $this->getmicrotime() . ' ' . get_class( $this ) . ": $string\n" );
}
}
/**
* adds debug data to the instance debug string without formatting
*
* @param string $string debug data
*
* @access public
*/
function appendDebug( $string ) {
if ( $this->debugLevel > 0 ) {
// it would be nice to use a memory stream here to use
// memory more efficiently
$this->debug_str .= $string;
}
}
/**
* clears the current debug data for this instance
*
* @access public
*/
function clearDebug() {
// it would be nice to use a memory stream here to use
// memory more efficiently
$this->debug_str = '';
}
/**
* gets the current debug data for this instance
*
* @return debug data
* @access public
*/
function &getDebug() {
// it would be nice to use a memory stream here to use
// memory more efficiently
return $this->debug_str;
}
/**
* gets the current debug data for this instance as an XML comment
* this may change the contents of the debug data
*
* @return debug data as an XML comment
* @access public
*/
function &getDebugAsXMLComment() {
// it would be nice to use a memory stream here to use
// memory more efficiently
while ( strpos( $this->debug_str, '--' ) ) {
$this->debug_str = str_replace( '--', '- -', $this->debug_str );
}
$ret = "<!--\n" . $this->debug_str . "\n-->";
return $ret;
}
/**
* expands entities, e.g. changes '<' to '<'.
*
* @param string $val The string in which to expand entities.
*
* @access private
*/
function expandEntities( $val ) {
if ( $this->charencoding ) {
$val = str_replace( '&', '&', $val );
$val = str_replace( "'", ''', $val );
$val = str_replace( '"', '"', $val );
$val = str_replace( '<', '<', $val );
$val = str_replace( '>', '>', $val );
}
return $val;
}
/**
* returns error string if present
*
* @return mixed error string or false
* @access public
*/
function getError() {
if ( $this->error_str != '' ) {
return $this->error_str;
}
return false;
}
/**
* sets error string
*
* @return boolean $string error string
* @access private
*/
function setError( $str ) {
$this->error_str = $str;
}
/**
* detect if array is a simple array or a struct (associative array)
*
* @param mixed $val The PHP array
*
* @return string (arraySimple|arrayStruct)
* @access private
*/
function isArraySimpleOrStruct( $val ) {
$keyList = array_keys( $val );
foreach ( $keyList as $keyListValue ) {
if ( ! is_int( $keyListValue ) ) {
return 'arrayStruct';
}
}
return 'arraySimple';
}
/**
* serializes PHP values in accordance w/ section 5. Type information is
* not serialized if $use == 'literal'.
*
* @param mixed $val The value to serialize
* @param string $name The name (local part) of the XML element
* @param string $type The XML schema type (local part) for the element
* @param string $name_ns The namespace for the name of the XML element
* @param string $type_ns The namespace for the type of the element
* @param array $attributes The attributes to serialize as name=>value pairs
* @param string $use The WSDL "use" (encoded|literal)
* @param boolean $soapval Whether this is called from soapval.
*
* @return string The serialized element, possibly with child elements
* @access public
*/
function serialize_val( $val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false ) {
$this->debug( "in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval" );
$this->appendDebug( 'value=' . $this->varDump( $val ) );
$this->appendDebug( 'attributes=' . $this->varDump( $attributes ) );
if ( is_object( $val ) && get_class( $val ) == 'soapval' && ( ! $soapval ) ) {
$this->debug( "serialize_val: serialize soapval" );
$xml = $val->serialize( $use );
$this->appendDebug( $val->getDebug() );
$val->clearDebug();
$this->debug( "serialize_val of soapval returning $xml" );
return $xml;
}
// force valid name if necessary
if ( is_numeric( $name ) ) {
$name = '__numeric_' . $name;
} elseif ( ! $name ) {
$name = 'noname';
}
// if name has ns, add ns prefix to name
$xmlns = '';
if ( $name_ns ) {
$prefix = 'nu' . rand( 1000, 9999 );
$name = $prefix . ':' . $name;
$xmlns .= " xmlns:$prefix=\"$name_ns\"";
}
// if type is prefixed, create type prefix
if ( $type_ns != '' && $type_ns == $this->namespaces['xsd'] ) {
// need to fix this. shouldn't default to xsd if no ns specified
// w/o checking against typemap
$type_prefix = 'xsd';
} elseif ( $type_ns ) {
$type_prefix = 'ns' . rand( 1000, 9999 );
$xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
}
// serialize attributes if present
$atts = '';
if ( $attributes ) {
foreach ( $attributes as $k => $v ) {
$atts .= " $k=\"" . $this->expandEntities( $v ) . '"';
}
}
// serialize null value
if ( is_null( $val ) ) {
$this->debug( "serialize_val: serialize null" );
if ( $use == 'literal' ) {
// TODO: depends on minOccurs
$xml = "<$name$xmlns$atts/>";
$this->debug( "serialize_val returning $xml" );
return $xml;
} else {
if ( isset( $type ) && isset( $type_prefix ) ) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = '';
}
$xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
$this->debug( "serialize_val returning $xml" );
return $xml;
}
}
// serialize if an xsd built-in primitive type
if ( $type != '' && isset( $this->typemap[ $this->XMLSchemaVersion ][ $type ] ) ) {
$this->debug( "serialize_val: serialize xsd built-in primitive type" );
if ( is_bool( $val ) ) {
if ( $type == 'boolean' ) {
$val = $val ? 'true' : 'false';
} elseif ( ! $val ) {
$val = 0;
}
} else if ( is_string( $val ) ) {
$val = $this->expandEntities( $val );
}
if ( $use == 'literal' ) {
$xml = "<$name$xmlns$atts>$val</$name>";
$this->debug( "serialize_val returning $xml" );
return $xml;
} else {
$xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
$this->debug( "serialize_val returning $xml" );
return $xml;
}
}
// detect type and serialize
$xml = '';
switch ( true ) {
case ( is_bool( $val ) || $type == 'boolean' ):
$this->debug( "serialize_val: serialize boolean" );
if ( $type == 'boolean' ) {
$val = $val ? 'true' : 'false';
} elseif ( ! $val ) {
$val = 0;
}
if ( $use == 'literal' ) {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
}
break;
case ( is_int( $val ) || is_long( $val ) || $type == 'int' ):
$this->debug( "serialize_val: serialize int" );
if ( $use == 'literal' ) {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
}
break;
case ( is_float( $val ) || is_double( $val ) || $type == 'float' ):
$this->debug( "serialize_val: serialize float" );
if ( $use == 'literal' ) {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
}
break;
case ( is_string( $val ) || $type == 'string' ):
$this->debug( "serialize_val: serialize string" );
$val = $this->expandEntities( $val );
if ( $use == 'literal' ) {
$xml .= "<$name$xmlns$atts>$val</$name>";
} else {
$xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
}
break;
case is_object( $val ):
$this->debug( "serialize_val: serialize object" );
if ( get_class( $val ) == 'soapval' ) {
$this->debug( "serialize_val: serialize soapval object" );
$pXml = $val->serialize( $use );
$this->appendDebug( $val->getDebug() );
$val->clearDebug();
} else {
if ( ! $name ) {
$name = get_class( $val );
$this->debug( "In serialize_val, used class name $name as element name" );
} else {
$this->debug( "In serialize_val, do not override name $name for element name for class " . get_class( $val ) );
}
foreach ( get_object_vars( $val ) as $k => $v ) {
$pXml = isset( $pXml ) ? $pXml . $this->serialize_val( $v, $k, false, false, false, false, $use ) : $this->serialize_val( $v, $k, false, false, false, false, $use );
}
}
if ( isset( $type ) && isset( $type_prefix ) ) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = '';
}
if ( $use == 'literal' ) {
$xml .= "<$name$xmlns$atts>$pXml</$name>";
} else {
$xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
}
break;
break;
case ( is_array( $val ) || $type ):
// detect if struct or array
$valueType = $this->isArraySimpleOrStruct( $val );
if ( $valueType == 'arraySimple' || preg_match( '/^ArrayOf/', $type ) ) {
$this->debug( "serialize_val: serialize array" );
$i = 0;
if ( is_array( $val ) && count( $val ) > 0 ) {
foreach ( $val as $v ) {
if ( is_object( $v ) && get_class( $v ) == 'soapval' ) {
$tt_ns = $v->type_ns;
$tt = $v->type;
} elseif ( is_array( $v ) ) {
$tt = $this->isArraySimpleOrStruct( $v );
} else {
$tt = gettype( $v );
}
$array_types[ $tt ] = 1;
// TODO: for literal, the name should be $name
$xml .= $this->serialize_val( $v, 'item', false, false, false, false, $use );
++ $i;
}
if ( count( $array_types ) > 1 ) {
$array_typename = 'xsd:anyType';
} elseif ( isset( $tt ) && isset( $this->typemap[ $this->XMLSchemaVersion ][ $tt ] ) ) {
if ( $tt == 'integer' ) {
$tt = 'int';
}
$array_typename = 'xsd:' . $tt;
} elseif ( isset( $tt ) && $tt == 'arraySimple' ) {
$array_typename = 'SOAP-ENC:Array';
} elseif ( isset( $tt ) && $tt == 'arrayStruct' ) {
$array_typename = 'unnamed_struct_use_soapval';
} else {
// if type is prefixed, create type prefix
if ( $tt_ns != '' && $tt_ns == $this->namespaces['xsd'] ) {
$array_typename = 'xsd:' . $tt;
} elseif ( $tt_ns ) {
$tt_prefix = 'ns' . rand( 1000, 9999 );
$array_typename = "$tt_prefix:$tt";
$xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
} else {
$array_typename = $tt;
}
}
$array_type = $i;
if ( $use == 'literal' ) {
$type_str = '';
} else if ( isset( $type ) && isset( $type_prefix ) ) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\"";
}
// empty array
} else {
if ( $use == 'literal' ) {
$type_str = '';
} else if ( isset( $type ) && isset( $type_prefix ) ) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
}
}
// TODO: for array in literal, there is no wrapper here
$xml = "<$name$xmlns$type_str$atts>" . $xml . "</$name>";
} else {
// got a struct
$this->debug( "serialize_val: serialize struct" );
if ( isset( $type ) && isset( $type_prefix ) ) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
$type_str = '';
}
if ( $use == 'literal' ) {
$xml .= "<$name$xmlns$atts>";
} else {
$xml .= "<$name$xmlns$type_str$atts>";
}
foreach ( $val as $k => $v ) {
// Apache Map
if ( $type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap' ) {
$xml .= '<item>';
$xml .= $this->serialize_val( $k, 'key', false, false, false, false, $use );
$xml .= $this->serialize_val( $v, 'value', false, false, false, false, $use );
$xml .= '</item>';
} else {
$xml .= $this->serialize_val( $v, $k, false, false, false, false, $use );
}
}
$xml .= "</$name>";
}
break;
default:
$this->debug( "serialize_val: serialize unknown" );
$xml .= 'not detected, got ' . gettype( $val ) . ' for ' . $val;
break;
}
$this->debug( "serialize_val returning $xml" );
return $xml;
}
/**
* serializes a message
*
* @param string $body the XML of the SOAP body
* @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
* @param array $namespaces optional the namespaces used in generating the body and headers
* @param string $style optional (rpc|document)
* @param string $use optional (encoded|literal)
* @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
*
* @return string the message
* @access public
*/
function serializeEnvelope( $body, $headers = false, $namespaces = array(), $style = 'rpc', $use = 'encoded', $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/' ) {
// TODO: add an option to automatically run utf8_encode on $body and $headers
// if $this->soap_defencoding is UTF-8. Not doing this automatically allows
// one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
$this->debug( "In serializeEnvelope length=" . strlen( $body ) . " body (max 1000 characters)=" . substr( $body, 0, 1000 ) . " style=$style use=$use encodingStyle=$encodingStyle" );
$this->debug( "headers:" );
$this->appendDebug( $this->varDump( $headers ) );
$this->debug( "namespaces:" );
$this->appendDebug( $this->varDump( $namespaces ) );
// serialize namespaces
$ns_string = '';
foreach ( array_merge( $this->namespaces, $namespaces ) as $k => $v ) {
$ns_string .= " xmlns:$k=\"$v\"";
}
if ( $encodingStyle ) {
$ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
}
// serialize headers
if ( $headers ) {
if ( is_array( $headers ) ) {
$xml = '';
foreach ( $headers as $k => $v ) {
if ( is_object( $v ) && get_class( $v ) == 'soapval' ) {
$xml .= $this->serialize_val( $v, false, false, false, false, false, $use );
} else {
$xml .= $this->serialize_val( $v, $k, false, false, false, false, $use );
}
}
$headers = $xml;
$this->debug( "In serializeEnvelope, serialized array of headers to $headers" );
}
$headers = "<SOAP-ENV:Header>" . $headers . "</SOAP-ENV:Header>";
}
// serialize envelope
return
'<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?' . ">" .
'<SOAP-ENV:Envelope' . $ns_string . ">" .
$headers .
"<SOAP-ENV:Body>" .
$body .
"</SOAP-ENV:Body>" .
"</SOAP-ENV:Envelope>";
}
/**
* formats a string to be inserted into an HTML stream
*
* @param string $str The string to format
*
* @return string The formatted string
* @access public
* @deprecated
*/
function formatDump( $str ) {
$str = htmlspecialchars( $str );
return nl2br( $str );
}
/**
* contracts (changes namespace to prefix) a qualified name
*
* @param string $qname qname
*
* @return string contracted qname
* @access private
*/
function contractQname( $qname ) {
// get element namespace
//$this->xdebug("Contract $qname");
if ( strrpos( $qname, ':' ) ) {
// get unqualified name
$name = substr( $qname, strrpos( $qname, ':' ) + 1 );
// get ns
$ns = substr( $qname, 0, strrpos( $qname, ':' ) );
$p = $this->getPrefixFromNamespace( $ns );
if ( $p ) {
return $p . ':' . $name;
}
return $qname;
} else {
return $qname;
}
}
/**
* expands (changes prefix to namespace) a qualified name
*
* @param string $qname qname
*
* @return string expanded qname
* @access private
*/
function expandQname( $qname ) {
// get element prefix
if ( strpos( $qname, ':' ) && ! preg_match( '/^http:\/\//', $qname ) ) {
// get unqualified name
$name = substr( strstr( $qname, ':' ), 1 );
// get ns prefix
$prefix = substr( $qname, 0, strpos( $qname, ':' ) );
if ( isset( $this->namespaces[ $prefix ] ) ) {
return $this->namespaces[ $prefix ] . ':' . $name;
} else {
return $qname;
}
} else {
return $qname;
}
}
/**
* returns the local part of a prefixed string
* returns the original string, if not prefixed
*
* @param string $str The prefixed string
*
* @return string The local part
* @access public
*/
function getLocalPart( $str ) {
if ( $sstr = strrchr( $str, ':' ) ) {
// get unqualified name
return substr( $sstr, 1 );
} else {
return $str;
}
}
/**
* returns the prefix part of a prefixed string
* returns false, if not prefixed
*
* @param string $str The prefixed string
*
* @return mixed The prefix or false if there is no prefix
* @access public
*/
function getPrefix( $str ) {
if ( $pos = strrpos( $str, ':' ) ) {
// get prefix
return substr( $str, 0, $pos );
}
return false;
}
/**
* pass it a prefix, it returns a namespace
*
* @param string $prefix The prefix
*
* @return mixed The namespace, false if no namespace has the specified prefix
* @access public
*/
function getNamespaceFromPrefix( $prefix ) {
if ( isset( $this->namespaces[ $prefix ] ) ) {
return $this->namespaces[ $prefix ];
}
//$this->setError("No namespace registered for prefix '$prefix'");
return false;
}
/**
* returns the prefix for a given namespace (or prefix)
* or false if no prefixes registered for the given namespace
*
* @param string $ns The namespace
*
* @return mixed The prefix, false if the namespace has no prefixes
* @access public
*/
function getPrefixFromNamespace( $ns ) {
foreach ( $this->namespaces as $p => $n ) {
if ( $ns == $n || $ns == $p ) {
$this->usedNamespaces[ $p ] = $n;
return $p;
}
}
return false;
}
/**
* returns the time in ODBC canonical form with microseconds
*
* @return string The time in ODBC canonical form with microseconds
* @access public
*/
function getmicrotime() {
if ( function_exists( 'gettimeofday' ) ) {
$tod = gettimeofday();
$sec = $tod['sec'];
$usec = $tod['usec'];
} else {
$sec = time();
$usec = 0;
}
return strftime( '%Y-%m-%d %H:%M:%S', $sec ) . '.' . sprintf( '%06d', $usec );
}
/**
* Returns a string with the output of var_dump
*
* @param mixed $data The variable to var_dump
*
* @return string The output of var_dump
* @access public
*/
function varDump( $data ) {
ob_start();
var_dump( $data );
$ret_val = ob_get_contents();
ob_end_clean();
return $ret_val;
}
/**
* represents the object as a string
*
* @return string
* @access public
*/
function __toString() {
return $this->varDump( $this );
}
}
// XML Schema Datatype Helper Functions
//xsd:dateTime helpers
/**
* convert unix timestamp to ISO 8601 compliant date string
*
* @param int $timestamp Unix time stamp
* @param boolean $utc Whether the time stamp is UTC or local
*
* @return mixed ISO 8601 date string or false
* @access public
*/
function timestamp_to_iso8601( $timestamp, $utc = true ) {
$datestr = date( 'Y-m-d\TH:i:sO', $timestamp );
$pos = strrpos( $datestr, "+" );
if ( $pos === false ) {
$pos = strrpos( $datestr, "-" );
}
if ( $pos !== false ) {
if ( strlen( $datestr ) == $pos + 5 ) {
$datestr = substr( $datestr, 0, $pos + 3 ) . ':' . substr( $datestr, - 2 );
}
}
if ( $utc ) {
$pattern = '/' .
'([0-9]{4})-' . // centuries & years CCYY-
'([0-9]{2})-' . // months MM-
'([0-9]{2})' . // days DD
'T' . // separator T
'([0-9]{2}):' . // hours hh:
'([0-9]{2}):' . // minutes mm:
'([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
'(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
'/';
if ( preg_match( $pattern, $datestr, $regs ) ) {
return sprintf( '%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6] );
}
return false;
} else {
return $datestr;
}
}
/**
* convert ISO 8601 compliant date string to unix timestamp
*
* @param string $datestr ISO 8601 compliant date string
*
* @return mixed Unix timestamp (int) or false
* @access public
*/
function iso8601_to_timestamp( $datestr ) {
$pattern = '/' .
'([0-9]{4})-' . // centuries & years CCYY-
'([0-9]{2})-' . // months MM-
'([0-9]{2})' . // days DD
'T' . // separator T
'([0-9]{2}):' . // hours hh:
'([0-9]{2}):' . // minutes mm:
'([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
'(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
'/';
if ( preg_match( $pattern, $datestr, $regs ) ) {
// not utc
if ( $regs[8] != 'Z' ) {
$op = substr( $regs[8], 0, 1 );
$h = substr( $regs[8], 1, 2 );
$m = substr( $regs[8], strlen( $regs[8] ) - 2, 2 );
if ( $op == '-' ) {
$regs[4] = $regs[4] + $h;
$regs[5] = $regs[5] + $m;
} elseif ( $op == '+' ) {
$regs[4] = $regs[4] - $h;
$regs[5] = $regs[5] - $m;
}
}
return gmmktime( $regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1] );
// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
} else {
return false;
}
}
/**
* sleeps some number of microseconds
*
* @param string $usec the number of microseconds to sleep
*
* @access public
* @deprecated
*/
function usleepWindows( $usec ) {
$start = gettimeofday();
do {
$stop = gettimeofday();
$timePassed = 1000000 * ( $stop['sec'] - $start['sec'] )
+ $stop['usec'] - $start['usec'];
} while ( $timePassed < $usec );
}
?><?php
/**
* Contains information for a SOAP fault.
* Mainly used for returning faults from deployed functions
* in a server instance.
* @author Dietrich Ayala <dietrich@ganx4.com>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_fault extends nusoap_base {
/**
* The fault code (client|server)
* @var string
* @access private
*/
var $faultcode;
/**
* The fault actor
* @var string
* @access private
*/
var $faultactor;
/**
* The fault string, a description of the fault
* @var string
* @access private
*/
var $faultstring;
/**
* The fault detail, typically a string or array of string
* @var mixed
* @access private
*/
var $faultdetail;
/**
* constructor
*
* @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
* @param string $faultactor only used when msg routed between multiple actors
* @param string $faultstring human readable error message
* @param mixed $faultdetail detail, typically a string or array of string
*/
function nusoap_fault( $faultcode, $faultactor = '', $faultstring = '', $faultdetail = '' ) {
parent::nusoap_base();
$this->faultcode = $faultcode;
$this->faultactor = $faultactor;
$this->faultstring = $faultstring;
$this->faultdetail = $faultdetail;
}
/**
* serialize a fault
*
* @return string The serialization of the fault instance.
* @access public
*/
function serialize() {
$ns_string = '';
foreach ( $this->namespaces as $k => $v ) {
$ns_string .= "\n xmlns:$k=\"$v\"";
}
$return_msg =
'<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?>' .
'<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" .
'<SOAP-ENV:Body>' .
'<SOAP-ENV:Fault>' .
$this->serialize_val( $this->faultcode, 'faultcode' ) .
$this->serialize_val( $this->faultactor, 'faultactor' ) .
$this->serialize_val( $this->faultstring, 'faultstring' ) .
$this->serialize_val( $this->faultdetail, 'detail' ) .
'</SOAP-ENV:Fault>' .
'</SOAP-ENV:Body>' .
'</SOAP-ENV:Envelope>';
return $return_msg;
}
}
/**
* Backward compatibility
*/
class soap_fault extends nusoap_fault {
}
?><?php
/**
* parses an XML Schema, allows access to it's data, other utility methods.
* imperfect, no validation... yet, but quite functional.
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_xmlschema extends nusoap_base {
// files
var $schema = '';
var $xml = '';
// namespaces
var $enclosingNamespaces;
// schema info
var $schemaInfo = array();
var $schemaTargetNamespace = '';
// types, elements, attributes defined by the schema
var $attributes = array();
var $complexTypes = array();
var $complexTypeStack = array();
var $currentComplexType = null;
var $elements = array();
var $elementStack = array();
var $currentElement = null;
var $simpleTypes = array();
var $simpleTypeStack = array();
var $currentSimpleType = null;
// imports
var $imports = array();
// parser vars
var $parser;
var $position = 0;
var $depth = 0;
var $depth_array = array();
var $message = array();
var $defaultNamespace = array();
/**
* constructor
*
* @param string $schema schema document URI
* @param string $xml xml document URI
* @param string $namespaces namespaces defined in enclosing XML
*
* @access public
*/
function nusoap_xmlschema( $schema = '', $xml = '', $namespaces = array() ) {
parent::nusoap_base();
$this->debug( 'nusoap_xmlschema class instantiated, inside constructor' );
// files
$this->schema = $schema;
$this->xml = $xml;
// namespaces
$this->enclosingNamespaces = $namespaces;
$this->namespaces = array_merge( $this->namespaces, $namespaces );
// parse schema file
if ( $schema != '' ) {
$this->debug( 'initial schema file: ' . $schema );
$this->parseFile( $schema, 'schema' );
}
// parse xml file
if ( $xml != '' ) {
$this->debug( 'initial xml file: ' . $xml );
$this->parseFile( $xml, 'xml' );
}
}
/**
* parse an XML file
*
* @param string $xml path/URL to XML file
* @param string $type (schema | xml)
*
* @return boolean
* @access public
*/
function parseFile( $xml, $type ) {
// parse xml file
if ( $xml != "" ) {
$xmlStr = @join( "", @file( $xml ) );
if ( $xmlStr == "" ) {
$msg = 'Error reading XML from ' . $xml;
$this->setError( $msg );
$this->debug( $msg );
return false;
} else {
$this->debug( "parsing $xml" );
$this->parseString( $xmlStr, $type );
$this->debug( "done parsing $xml" );
return true;
}
}
return false;
}
/**
* parse an XML string
*
* @param string $xml path or URL
* @param string $type (schema|xml)
*
* @access private
*/
function parseString( $xml, $type ) {
// parse xml string
if ( $xml != "" ) {
// Create an XML parser.
$this->parser = xml_parser_create();
// Set the options for parsing the XML data.
xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
// Set the object for the parser.
xml_set_object( $this->parser, $this );
// Set the element handlers for the parser.
if ( $type == "schema" ) {
xml_set_element_handler( $this->parser, 'schemaStartElement', 'schemaEndElement' );
xml_set_character_data_handler( $this->parser, 'schemaCharacterData' );
} elseif ( $type == "xml" ) {
xml_set_element_handler( $this->parser, 'xmlStartElement', 'xmlEndElement' );
xml_set_character_data_handler( $this->parser, 'xmlCharacterData' );
}
// Parse the XML file.
if ( ! xml_parse( $this->parser, $xml, true ) ) {
// Display an error message.
$errstr = sprintf( 'XML error parsing XML schema on line %d: %s',
xml_get_current_line_number( $this->parser ),
xml_error_string( xml_get_error_code( $this->parser ) )
);
$this->debug( $errstr );
$this->debug( "XML payload:\n" . $xml );
$this->setError( $errstr );
}
xml_parser_free( $this->parser );
} else {
$this->debug( 'no xml passed to parseString()!!' );
$this->setError( 'no xml passed to parseString()!!' );
}
}
/**
* gets a type name for an unnamed type
*
* @param string Element name
*
* @return string A type name for an unnamed type
* @access private
*/
function CreateTypeName( $ename ) {
$scope = '';
for ( $i = 0; $i < count( $this->complexTypeStack ); $i ++ ) {
$scope .= $this->complexTypeStack[ $i ] . '_';
}
return $scope . $ename . '_ContainedType';
}
/**
* start-element handler
*
* @param string $parser XML parser object
* @param string $name element name
* @param string $attrs associative array of attributes
*
* @access private
*/
function schemaStartElement( $parser, $name, $attrs ) {
// position in the total number of elements, starting from 0
$pos = $this->position ++;
$depth = $this->depth ++;
// set self as current value for this depth
$this->depth_array[ $depth ] = $pos;
$this->message[ $pos ] = array( 'cdata' => '' );
if ( $depth > 0 ) {
$this->defaultNamespace[ $pos ] = $this->defaultNamespace[ $this->depth_array[ $depth - 1 ] ];
} else {
$this->defaultNamespace[ $pos ] = false;
}
// get element prefix
if ( $prefix = $this->getPrefix( $name ) ) {
// get unqualified name
$name = $this->getLocalPart( $name );
} else {
$prefix = '';
}
// loop thru attributes, expanding, and registering namespace declarations
if ( count( $attrs ) > 0 ) {
foreach ( $attrs as $k => $v ) {
// if ns declarations, add to class level array of valid namespaces
if ( preg_match( '/^xmlns/', $k ) ) {
//$this->xdebug("$k: $v");
//$this->xdebug('ns_prefix: '.$this->getPrefix($k));
if ( $ns_prefix = substr( strrchr( $k, ':' ), 1 ) ) {
//$this->xdebug("Add namespace[$ns_prefix] = $v");
$this->namespaces[ $ns_prefix ] = $v;
} else {
$this->defaultNamespace[ $pos ] = $v;
if ( ! $this->getPrefixFromNamespace( $v ) ) {
$this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $v;
}
}
if ( $v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema' ) {
$this->XMLSchemaVersion = $v;
$this->namespaces['xsi'] = $v . '-instance';
}
}
}
foreach ( $attrs as $k => $v ) {
// expand each attribute
$k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
$v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
$eAttrs[ $k ] = $v;
}
$attrs = $eAttrs;
} else {
$attrs = array();
}
// find status, register data
switch ( $name ) {
case 'all': // (optional) compositor content for a complexType
case 'choice':
case 'group':
case 'sequence':
//$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
$this->complexTypes[ $this->currentComplexType ]['compositor'] = $name;
//if($name == 'all' || $name == 'sequence'){
// $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
//}
break;
case 'attribute': // complexType attribute
//$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
$this->xdebug( "parsing attribute:" );
$this->appendDebug( $this->varDump( $attrs ) );
if ( ! isset( $attrs['form'] ) ) {
// TODO: handle globals
$attrs['form'] = $this->schemaInfo['attributeFormDefault'];
}
if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) ) {
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
if ( ! strpos( $v, ':' ) ) {
// no namespace in arrayType attribute value...
if ( $this->defaultNamespace[ $pos ] ) {
// ...so use the default
$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[ $pos ] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
}
}
}
if ( isset( $attrs['name'] ) ) {
$this->attributes[ $attrs['name'] ] = $attrs;
$aname = $attrs['name'];
} elseif ( isset( $attrs['ref'] ) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType' ) {
if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) ) {
$aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
} else {
$aname = '';
}
} elseif ( isset( $attrs['ref'] ) ) {
$aname = $attrs['ref'];
$this->attributes[ $attrs['ref'] ] = $attrs;
}
if ( $this->currentComplexType ) { // This should *always* be
$this->complexTypes[ $this->currentComplexType ]['attrs'][ $aname ] = $attrs;
}
// arrayType attribute
if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) || $this->getLocalPart( $aname ) == 'arrayType' ) {
$this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
$prefix = $this->getPrefix( $aname );
if ( isset( $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] ) ) {
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
} else {
$v = '';
}
if ( strpos( $v, '[,]' ) ) {
$this->complexTypes[ $this->currentComplexType ]['multidimensional'] = true;
}
$v = substr( $v, 0, strpos( $v, '[' ) ); // clip the []
if ( ! strpos( $v, ':' ) && isset( $this->typemap[ $this->XMLSchemaVersion ][ $v ] ) ) {
$v = $this->XMLSchemaVersion . ':' . $v;
}
$this->complexTypes[ $this->currentComplexType ]['arrayType'] = $v;
}
break;
case 'complexContent': // (optional) content for a complexType
$this->xdebug( "do nothing for element $name" );
break;
case 'complexType':
array_push( $this->complexTypeStack, $this->currentComplexType );
if ( isset( $attrs['name'] ) ) {
// TODO: what is the scope of named complexTypes that appear
// nested within other c complexTypes?
$this->xdebug( 'processing named complexType ' . $attrs['name'] );
//$this->currentElement = false;
$this->currentComplexType = $attrs['name'];
$this->complexTypes[ $this->currentComplexType ] = $attrs;
$this->complexTypes[ $this->currentComplexType ]['typeClass'] = 'complexType';
// This is for constructs like
// <complexType name="ListOfString" base="soap:Array">
// <sequence>
// <element name="string" type="xsd:string"
// minOccurs="0" maxOccurs="unbounded" />
// </sequence>
// </complexType>
if ( isset( $attrs['base'] ) && preg_match( '/:Array$/', $attrs['base'] ) ) {
$this->xdebug( 'complexType is unusual array' );
$this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
} else {
$this->complexTypes[ $this->currentComplexType ]['phpType'] = 'struct';
}
} else {
$name = $this->CreateTypeName( $this->currentElement );
$this->xdebug( 'processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name );
$this->currentComplexType = $name;
//$this->currentElement = false;
$this->complexTypes[ $this->currentComplexType ] = $attrs;
$this->complexTypes[ $this->currentComplexType ]['typeClass'] = 'complexType';
// This is for constructs like
// <complexType name="ListOfString" base="soap:Array">
// <sequence>
// <element name="string" type="xsd:string"
// minOccurs="0" maxOccurs="unbounded" />
// </sequence>
// </complexType>
if ( isset( $attrs['base'] ) && preg_match( '/:Array$/', $attrs['base'] ) ) {
$this->xdebug( 'complexType is unusual array' );
$this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
} else {
$this->complexTypes[ $this->currentComplexType ]['phpType'] = 'struct';
}
}
$this->complexTypes[ $this->currentComplexType ]['simpleContent'] = 'false';
break;
case 'element':
array_push( $this->elementStack, $this->currentElement );
if ( ! isset( $attrs['form'] ) ) {
if ( $this->currentComplexType ) {
$attrs['form'] = $this->schemaInfo['elementFormDefault'];
} else {
// global
$attrs['form'] = 'qualified';
}
}
if ( isset( $attrs['type'] ) ) {
$this->xdebug( "processing typed element " . $attrs['name'] . " of type " . $attrs['type'] );
if ( ! $this->getPrefix( $attrs['type'] ) ) {
if ( $this->defaultNamespace[ $pos ] ) {
$attrs['type'] = $this->defaultNamespace[ $pos ] . ':' . $attrs['type'];
$this->xdebug( 'used default namespace to make type ' . $attrs['type'] );
}
}
// This is for constructs like
// <complexType name="ListOfString" base="soap:Array">
// <sequence>
// <element name="string" type="xsd:string"
// minOccurs="0" maxOccurs="unbounded" />
// </sequence>
// </complexType>
if ( $this->currentComplexType && $this->complexTypes[ $this->currentComplexType ]['phpType'] == 'array' ) {
$this->xdebug( 'arrayType for unusual array is ' . $attrs['type'] );
$this->complexTypes[ $this->currentComplexType ]['arrayType'] = $attrs['type'];
}
$this->currentElement = $attrs['name'];
$ename = $attrs['name'];
} elseif ( isset( $attrs['ref'] ) ) {
$this->xdebug( "processing element as ref to " . $attrs['ref'] );
$this->currentElement = "ref to " . $attrs['ref'];
$ename = $this->getLocalPart( $attrs['ref'] );
} else {
$type = $this->CreateTypeName( $this->currentComplexType . '_' . $attrs['name'] );
$this->xdebug( "processing untyped element " . $attrs['name'] . ' type ' . $type );
$this->currentElement = $attrs['name'];
$attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
$ename = $attrs['name'];
}
if ( isset( $ename ) && $this->currentComplexType ) {
$this->xdebug( "add element $ename to complexType $this->currentComplexType" );
$this->complexTypes[ $this->currentComplexType ]['elements'][ $ename ] = $attrs;
} elseif ( ! isset( $attrs['ref'] ) ) {
$this->xdebug( "add element $ename to elements array" );
$this->elements[ $attrs['name'] ] = $attrs;
$this->elements[ $attrs['name'] ]['typeClass'] = 'element';
}
break;
case 'enumeration': // restriction value list member
$this->xdebug( 'enumeration ' . $attrs['value'] );
if ( $this->currentSimpleType ) {
$this->simpleTypes[ $this->currentSimpleType ]['enumeration'][] = $attrs['value'];
} elseif ( $this->currentComplexType ) {
$this->complexTypes[ $this->currentComplexType ]['enumeration'][] = $attrs['value'];
}
break;
case 'extension': // simpleContent or complexContent type extension
$this->xdebug( 'extension ' . $attrs['base'] );
if ( $this->currentComplexType ) {
$ns = $this->getPrefix( $attrs['base'] );
if ( $ns == '' ) {
$this->complexTypes[ $this->currentComplexType ]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
} else {
$this->complexTypes[ $this->currentComplexType ]['extensionBase'] = $attrs['base'];
}
} else {
$this->xdebug( 'no current complexType to set extensionBase' );
}
break;
case 'import':
if ( isset( $attrs['schemaLocation'] ) ) {
$this->xdebug( 'import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation'] );
$this->imports[ $attrs['namespace'] ][] = array(
'location' => $attrs['schemaLocation'],
'loaded' => false
);
} else {
$this->xdebug( 'import namespace ' . $attrs['namespace'] );
$this->imports[ $attrs['namespace'] ][] = array( 'location' => '', 'loaded' => true );
if ( ! $this->getPrefixFromNamespace( $attrs['namespace'] ) ) {
$this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $attrs['namespace'];
}
}
break;
case 'include':
if ( isset( $attrs['schemaLocation'] ) ) {
$this->xdebug( 'include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation'] );
$this->imports[ $this->schemaTargetNamespace ][] = array(
'location' => $attrs['schemaLocation'],
'loaded' => false
);
} else {
$this->xdebug( 'ignoring invalid XML Schema construct: include without schemaLocation attribute' );
}
break;
case 'list': // simpleType value list
$this->xdebug( "do nothing for element $name" );
break;
case 'restriction': // simpleType, simpleContent or complexContent value restriction
$this->xdebug( 'restriction ' . $attrs['base'] );
if ( $this->currentSimpleType ) {
$this->simpleTypes[ $this->currentSimpleType ]['type'] = $attrs['base'];
} elseif ( $this->currentComplexType ) {
$this->complexTypes[ $this->currentComplexType ]['restrictionBase'] = $attrs['base'];
if ( strstr( $attrs['base'], ':' ) == ':Array' ) {
$this->complexTypes[ $this->currentComplexType ]['phpType'] = 'array';
}
}
break;
case 'schema':
$this->schemaInfo = $attrs;
$this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix( $prefix );
if ( isset( $attrs['targetNamespace'] ) ) {
$this->schemaTargetNamespace = $attrs['targetNamespace'];
}
if ( ! isset( $attrs['elementFormDefault'] ) ) {
$this->schemaInfo['elementFormDefault'] = 'unqualified';
}
if ( ! isset( $attrs['attributeFormDefault'] ) ) {
$this->schemaInfo['attributeFormDefault'] = 'unqualified';
}
break;
case 'simpleContent': // (optional) content for a complexType
if ( $this->currentComplexType ) { // This should *always* be
$this->complexTypes[ $this->currentComplexType ]['simpleContent'] = 'true';
} else {
$this->xdebug( "do nothing for element $name because there is no current complexType" );
}
break;
case 'simpleType':
array_push( $this->simpleTypeStack, $this->currentSimpleType );
if ( isset( $attrs['name'] ) ) {
$this->xdebug( "processing simpleType for name " . $attrs['name'] );
$this->currentSimpleType = $attrs['name'];
$this->simpleTypes[ $attrs['name'] ] = $attrs;
$this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
$this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
} else {
$name = $this->CreateTypeName( $this->currentComplexType . '_' . $this->currentElement );
$this->xdebug( 'processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name );
$this->currentSimpleType = $name;
//$this->currentElement = false;
$this->simpleTypes[ $this->currentSimpleType ] = $attrs;
$this->simpleTypes[ $this->currentSimpleType ]['phpType'] = 'scalar';
}
break;
case 'union': // simpleType type list
$this->xdebug( "do nothing for element $name" );
break;
default:
$this->xdebug( "do not have any logic to process element $name" );
}
}
/**
* end-element handler
*
* @param string $parser XML parser object
* @param string $name element name
*
* @access private
*/
function schemaEndElement( $parser, $name ) {
// bring depth down a notch
$this->depth --;
// position of current element is equal to the last value left in depth_array for my depth
if ( isset( $this->depth_array[ $this->depth ] ) ) {
$pos = $this->depth_array[ $this->depth ];
}
// get element prefix
if ( $prefix = $this->getPrefix( $name ) ) {
// get unqualified name
$name = $this->getLocalPart( $name );
} else {
$prefix = '';
}
// move on...
if ( $name == 'complexType' ) {
$this->xdebug( 'done processing complexType ' . ( $this->currentComplexType ? $this->currentComplexType : '(unknown)' ) );
$this->xdebug( $this->varDump( $this->complexTypes[ $this->currentComplexType ] ) );
$this->currentComplexType = array_pop( $this->complexTypeStack );
//$this->currentElement = false;
}
if ( $name == 'element' ) {
$this->xdebug( 'done processing element ' . ( $this->currentElement ? $this->currentElement : '(unknown)' ) );
$this->currentElement = array_pop( $this->elementStack );
}
if ( $name == 'simpleType' ) {
$this->xdebug( 'done processing simpleType ' . ( $this->currentSimpleType ? $this->currentSimpleType : '(unknown)' ) );
$this->xdebug( $this->varDump( $this->simpleTypes[ $this->currentSimpleType ] ) );
$this->currentSimpleType = array_pop( $this->simpleTypeStack );
}
}
/**
* element content handler
*
* @param string $parser XML parser object
* @param string $data element content
*
* @access private
*/
function schemaCharacterData( $parser, $data ) {
$pos = $this->depth_array[ $this->depth - 1 ];
$this->message[ $pos ]['cdata'] .= $data;
}
/**
* serialize the schema
*
* @access public
*/
function serializeSchema() {
$schemaPrefix = $this->getPrefixFromNamespace( $this->XMLSchemaVersion );
$xml = '';
// imports
if ( sizeof( $this->imports ) > 0 ) {
foreach ( $this->imports as $ns => $list ) {
foreach ( $list as $ii ) {
if ( $ii['location'] != '' ) {
$xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
} else {
$xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
}
}
}
}
// complex types
foreach ( $this->complexTypes as $typeName => $attrs ) {
$contentStr = '';
// serialize child elements
if ( isset( $attrs['elements'] ) && ( count( $attrs['elements'] ) > 0 ) ) {
foreach ( $attrs['elements'] as $element => $eParts ) {
if ( isset( $eParts['ref'] ) ) {
$contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
} else {
$contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName( $eParts['type'] ) . "\"";
foreach ( $eParts as $aName => $aValue ) {
// handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
if ( $aName != 'name' && $aName != 'type' ) {
$contentStr .= " $aName=\"$aValue\"";
}
}
$contentStr .= "/>\n";
}
}
// compositor wraps elements
if ( isset( $attrs['compositor'] ) && ( $attrs['compositor'] != '' ) ) {
$contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " </$schemaPrefix:$attrs[compositor]>\n";
}
}
// attributes
if ( isset( $attrs['attrs'] ) && ( count( $attrs['attrs'] ) >= 1 ) ) {
foreach ( $attrs['attrs'] as $attr => $aParts ) {
$contentStr .= " <$schemaPrefix:attribute";
foreach ( $aParts as $a => $v ) {
if ( $a == 'ref' || $a == 'type' ) {
$contentStr .= " $a=\"" . $this->contractQName( $v ) . '"';
} elseif ( $a == 'http://schemas.xmlsoap.org/wsdl/:arrayType' ) {
$this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
$contentStr .= ' wsdl:arrayType="' . $this->contractQName( $v ) . '"';
} else {
$contentStr .= " $a=\"$v\"";
}
}
$contentStr .= "/>\n";
}
}
// if restriction
if ( isset( $attrs['restrictionBase'] ) && $attrs['restrictionBase'] != '' ) {
$contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName( $attrs['restrictionBase'] ) . "\">\n" . $contentStr . " </$schemaPrefix:restriction>\n";
// complex or simple content
if ( ( isset( $attrs['elements'] ) && count( $attrs['elements'] ) > 0 ) || ( isset( $attrs['attrs'] ) && count( $attrs['attrs'] ) > 0 ) ) {
$contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " </$schemaPrefix:complexContent>\n";
}
}
// finalize complex type
if ( $contentStr != '' ) {
$contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
} else {
$contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
}
$xml .= $contentStr;
}
// simple types
if ( isset( $this->simpleTypes ) && count( $this->simpleTypes ) > 0 ) {
foreach ( $this->simpleTypes as $typeName => $eParts ) {
$xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName( $eParts['type'] ) . "\">\n";
if ( isset( $eParts['enumeration'] ) ) {
foreach ( $eParts['enumeration'] as $e ) {
$xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
}
}
$xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
}
}
// elements
if ( isset( $this->elements ) && count( $this->elements ) > 0 ) {
foreach ( $this->elements as $element => $eParts ) {
$xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName( $eParts['type'] ) . "\"/>\n";
}
}
// attributes
if ( isset( $this->attributes ) && count( $this->attributes ) > 0 ) {
foreach ( $this->attributes as $attr => $aParts ) {
$xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName( $aParts['type'] ) . "\"\n/>";
}
}
// finish 'er up
$attr = '';
foreach ( $this->schemaInfo as $k => $v ) {
if ( $k == 'elementFormDefault' || $k == 'attributeFormDefault' ) {
$attr .= " $k=\"$v\"";
}
}
$el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
foreach ( array_diff( $this->usedNamespaces, $this->enclosingNamespaces ) as $nsp => $ns ) {
$el .= " xmlns:$nsp=\"$ns\"";
}
$xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
return $xml;
}
/**
* adds debug data to the clas level debug string
*
* @param string $string debug data
*
* @access private
*/
function xdebug( $string ) {
$this->debug( '<' . $this->schemaTargetNamespace . '> ' . $string );
}
/**
* get the PHP type of a user defined type in the schema
* PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
* returns false if no type exists, or not w/ the given namespace
* else returns a string that is either a native php type, or 'struct'
*
* @param string $type name of defined type
* @param string $ns namespace of type
*
* @return mixed
* @access public
* @deprecated
*/
function getPHPType( $type, $ns ) {
if ( isset( $this->typemap[ $ns ][ $type ] ) ) {
//print "found type '$type' and ns $ns in typemap<br>";
return $this->typemap[ $ns ][ $type ];
} elseif ( isset( $this->complexTypes[ $type ] ) ) {
//print "getting type '$type' and ns $ns from complexTypes array<br>";
return $this->complexTypes[ $type ]['phpType'];
}
return false;
}
/**
* returns an associative array of information about a given type
* returns false if no type exists by the given name
*
* For a complexType typeDef = array(
* 'restrictionBase' => '',
* 'phpType' => '',
* 'compositor' => '(sequence|all)',
* 'elements' => array(), // refs to elements array
* 'attrs' => array() // refs to attributes array
* ... and so on (see addComplexType)
* )
*
* For simpleType or element, the array has different keys.
*
* @param string $type
*
* @return mixed
* @access public
* @see addComplexType
* @see addSimpleType
* @see addElement
*/
function getTypeDef( $type ) {
//$this->debug("in getTypeDef for type $type");
if ( substr( $type, - 1 ) == '^' ) {
$is_element = 1;
$type = substr( $type, 0, - 1 );
} else {
$is_element = 0;
}
if ( ( ! $is_element ) && isset( $this->complexTypes[ $type ] ) ) {
$this->xdebug( "in getTypeDef, found complexType $type" );
return $this->complexTypes[ $type ];
} elseif ( ( ! $is_element ) && isset( $this->simpleTypes[ $type ] ) ) {
$this->xdebug( "in getTypeDef, found simpleType $type" );
if ( ! isset( $this->simpleTypes[ $type ]['phpType'] ) ) {
// get info for type to tack onto the simple type
// TODO: can this ever really apply (i.e. what is a simpleType really?)
$uqType = substr( $this->simpleTypes[ $type ]['type'], strrpos( $this->simpleTypes[ $type ]['type'], ':' ) + 1 );
$ns = substr( $this->simpleTypes[ $type ]['type'], 0, strrpos( $this->simpleTypes[ $type ]['type'], ':' ) );
$etype = $this->getTypeDef( $uqType );
if ( $etype ) {
$this->xdebug( "in getTypeDef, found type for simpleType $type:" );
$this->xdebug( $this->varDump( $etype ) );
if ( isset( $etype['phpType'] ) ) {
$this->simpleTypes[ $type ]['phpType'] = $etype['phpType'];
}
if ( isset( $etype['elements'] ) ) {
$this->simpleTypes[ $type ]['elements'] = $etype['elements'];
}
}
}
return $this->simpleTypes[ $type ];
} elseif ( isset( $this->elements[ $type ] ) ) {
$this->xdebug( "in getTypeDef, found element $type" );
if ( ! isset( $this->elements[ $type ]['phpType'] ) ) {
// get info for type to tack onto the element
$uqType = substr( $this->elements[ $type ]['type'], strrpos( $this->elements[ $type ]['type'], ':' ) + 1 );
$ns = substr( $this->elements[ $type ]['type'], 0, strrpos( $this->elements[ $type ]['type'], ':' ) );
$etype = $this->getTypeDef( $uqType );
if ( $etype ) {
$this->xdebug( "in getTypeDef, found type for element $type:" );
$this->xdebug( $this->varDump( $etype ) );
if ( isset( $etype['phpType'] ) ) {
$this->elements[ $type ]['phpType'] = $etype['phpType'];
}
if ( isset( $etype['elements'] ) ) {
$this->elements[ $type ]['elements'] = $etype['elements'];
}
if ( isset( $etype['extensionBase'] ) ) {
$this->elements[ $type ]['extensionBase'] = $etype['extensionBase'];
}
} elseif ( $ns == 'http://www.w3.org/2001/XMLSchema' ) {
$this->xdebug( "in getTypeDef, element $type is an XSD type" );
$this->elements[ $type ]['phpType'] = 'scalar';
}
}
return $this->elements[ $type ];
} elseif ( isset( $this->attributes[ $type ] ) ) {
$this->xdebug( "in getTypeDef, found attribute $type" );
return $this->attributes[ $type ];
} elseif ( preg_match( '/_ContainedType$/', $type ) ) {
$this->xdebug( "in getTypeDef, have an untyped element $type" );
$typeDef['typeClass'] = 'simpleType';
$typeDef['phpType'] = 'scalar';
$typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
return $typeDef;
}
$this->xdebug( "in getTypeDef, did not find $type" );
return false;
}
/**
* returns a sample serialization of a given type, or false if no type by the given name
*
* @param string $type name of type
*
* @return mixed
* @access public
* @deprecated
*/
function serializeTypeDef( $type ) {
//print "in sTD() for type $type<br>";
if ( $typeDef = $this->getTypeDef( $type ) ) {
$str .= '<' . $type;
if ( is_array( $typeDef['attrs'] ) ) {
foreach ( $typeDef['attrs'] as $attName => $data ) {
$str .= " $attName=\"{type = " . $data['type'] . "}\"";
}
}
$str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
if ( count( $typeDef['elements'] ) > 0 ) {
$str .= ">";
foreach ( $typeDef['elements'] as $element => $eData ) {
$str .= $this->serializeTypeDef( $element );
}
$str .= "</$type>";
} elseif ( $typeDef['typeClass'] == 'element' ) {
$str .= "></$type>";
} else {
$str .= "/>";
}
return $str;
}
return false;
}
/**
* returns HTML form elements that allow a user
* to enter values for creating an instance of the given type.
*
* @param string $name name for type instance
* @param string $type name of type
*
* @return string
* @access public
* @deprecated
*/
function typeToForm( $name, $type ) {
// get typedef
if ( $typeDef = $this->getTypeDef( $type ) ) {
// if struct
if ( $typeDef['phpType'] == 'struct' ) {
$buffer .= '<table>';
foreach ( $typeDef['elements'] as $child => $childDef ) {
$buffer .= "
<tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart( $childDef['type'] ) . "):</td>
<td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
}
$buffer .= '</table>';
// if array
} elseif ( $typeDef['phpType'] == 'array' ) {
$buffer .= '<table>';
for ( $i = 0; $i < 3; $i ++ ) {
$buffer .= "
<tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
<td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
}
$buffer .= '</table>';
// if scalar
} else {
$buffer .= "<input type='text' name='parameters[$name]'>";
}
} else {
$buffer .= "<input type='text' name='parameters[$name]'>";
}
return $buffer;
}
/**
* adds a complex type to the schema
*
* example: array
*
* addType(
* 'ArrayOfstring',
* 'complexType',
* 'array',
* '',
* 'SOAP-ENC:Array',
* array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
* 'xsd:string'
* );
*
* example: PHP associative array ( SOAP Struct )
*
* addType(
* 'SOAPStruct',
* 'complexType',
* 'struct',
* 'all',
* array('myVar'=> array('name'=>'myVar','type'=>'string')
* );
*
* @param name
* @param typeClass (complexType|simpleType|attribute)
* @param phpType : currently supported are array and struct (php assoc array)
* @param compositor (all|sequence|choice)
* @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param elements = array ( name = array(name=>'',type=>'') )
* @param attrs = array(
* array(
* 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
* "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
* )
* )
* @param arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
*
* @access public
* @see getTypeDef
*/
function addComplexType( $name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '' ) {
$this->complexTypes[ $name ] = array(
'name' => $name,
'typeClass' => $typeClass,
'phpType' => $phpType,
'compositor' => $compositor,
'restrictionBase' => $restrictionBase,
'elements' => $elements,
'attrs' => $attrs,
'arrayType' => $arrayType
);
$this->xdebug( "addComplexType $name:" );
$this->appendDebug( $this->varDump( $this->complexTypes[ $name ] ) );
}
/**
* adds a simple type to the schema
*
* @param string $name
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param string $typeClass (should always be simpleType)
* @param string $phpType (should always be scalar)
* @param array $enumeration array of values
*
* @access public
* @see nusoap_xmlschema
* @see getTypeDef
*/
function addSimpleType( $name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array() ) {
$this->simpleTypes[ $name ] = array(
'name' => $name,
'typeClass' => $typeClass,
'phpType' => $phpType,
'type' => $restrictionBase,
'enumeration' => $enumeration
);
$this->xdebug( "addSimpleType $name:" );
$this->appendDebug( $this->varDump( $this->simpleTypes[ $name ] ) );
}
/**
* adds an element to the schema
*
* @param array $attrs attributes that must include name and type
*
* @see nusoap_xmlschema
* @access public
*/
function addElement( $attrs ) {
if ( ! $this->getPrefix( $attrs['type'] ) ) {
$attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
}
$this->elements[ $attrs['name'] ] = $attrs;
$this->elements[ $attrs['name'] ]['typeClass'] = 'element';
$this->xdebug( "addElement " . $attrs['name'] );
$this->appendDebug( $this->varDump( $this->elements[ $attrs['name'] ] ) );
}
}
/**
* Backward compatibility
*/
class XMLSchema extends nusoap_xmlschema {
}
?><?php
/**
* For creating serializable abstractions of native PHP types. This class
* allows element name/namespace, XSD type, and XML attributes to be
* associated with a value. This is extremely useful when WSDL is not
* used, but is also useful when WSDL is used with polymorphic types, including
* xsd:anyType and user-defined types.
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class soapval extends nusoap_base {
/**
* The XML element name
*
* @var string
* @access private
*/
var $name;
/**
* The XML type name (string or false)
*
* @var mixed
* @access private
*/
var $type;
/**
* The PHP value
*
* @var mixed
* @access private
*/
var $value;
/**
* The XML element namespace (string or false)
*
* @var mixed
* @access private
*/
var $element_ns;
/**
* The XML type namespace (string or false)
*
* @var mixed
* @access private
*/
var $type_ns;
/**
* The XML element attributes (array or false)
*
* @var mixed
* @access private
*/
var $attributes;
/**
* constructor
*
* @param string $name optional name
* @param mixed $type optional type name
* @param mixed $value optional value
* @param mixed $element_ns optional namespace of value
* @param mixed $type_ns optional namespace of type
* @param mixed $attributes associative array of attributes to add to element serialization
*
* @access public
*/
function soapval( $name = 'soapval', $type = false, $value = - 1, $element_ns = false, $type_ns = false, $attributes = false ) {
parent::nusoap_base();
$this->name = $name;
$this->type = $type;
$this->value = $value;
$this->element_ns = $element_ns;
$this->type_ns = $type_ns;
$this->attributes = $attributes;
}
/**
* return serialized value
*
* @param string $use The WSDL use value (encoded|literal)
*
* @return string XML data
* @access public
*/
function serialize( $use = 'encoded' ) {
return $this->serialize_val( $this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true );
}
/**
* decodes a soapval object into a PHP native type
*
* @return mixed
* @access public
*/
function decode() {
return $this->value;
}
}
?><?php
/**
* transport class for sending/receiving data via HTTP and HTTPS
* NOTE: PHP must be compiled with the CURL extension for HTTPS support
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class soap_transport_http extends nusoap_base {
var $url = '';
var $uri = '';
var $digest_uri = '';
var $scheme = '';
var $host = '';
var $port = '';
var $path = '';
var $request_method = 'POST';
var $protocol_version = '1.0';
var $encoding = '';
var $outgoing_headers = array();
var $incoming_headers = array();
var $incoming_cookies = array();
var $outgoing_payload = '';
var $incoming_payload = '';
var $response_status_line; // HTTP response status line
var $useSOAPAction = true;
var $persistentConnection = false;
var $ch = false; // cURL handle
var $ch_options = array(); // cURL custom options
var $use_curl = false; // force cURL use
var $proxy = null; // proxy information (associative array)
var $username = '';
var $password = '';
var $authtype = '';
var $digestRequest = array();
var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
// cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
// sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
// sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
// passphrase: SSL key password/passphrase
// certpassword: SSL certificate password
// verifypeer: default is 1
// verifyhost: default is 1
/**
* constructor
*
* @param string $url The URL to which to connect
* @param array $curl_options User-specified cURL options
* @param boolean $use_curl Whether to try to force cURL use
*
* @access public
*/
function soap_transport_http( $url, $curl_options = null, $use_curl = false ) {
parent::nusoap_base();
$this->debug( "ctor url=$url use_curl=$use_curl curl_options:" );
$this->appendDebug( $this->varDump( $curl_options ) );
$this->setURL( $url );
if ( is_array( $curl_options ) ) {
$this->ch_options = $curl_options;
}
$this->use_curl = $use_curl;
preg_match( '/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev );
$this->setHeader( 'User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')' );
}
/**
* sets a cURL option
*
* @param mixed $option The cURL option (always integer?)
* @param mixed $value The cURL option value
*
* @access private
*/
function setCurlOption( $option, $value ) {
$this->debug( "setCurlOption option=$option, value=" );
$this->appendDebug( $this->varDump( $value ) );
curl_setopt( $this->ch, $option, $value );
}
/**
* sets an HTTP header
*
* @param string $name The name of the header
* @param string $value The value of the header
*
* @access private
*/
function setHeader( $name, $value ) {
$this->outgoing_headers[ $name ] = $value;
$this->debug( "set header $name: $value" );
}
/**
* unsets an HTTP header
*
* @param string $name The name of the header
*
* @access private
*/
function unsetHeader( $name ) {
if ( isset( $this->outgoing_headers[ $name ] ) ) {
$this->debug( "unset header $name" );
unset( $this->outgoing_headers[ $name ] );
}
}
/**
* sets the URL to which to connect
*
* @param string $url The URL to which to connect
*
* @access private
*/
function setURL( $url ) {
$this->url = $url;
$u = parse_url( $url );
foreach ( $u as $k => $v ) {
$this->debug( "parsed URL $k = $v" );
$this->$k = $v;
}
// add any GET params to path
if ( isset( $u['query'] ) && $u['query'] != '' ) {
$this->path .= '?' . $u['query'];
}
// set default port
if ( ! isset( $u['port'] ) ) {
if ( $u['scheme'] == 'https' ) {
$this->port = 443;
} else {
$this->port = 80;
}
}
$this->uri = $this->path;
$this->digest_uri = $this->uri;
// build headers
if ( ! isset( $u['port'] ) ) {
$this->setHeader( 'Host', $this->host );
} else {
$this->setHeader( 'Host', $this->host . ':' . $this->port );
}
if ( isset( $u['user'] ) && $u['user'] != '' ) {
$this->setCredentials( urldecode( $u['user'] ), isset( $u['pass'] ) ? urldecode( $u['pass'] ) : '' );
}
}
/**
* gets the I/O method to use
*
* @return string I/O method to use (socket|curl|unknown)
* @access private
*/
function io_method() {
if ( $this->use_curl || ( $this->scheme == 'https' ) || ( $this->scheme == 'http' && $this->authtype == 'ntlm' ) || ( $this->scheme == 'http' && is_array( $this->proxy ) && $this->proxy['authtype'] == 'ntlm' ) ) {
return 'curl';
}
if ( ( $this->scheme == 'http' || $this->scheme == 'ssl' ) && $this->authtype != 'ntlm' && ( ! is_array( $this->proxy ) || $this->proxy['authtype'] != 'ntlm' ) ) {
return 'socket';
}
return 'unknown';
}
/**
* establish an HTTP connection
*
* @param integer $timeout set connection timeout in seconds
* @param integer $response_timeout set response timeout in seconds
*
* @return boolean true if connected, false if not
* @access private
*/
function connect( $connection_timeout = 0, $response_timeout = 30 ) {
// For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
// "regular" socket.
// TODO: disabled for now because OpenSSL must be *compiled* in (not just
// loaded), and until PHP5 stream_get_wrappers is not available.
// if ($this->scheme == 'https') {
// if (version_compare(phpversion(), '4.3.0') >= 0) {
// if (extension_loaded('openssl')) {
// $this->scheme = 'ssl';
// $this->debug('Using SSL over OpenSSL');
// }
// }
// }
$this->debug( "connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port" );
if ( $this->io_method() == 'socket' ) {
if ( ! is_array( $this->proxy ) ) {
$host = $this->host;
$port = $this->port;
} else {
$host = $this->proxy['host'];
$port = $this->proxy['port'];
}
// use persistent connection
if ( $this->persistentConnection && isset( $this->fp ) && is_resource( $this->fp ) ) {
if ( ! feof( $this->fp ) ) {
$this->debug( 'Re-use persistent connection' );
return true;
}
fclose( $this->fp );
$this->debug( 'Closed persistent connection at EOF' );
}
// munge host if using OpenSSL
if ( $this->scheme == 'ssl' ) {
$host = 'ssl://' . $host;
}
$this->debug( 'calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout );
// open socket
if ( $connection_timeout > 0 ) {
$this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout );
} else {
$this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str );
}
// test pointer
if ( ! $this->fp ) {
$msg = 'Couldn\'t open socket connection to server ' . $this->url;
if ( $this->errno ) {
$msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
} else {
$msg .= ' prior to connect(). This is often a problem looking up the host name.';
}
$this->debug( $msg );
$this->setError( $msg );
return false;
}
// set response timeout
$this->debug( 'set response timeout to ' . $response_timeout );
socket_set_timeout( $this->fp, $response_timeout );
$this->debug( 'socket connected' );
return true;
} else if ( $this->io_method() == 'curl' ) {
if ( ! extension_loaded( 'curl' ) ) {
// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
$this->setError( 'The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.' );
return false;
}
// Avoid warnings when PHP does not have these options
if ( defined( 'CURLOPT_CONNECTIONTIMEOUT' ) ) {
$CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
} else {
$CURLOPT_CONNECTIONTIMEOUT = 78;
}
if ( defined( 'CURLOPT_HTTPAUTH' ) ) {
$CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
} else {
$CURLOPT_HTTPAUTH = 107;
}
if ( defined( 'CURLOPT_PROXYAUTH' ) ) {
$CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
} else {
$CURLOPT_PROXYAUTH = 111;
}
if ( defined( 'CURLAUTH_BASIC' ) ) {
$CURLAUTH_BASIC = CURLAUTH_BASIC;
} else {
$CURLAUTH_BASIC = 1;
}
if ( defined( 'CURLAUTH_DIGEST' ) ) {
$CURLAUTH_DIGEST = CURLAUTH_DIGEST;
} else {
$CURLAUTH_DIGEST = 2;
}
if ( defined( 'CURLAUTH_NTLM' ) ) {
$CURLAUTH_NTLM = CURLAUTH_NTLM;
} else {
$CURLAUTH_NTLM = 8;
}
$this->debug( 'connect using cURL' );
// init CURL
$this->ch = curl_init();
// set url
$hostURL = ( $this->port != '' ) ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
// add path
$hostURL .= $this->path;
$this->setCurlOption( CURLOPT_URL, $hostURL );
// follow location headers (re-directs)
if ( ini_get( 'safe_mode' ) || ini_get( 'open_basedir' ) ) {
$this->debug( 'safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION' );
$this->debug( 'safe_mode = ' );
$this->appendDebug( $this->varDump( ini_get( 'safe_mode' ) ) );
$this->debug( 'open_basedir = ' );
$this->appendDebug( $this->varDump( ini_get( 'open_basedir' ) ) );
} else {
$this->setCurlOption( CURLOPT_FOLLOWLOCATION, 1 );
}
// ask for headers in the response output
$this->setCurlOption( CURLOPT_HEADER, 1 );
// ask for the response output as the return value
$this->setCurlOption( CURLOPT_RETURNTRANSFER, 1 );
// encode
// We manage this ourselves through headers and encoding
// if(function_exists('gzuncompress')){
// $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
// }
// persistent connection
if ( $this->persistentConnection ) {
// I believe the following comment is now bogus, having applied to
// the code when it used CURLOPT_CUSTOMREQUEST to send the request.
// The way we send data, we cannot use persistent connections, since
// there will be some "junk" at the end of our request.
//$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
$this->persistentConnection = false;
$this->setHeader( 'Connection', 'close' );
}
// set timeouts
if ( $connection_timeout != 0 ) {
$this->setCurlOption( $CURLOPT_CONNECTIONTIMEOUT, $connection_timeout );
}
if ( $response_timeout != 0 ) {
$this->setCurlOption( CURLOPT_TIMEOUT, $response_timeout );
}
if ( $this->scheme == 'https' ) {
$this->debug( 'set cURL SSL verify options' );
// recent versions of cURL turn on peer/host checking by default,
// while PHP binaries are not compiled with a default location for the
// CA cert bundle, so disable peer/host checking.
//$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
$this->setCurlOption( CURLOPT_SSL_VERIFYPEER, 0 );
$this->setCurlOption( CURLOPT_SSL_VERIFYHOST, 0 );
// support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
if ( $this->authtype == 'certificate' ) {
$this->debug( 'set cURL certificate options' );
if ( isset( $this->certRequest['cainfofile'] ) ) {
$this->setCurlOption( CURLOPT_CAINFO, $this->certRequest['cainfofile'] );
}
if ( isset( $this->certRequest['verifypeer'] ) ) {
$this->setCurlOption( CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer'] );
} else {
$this->setCurlOption( CURLOPT_SSL_VERIFYPEER, 1 );
}
if ( isset( $this->certRequest['verifyhost'] ) ) {
$this->setCurlOption( CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost'] );
} else {
$this->setCurlOption( CURLOPT_SSL_VERIFYHOST, 1 );
}
if ( isset( $this->certRequest['sslcertfile'] ) ) {
$this->setCurlOption( CURLOPT_SSLCERT, $this->certRequest['sslcertfile'] );
}
if ( isset( $this->certRequest['sslkeyfile'] ) ) {
$this->setCurlOption( CURLOPT_SSLKEY, $this->certRequest['sslkeyfile'] );
}
if ( isset( $this->certRequest['passphrase'] ) ) {
$this->setCurlOption( CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase'] );
}
if ( isset( $this->certRequest['certpassword'] ) ) {
$this->setCurlOption( CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword'] );
}
}
}
if ( $this->authtype && ( $this->authtype != 'certificate' ) ) {
if ( $this->username ) {
$this->debug( 'set cURL username/password' );
$this->setCurlOption( CURLOPT_USERPWD, "$this->username:$this->password" );
}
if ( $this->authtype == 'basic' ) {
$this->debug( 'set cURL for Basic authentication' );
$this->setCurlOption( $CURLOPT_HTTPAUTH, $CURLAUTH_BASIC );
}
if ( $this->authtype == 'digest' ) {
$this->debug( 'set cURL for digest authentication' );
$this->setCurlOption( $CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST );
}
if ( $this->authtype == 'ntlm' ) {
$this->debug( 'set cURL for NTLM authentication' );
$this->setCurlOption( $CURLOPT_HTTPAUTH, $CURLAUTH_NTLM );
}
}
if ( is_array( $this->proxy ) ) {
$this->debug( 'set cURL proxy options' );
if ( $this->proxy['port'] != '' ) {
$this->setCurlOption( CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port'] );
} else {
$this->setCurlOption( CURLOPT_PROXY, $this->proxy['host'] );
}
if ( $this->proxy['username'] || $this->proxy['password'] ) {
$this->debug( 'set cURL proxy authentication options' );
$this->setCurlOption( CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password'] );
if ( $this->proxy['authtype'] == 'basic' ) {
$this->setCurlOption( $CURLOPT_PROXYAUTH, $CURLAUTH_BASIC );
}
if ( $this->proxy['authtype'] == 'ntlm' ) {
$this->setCurlOption( $CURLOPT_PROXYAUTH, $CURLAUTH_NTLM );
}
}
}
$this->debug( 'cURL connection set up' );
return true;
} else {
$this->setError( 'Unknown scheme ' . $this->scheme );
$this->debug( 'Unknown scheme ' . $this->scheme );
return false;
}
}
/**
* sends the SOAP request and gets the SOAP response via HTTP[S]
*
* @param string $data message data
* @param integer $timeout set connection timeout in seconds
* @param integer $response_timeout set response timeout in seconds
* @param array $cookies cookies to send
*
* @return string data
* @access public
*/
function send( $data, $timeout = 0, $response_timeout = 30, $cookies = null ) {
$this->debug( 'entered send() with data of length: ' . strlen( $data ) );
$this->tryagain = true;
$tries = 0;
while ( $this->tryagain ) {
$this->tryagain = false;
if ( $tries ++ < 2 ) {
// make connnection
if ( ! $this->connect( $timeout, $response_timeout ) ) {
return false;
}
// send request
if ( ! $this->sendRequest( $data, $cookies ) ) {
return false;
}
// get response
$respdata = $this->getResponse();
} else {
$this->setError( "Too many tries to get an OK response ($this->response_status_line)" );
}
}
$this->debug( 'end of send()' );
return $respdata;
}
/**
* sends the SOAP request and gets the SOAP response via HTTPS using CURL
*
* @param string $data message data
* @param integer $timeout set connection timeout in seconds
* @param integer $response_timeout set response timeout in seconds
* @param array $cookies cookies to send
*
* @return string data
* @access public
* @deprecated
*/
function sendHTTPS( $data, $timeout = 0, $response_timeout = 30, $cookies ) {
return $this->send( $data, $timeout, $response_timeout, $cookies );
}
/**
* if authenticating, set user credentials here
*
* @param string $username
* @param string $password
* @param string $authtype (basic|digest|certificate|ntlm)
* @param array $digestRequest (keys must be nonce, nc, realm, qop)
* @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
*
* @access public
*/
function setCredentials( $username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array() ) {
$this->debug( "setCredentials username=$username authtype=$authtype digestRequest=" );
$this->appendDebug( $this->varDump( $digestRequest ) );
$this->debug( "certRequest=" );
$this->appendDebug( $this->varDump( $certRequest ) );
// cf. RFC 2617
if ( $authtype == 'basic' ) {
$this->setHeader( 'Authorization', 'Basic ' . base64_encode( str_replace( ':', '', $username ) . ':' . $password ) );
} elseif ( $authtype == 'digest' ) {
if ( isset( $digestRequest['nonce'] ) ) {
$digestRequest['nc'] = isset( $digestRequest['nc'] ) ? $digestRequest['nc'] ++ : 1;
// calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
// A1 = unq(username-value) ":" unq(realm-value) ":" passwd
$A1 = $username . ':' . ( isset( $digestRequest['realm'] ) ? $digestRequest['realm'] : '' ) . ':' . $password;
// H(A1) = MD5(A1)
$HA1 = md5( $A1 );
// A2 = Method ":" digest-uri-value
$A2 = $this->request_method . ':' . $this->digest_uri;
// H(A2)
$HA2 = md5( $A2 );
// KD(secret, data) = H(concat(secret, ":", data))
// if qop == auth:
// request-digest = <"> < KD ( H(A1), unq(nonce-value)
// ":" nc-value
// ":" unq(cnonce-value)
// ":" unq(qop-value)
// ":" H(A2)
// ) <">
// if qop is missing,
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
$unhashedDigest = '';
$nonce = isset( $digestRequest['nonce'] ) ? $digestRequest['nonce'] : '';
$cnonce = $nonce;
if ( $digestRequest['qop'] != '' ) {
$unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf( "%08d", $digestRequest['nc'] ) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
} else {
$unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
}
$hashedDigest = md5( $unhashedDigest );
$opaque = '';
if ( isset( $digestRequest['opaque'] ) ) {
$opaque = ', opaque="' . $digestRequest['opaque'] . '"';
}
$this->setHeader( 'Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf( "%08x", $digestRequest['nc'] ) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"' );
}
} elseif ( $authtype == 'certificate' ) {
$this->certRequest = $certRequest;
$this->debug( 'Authorization header not set for certificate' );
} elseif ( $authtype == 'ntlm' ) {
// do nothing
$this->debug( 'Authorization header not set for ntlm' );
}
$this->username = $username;
$this->password = $password;
$this->authtype = $authtype;
$this->digestRequest = $digestRequest;
}
/**
* set the soapaction value
*
* @param string $soapaction
*
* @access public
*/
function setSOAPAction( $soapaction ) {
$this->setHeader( 'SOAPAction', '"' . $soapaction . '"' );
}
/**
* use http encoding
*
* @param string $enc encoding style. supported values: gzip, deflate, or both
*
* @access public
*/
function setEncoding( $enc = 'gzip, deflate' ) {
if ( function_exists( 'gzdeflate' ) ) {
$this->protocol_version = '1.1';
$this->setHeader( 'Accept-Encoding', $enc );
if ( ! isset( $this->outgoing_headers['Connection'] ) ) {
$this->setHeader( 'Connection', 'close' );
$this->persistentConnection = false;
}
// deprecated as of PHP 5.3.0
//set_magic_quotes_runtime(0);
$this->encoding = $enc;
}
}
/**
* set proxy info here
*
* @param string $proxyhost use an empty string to remove proxy
* @param string $proxyport
* @param string $proxyusername
* @param string $proxypassword
* @param string $proxyauthtype (basic|ntlm)
*
* @access public
*/
function setProxy( $proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic' ) {
if ( $proxyhost ) {
$this->proxy = array(
'host' => $proxyhost,
'port' => $proxyport,
'username' => $proxyusername,
'password' => $proxypassword,
'authtype' => $proxyauthtype
);
if ( $proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic' ) {
$this->setHeader( 'Proxy-Authorization', ' Basic ' . base64_encode( $proxyusername . ':' . $proxypassword ) );
}
} else {
$this->debug( 'remove proxy' );
$proxy = null;
unsetHeader( 'Proxy-Authorization' );
}
}
/**
* Test if the given string starts with a header that is to be skipped.
* Skippable headers result from chunked transfer and proxy requests.
*
* @param string $data The string to check.
*
* @returns boolean Whether a skippable header was found.
* @access private
*/
function isSkippableCurlHeader( &$data ) {
$skipHeaders = array(
'HTTP/1.1 100',
'HTTP/1.0 301',
'HTTP/1.1 301',
'HTTP/1.0 302',
'HTTP/1.1 302',
'HTTP/1.0 401',
'HTTP/1.1 401',
'HTTP/1.0 200 Connection established'
);
foreach ( $skipHeaders as $hd ) {
$prefix = substr( $data, 0, strlen( $hd ) );
if ( $prefix == $hd ) {
return true;
}
}
return false;
}
/**
* decode a string that is encoded w/ "chunked' transfer encoding
* as defined in RFC2068 19.4.6
*
* @param string $buffer
* @param string $lb
*
* @returns string
* @access public
* @deprecated
*/
function decodeChunked( $buffer, $lb ) {
// length := 0
$length = 0;
$new = '';
// read chunk-size, chunk-extension (if any) and CRLF
// get the position of the linebreak
$chunkend = strpos( $buffer, $lb );
if ( $chunkend == false ) {
$this->debug( 'no linebreak found in decodeChunked' );
return $new;
}
$temp = substr( $buffer, 0, $chunkend );
$chunk_size = hexdec( trim( $temp ) );
$chunkstart = $chunkend + strlen( $lb );
// while (chunk-size > 0) {
while ( $chunk_size > 0 ) {
$this->debug( "chunkstart: $chunkstart chunk_size: $chunk_size" );
$chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size );
// Just in case we got a broken connection
if ( $chunkend == false ) {
$chunk = substr( $buffer, $chunkstart );
// append chunk-data to entity-body
$new .= $chunk;
$length += strlen( $chunk );
break;
}
// read chunk-data and CRLF
$chunk = substr( $buffer, $chunkstart, $chunkend - $chunkstart );
// append chunk-data to entity-body
$new .= $chunk;
// length := length + chunk-size
$length += strlen( $chunk );
// read chunk-size and CRLF
$chunkstart = $chunkend + strlen( $lb );
$chunkend = strpos( $buffer, $lb, $chunkstart ) + strlen( $lb );
if ( $chunkend == false ) {
break; //Just in case we got a broken connection
}
$temp = substr( $buffer, $chunkstart, $chunkend - $chunkstart );
$chunk_size = hexdec( trim( $temp ) );
$chunkstart = $chunkend;
}
return $new;
}
/**
* Writes the payload, including HTTP headers, to $this->outgoing_payload.
*
* @param string $data HTTP body
* @param string $cookie_str data for HTTP Cookie header
*
* @return void
* @access private
*/
function buildPayload( $data, $cookie_str = '' ) {
// Note: for cURL connections, $this->outgoing_payload is ignored,
// as is the Content-Length header, but these are still created as
// debugging guides.
// add content-length header
if ( $this->request_method != 'GET' ) {
$this->setHeader( 'Content-Length', strlen( $data ) );
}
// start building outgoing payload:
if ( $this->proxy ) {
$uri = $this->url;
} else {
$uri = $this->uri;
}
$req = "$this->request_method $uri HTTP/$this->protocol_version";
$this->debug( "HTTP request: $req" );
$this->outgoing_payload = "$req\r\n";
// loop thru headers, serializing
foreach ( $this->outgoing_headers as $k => $v ) {
$hdr = $k . ': ' . $v;
$this->debug( "HTTP header: $hdr" );
$this->outgoing_payload .= "$hdr\r\n";
}
// add any cookies
if ( $cookie_str != '' ) {
$hdr = 'Cookie: ' . $cookie_str;
$this->debug( "HTTP header: $hdr" );
$this->outgoing_payload .= "$hdr\r\n";
}
// header/body separator
$this->outgoing_payload .= "\r\n";
// add data
$this->outgoing_payload .= $data;
}
/**
* sends the SOAP request via HTTP[S]
*
* @param string $data message data
* @param array $cookies cookies to send
*
* @return boolean true if OK, false if problem
* @access private
*/
function sendRequest( $data, $cookies = null ) {
// build cookie string
$cookie_str = $this->getCookiesForRequest( $cookies, ( ( $this->scheme == 'ssl' ) || ( $this->scheme == 'https' ) ) );
// build payload
$this->buildPayload( $data, $cookie_str );
if ( $this->io_method() == 'socket' ) {
// send payload
if ( ! fputs( $this->fp, $this->outgoing_payload, strlen( $this->outgoing_payload ) ) ) {
$this->setError( 'couldn\'t write message data to socket' );
$this->debug( 'couldn\'t write message data to socket' );
return false;
}
$this->debug( 'wrote data to socket, length = ' . strlen( $this->outgoing_payload ) );
return true;
} else if ( $this->io_method() == 'curl' ) {
// set payload
// cURL does say this should only be the verb, and in fact it
// turns out that the URI and HTTP version are appended to this, which
// some servers refuse to work with (so we no longer use this method!)
//$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
$curl_headers = array();
foreach ( $this->outgoing_headers as $k => $v ) {
if ( $k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization' ) {
$this->debug( "Skip cURL header $k: $v" );
} else {
$curl_headers[] = "$k: $v";
}
}
if ( $cookie_str != '' ) {
$curl_headers[] = 'Cookie: ' . $cookie_str;
}
$this->setCurlOption( CURLOPT_HTTPHEADER, $curl_headers );
$this->debug( 'set cURL HTTP headers' );
if ( $this->request_method == "POST" ) {
$this->setCurlOption( CURLOPT_POST, 1 );
$this->setCurlOption( CURLOPT_POSTFIELDS, $data );
$this->debug( 'set cURL POST data' );
} else {
}
// insert custom user-set cURL options
foreach ( $this->ch_options as $key => $val ) {
$this->setCurlOption( $key, $val );
}
$this->debug( 'set cURL payload' );
return true;
}
}
/**
* gets the SOAP response via HTTP[S]
*
* @return string the response (also sets member variables like incoming_payload)
* @access private
*/
function getResponse() {
$this->incoming_payload = '';
if ( $this->io_method() == 'socket' ) {
// loop until headers have been retrieved
$data = '';
while ( ! isset( $lb ) ) {
// We might EOF during header read.
if ( feof( $this->fp ) ) {
$this->incoming_payload = $data;
$this->debug( 'found no headers before EOF after length ' . strlen( $data ) );
$this->debug( "received before EOF:\n" . $data );
$this->setError( 'server failed to send headers' );
return false;
}
$tmp = fgets( $this->fp, 256 );
$tmplen = strlen( $tmp );
$this->debug( "read line of $tmplen bytes: " . trim( $tmp ) );
if ( $tmplen == 0 ) {
$this->incoming_payload = $data;
$this->debug( 'socket read of headers timed out after length ' . strlen( $data ) );
$this->debug( "read before timeout: " . $data );
$this->setError( 'socket read of headers timed out' );
return false;
}
$data .= $tmp;
$pos = strpos( $data, "\r\n\r\n" );
if ( $pos > 1 ) {
$lb = "\r\n";
} else {
$pos = strpos( $data, "\n\n" );
if ( $pos > 1 ) {
$lb = "\n";
}
}
// remove 100 headers
if ( isset( $lb ) && preg_match( '/^HTTP\/1.1 100/', $data ) ) {
unset( $lb );
$data = '';
}//
}
// store header data
$this->incoming_payload .= $data;
$this->debug( 'found end of headers after length ' . strlen( $data ) );
// process headers
$header_data = trim( substr( $data, 0, $pos ) );
$header_array = explode( $lb, $header_data );
$this->incoming_headers = array();
$this->incoming_cookies = array();
foreach ( $header_array as $header_line ) {
$arr = explode( ':', $header_line, 2 );
if ( count( $arr ) > 1 ) {
$header_name = strtolower( trim( $arr[0] ) );
$this->incoming_headers[ $header_name ] = trim( $arr[1] );
if ( $header_name == 'set-cookie' ) {
// TODO: allow multiple cookies from parseCookie
$cookie = $this->parseCookie( trim( $arr[1] ) );
if ( $cookie ) {
$this->incoming_cookies[] = $cookie;
$this->debug( 'found cookie: ' . $cookie['name'] . ' = ' . $cookie['value'] );
} else {
$this->debug( 'did not find cookie in ' . trim( $arr[1] ) );
}
}
} else if ( isset( $header_name ) ) {
// append continuation line to previous header
$this->incoming_headers[ $header_name ] .= $lb . ' ' . $header_line;
}
}
// loop until msg has been received
if ( isset( $this->incoming_headers['transfer-encoding'] ) && strtolower( $this->incoming_headers['transfer-encoding'] ) == 'chunked' ) {
$content_length = 2147483647; // ignore any content-length header
$chunked = true;
$this->debug( "want to read chunked content" );
} elseif ( isset( $this->incoming_headers['content-length'] ) ) {
$content_length = $this->incoming_headers['content-length'];
$chunked = false;
$this->debug( "want to read content of length $content_length" );
} else {
$content_length = 2147483647;
$chunked = false;
$this->debug( "want to read content to EOF" );
}
$data = '';
do {
if ( $chunked ) {
$tmp = fgets( $this->fp, 256 );
$tmplen = strlen( $tmp );
$this->debug( "read chunk line of $tmplen bytes" );
if ( $tmplen == 0 ) {
$this->incoming_payload = $data;
$this->debug( 'socket read of chunk length timed out after length ' . strlen( $data ) );
$this->debug( "read before timeout:\n" . $data );
$this->setError( 'socket read of chunk length timed out' );
return false;
}
$content_length = hexdec( trim( $tmp ) );
$this->debug( "chunk length $content_length" );
}
$strlen = 0;
while ( ( $strlen < $content_length ) && ( ! feof( $this->fp ) ) ) {
$readlen = min( 8192, $content_length - $strlen );
$tmp = fread( $this->fp, $readlen );
$tmplen = strlen( $tmp );
$this->debug( "read buffer of $tmplen bytes" );
if ( ( $tmplen == 0 ) && ( ! feof( $this->fp ) ) ) {
$this->incoming_payload = $data;
$this->debug( 'socket read of body timed out after length ' . strlen( $data ) );
$this->debug( "read before timeout:\n" . $data );
$this->setError( 'socket read of body timed out' );
return false;
}
$strlen += $tmplen;
$data .= $tmp;
}
if ( $chunked && ( $content_length > 0 ) ) {
$tmp = fgets( $this->fp, 256 );
$tmplen = strlen( $tmp );
$this->debug( "read chunk terminator of $tmplen bytes" );
if ( $tmplen == 0 ) {
$this->incoming_payload = $data;
$this->debug( 'socket read of chunk terminator timed out after length ' . strlen( $data ) );
$this->debug( "read before timeout:\n" . $data );
$this->setError( 'socket read of chunk terminator timed out' );
return false;
}
}
} while ( $chunked && ( $content_length > 0 ) && ( ! feof( $this->fp ) ) );
if ( feof( $this->fp ) ) {
$this->debug( 'read to EOF' );
}
$this->debug( 'read body of length ' . strlen( $data ) );
$this->incoming_payload .= $data;
$this->debug( 'received a total of ' . strlen( $this->incoming_payload ) . ' bytes of data from server' );
// close filepointer
if (
( isset( $this->incoming_headers['connection'] ) && strtolower( $this->incoming_headers['connection'] ) == 'close' ) ||
( ! $this->persistentConnection ) || feof( $this->fp ) ) {
fclose( $this->fp );
$this->fp = false;
$this->debug( 'closed socket' );
}
// connection was closed unexpectedly
if ( $this->incoming_payload == '' ) {
$this->setError( 'no response from server' );
return false;
}
// decode transfer-encoding
// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
// if(!$data = $this->decodeChunked($data, $lb)){
// $this->setError('Decoding of chunked data failed');
// return false;
// }
//print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
// set decoded payload
// $this->incoming_payload = $header_data.$lb.$lb.$data;
// }
} else if ( $this->io_method() == 'curl' ) {
// send and receive
$this->debug( 'send and receive with cURL' );
$this->incoming_payload = curl_exec( $this->ch );
$data = $this->incoming_payload;
$cErr = curl_error( $this->ch );
if ( $cErr != '' ) {
$err = 'cURL ERROR: ' . curl_errno( $this->ch ) . ': ' . $cErr . '<br>';
// TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
foreach ( curl_getinfo( $this->ch ) as $k => $v ) {
$err .= "$k: $v<br>";
}
$this->debug( $err );
$this->setError( $err );
curl_close( $this->ch );
return false;
} else {
//echo '<pre>';
//var_dump(curl_getinfo($this->ch));
//echo '</pre>';
}
// close curl
$this->debug( 'No cURL error, closing cURL' );
curl_close( $this->ch );
// try removing skippable headers
$savedata = $data;
while ( $this->isSkippableCurlHeader( $data ) ) {
$this->debug( "Found HTTP header to skip" );
if ( $pos = strpos( $data, "\r\n\r\n" ) ) {
$data = ltrim( substr( $data, $pos ) );
} elseif ( $pos = strpos( $data, "\n\n" ) ) {
$data = ltrim( substr( $data, $pos ) );
}
}
if ( $data == '' ) {
// have nothing left; just remove 100 header(s)
$data = $savedata;
while ( preg_match( '/^HTTP\/1.1 100/', $data ) ) {
if ( $pos = strpos( $data, "\r\n\r\n" ) ) {
$data = ltrim( substr( $data, $pos ) );
} elseif ( $pos = strpos( $data, "\n\n" ) ) {
$data = ltrim( substr( $data, $pos ) );
}
}
}
// separate content from HTTP headers
if ( $pos = strpos( $data, "\r\n\r\n" ) ) {
$lb = "\r\n";
} elseif ( $pos = strpos( $data, "\n\n" ) ) {
$lb = "\n";
} else {
$this->debug( 'no proper separation of headers and document' );
$this->setError( 'no proper separation of headers and document' );
return false;
}
$header_data = trim( substr( $data, 0, $pos ) );
$header_array = explode( $lb, $header_data );
$data = ltrim( substr( $data, $pos ) );
$this->debug( 'found proper separation of headers and document' );
$this->debug( 'cleaned data, stringlen: ' . strlen( $data ) );
// clean headers
foreach ( $header_array as $header_line ) {
$arr = explode( ':', $header_line, 2 );
if ( count( $arr ) > 1 ) {
$header_name = strtolower( trim( $arr[0] ) );
$this->incoming_headers[ $header_name ] = trim( $arr[1] );
if ( $header_name == 'set-cookie' ) {
// TODO: allow multiple cookies from parseCookie
$cookie = $this->parseCookie( trim( $arr[1] ) );
if ( $cookie ) {
$this->incoming_cookies[] = $cookie;
$this->debug( 'found cookie: ' . $cookie['name'] . ' = ' . $cookie['value'] );
} else {
$this->debug( 'did not find cookie in ' . trim( $arr[1] ) );
}
}
} else if ( isset( $header_name ) ) {
// append continuation line to previous header
$this->incoming_headers[ $header_name ] .= $lb . ' ' . $header_line;
}
}
}
$this->response_status_line = $header_array[0];
$arr = explode( ' ', $this->response_status_line, 3 );
$http_version = $arr[0];
$http_status = intval( $arr[1] );
$http_reason = count( $arr ) > 2 ? $arr[2] : '';
// see if we need to resend the request with http digest authentication
if ( isset( $this->incoming_headers['location'] ) && ( $http_status == 301 || $http_status == 302 ) ) {
$this->debug( "Got $http_status $http_reason with Location: " . $this->incoming_headers['location'] );
$this->setURL( $this->incoming_headers['location'] );
$this->tryagain = true;
return false;
}
// see if we need to resend the request with http digest authentication
if ( isset( $this->incoming_headers['www-authenticate'] ) && $http_status == 401 ) {
$this->debug( "Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate'] );
if ( strstr( $this->incoming_headers['www-authenticate'], "Digest " ) ) {
$this->debug( 'Server wants digest authentication' );
// remove "Digest " from our elements
$digestString = str_replace( 'Digest ', '', $this->incoming_headers['www-authenticate'] );
// parse elements into array
$digestElements = explode( ',', $digestString );
foreach ( $digestElements as $val ) {
$tempElement = explode( '=', trim( $val ), 2 );
$digestRequest[ $tempElement[0] ] = str_replace( "\"", '', $tempElement[1] );
}
// should have (at least) qop, realm, nonce
if ( isset( $digestRequest['nonce'] ) ) {
$this->setCredentials( $this->username, $this->password, 'digest', $digestRequest );
$this->tryagain = true;
return false;
}
}
$this->debug( 'HTTP authentication failed' );
$this->setError( 'HTTP authentication failed' );
return false;
}
if (
( $http_status >= 300 && $http_status <= 307 ) ||
( $http_status >= 400 && $http_status <= 417 ) ||
( $http_status >= 501 && $http_status <= 505 )
) {
$this->setError( "Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)" );
return false;
}
// decode content-encoding
if ( isset( $this->incoming_headers['content-encoding'] ) && $this->incoming_headers['content-encoding'] != '' ) {
if ( strtolower( $this->incoming_headers['content-encoding'] ) == 'deflate' || strtolower( $this->incoming_headers['content-encoding'] ) == 'gzip' ) {
// if decoding works, use it. else assume data wasn't gzencoded
if ( function_exists( 'gzinflate' ) ) {
//$timer->setMarker('starting decoding of gzip/deflated content');
// IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
// this means there are no Zlib headers, although there should be
$this->debug( 'The gzinflate function exists' );
$datalen = strlen( $data );
if ( $this->incoming_headers['content-encoding'] == 'deflate' ) {
if ( $degzdata = @gzinflate( $data ) ) {
$data = $degzdata;
$this->debug( 'The payload has been inflated to ' . strlen( $data ) . ' bytes' );
if ( strlen( $data ) < $datalen ) {
// test for the case that the payload has been compressed twice
$this->debug( 'The inflated payload is smaller than the gzipped one; try again' );
if ( $degzdata = @gzinflate( $data ) ) {
$data = $degzdata;
$this->debug( 'The payload has been inflated again to ' . strlen( $data ) . ' bytes' );
}
}
} else {
$this->debug( 'Error using gzinflate to inflate the payload' );
$this->setError( 'Error using gzinflate to inflate the payload' );
}
} elseif ( $this->incoming_headers['content-encoding'] == 'gzip' ) {
if ( $degzdata = @gzinflate( substr( $data, 10 ) ) ) { // do our best
$data = $degzdata;
$this->debug( 'The payload has been un-gzipped to ' . strlen( $data ) . ' bytes' );
if ( strlen( $data ) < $datalen ) {
// test for the case that the payload has been compressed twice
$this->debug( 'The un-gzipped payload is smaller than the gzipped one; try again' );
if ( $degzdata = @gzinflate( substr( $data, 10 ) ) ) {
$data = $degzdata;
$this->debug( 'The payload has been un-gzipped again to ' . strlen( $data ) . ' bytes' );
}
}
} else {
$this->debug( 'Error using gzinflate to un-gzip the payload' );
$this->setError( 'Error using gzinflate to un-gzip the payload' );
}
}
//$timer->setMarker('finished decoding of gzip/deflated content');
//print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
// set decoded payload
$this->incoming_payload = $header_data . $lb . $lb . $data;
} else {
$this->debug( 'The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.' );
$this->setError( 'The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.' );
}
} else {
$this->debug( 'Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding'] );
$this->setError( 'Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding'] );
}
} else {
$this->debug( 'No Content-Encoding header' );
}
if ( strlen( $data ) == 0 ) {
$this->debug( 'no data after headers!' );
$this->setError( 'no data present after HTTP headers' );
return false;
}
return $data;
}
/**
* sets the content-type for the SOAP message to be sent
*
* @param string $type the content type, MIME style
* @param mixed $charset character set used for encoding (or false)
*
* @access public
*/
function setContentType( $type, $charset = false ) {
$this->setHeader( 'Content-Type', $type . ( $charset ? '; charset=' . $charset : '' ) );
}
/**
* specifies that an HTTP persistent connection should be used
*
* @return boolean whether the request was honored by this method.
* @access public
*/
function usePersistentConnection() {
if ( isset( $this->outgoing_headers['Accept-Encoding'] ) ) {
return false;
}
$this->protocol_version = '1.1';
$this->persistentConnection = true;
$this->setHeader( 'Connection', 'Keep-Alive' );
return true;
}
/**
* parse an incoming Cookie into it's parts
*
* @param string $cookie_str content of cookie
*
* @return array with data of that cookie
* @access private
*/
/*
* TODO: allow a Set-Cookie string to be parsed into multiple cookies
*/
function parseCookie( $cookie_str ) {
$cookie_str = str_replace( '; ', ';', $cookie_str ) . ';';
$data = preg_split( '/;/', $cookie_str );
$value_str = $data[0];
$cookie_param = 'domain=';
$start = strpos( $cookie_str, $cookie_param );
if ( $start > 0 ) {
$domain = substr( $cookie_str, $start + strlen( $cookie_param ) );
$domain = substr( $domain, 0, strpos( $domain, ';' ) );
} else {
$domain = '';
}
$cookie_param = 'expires=';
$start = strpos( $cookie_str, $cookie_param );
if ( $start > 0 ) {
$expires = substr( $cookie_str, $start + strlen( $cookie_param ) );
$expires = substr( $expires, 0, strpos( $expires, ';' ) );
} else {
$expires = '';
}
$cookie_param = 'path=';
$start = strpos( $cookie_str, $cookie_param );
if ( $start > 0 ) {
$path = substr( $cookie_str, $start + strlen( $cookie_param ) );
$path = substr( $path, 0, strpos( $path, ';' ) );
} else {
$path = '/';
}
$cookie_param = ';secure;';
if ( strpos( $cookie_str, $cookie_param ) !== false ) {
$secure = true;
} else {
$secure = false;
}
$sep_pos = strpos( $value_str, '=' );
if ( $sep_pos ) {
$name = substr( $value_str, 0, $sep_pos );
$value = substr( $value_str, $sep_pos + 1 );
$cookie = array(
'name' => $name,
'value' => $value,
'domain' => $domain,
'path' => $path,
'expires' => $expires,
'secure' => $secure
);
return $cookie;
}
return false;
}
/**
* sort out cookies for the current request
*
* @param array $cookies array with all cookies
* @param boolean $secure is the send-content secure or not?
*
* @return string for Cookie-HTTP-Header
* @access private
*/
function getCookiesForRequest( $cookies, $secure = false ) {
$cookie_str = '';
if ( ( ! is_null( $cookies ) ) && ( is_array( $cookies ) ) ) {
foreach ( $cookies as $cookie ) {
if ( ! is_array( $cookie ) ) {
continue;
}
$this->debug( "check cookie for validity: " . $cookie['name'] . '=' . $cookie['value'] );
if ( ( isset( $cookie['expires'] ) ) && ( ! empty( $cookie['expires'] ) ) ) {
if ( strtotime( $cookie['expires'] ) <= time() ) {
$this->debug( 'cookie has expired' );
continue;
}
}
if ( ( isset( $cookie['domain'] ) ) && ( ! empty( $cookie['domain'] ) ) ) {
$domain = preg_quote( $cookie['domain'] );
if ( ! preg_match( "'.*$domain$'i", $this->host ) ) {
$this->debug( 'cookie has different domain' );
continue;
}
}
if ( ( isset( $cookie['path'] ) ) && ( ! empty( $cookie['path'] ) ) ) {
$path = preg_quote( $cookie['path'] );
if ( ! preg_match( "'^$path.*'i", $this->path ) ) {
$this->debug( 'cookie is for a different path' );
continue;
}
}
if ( ( ! $secure ) && ( isset( $cookie['secure'] ) ) && ( $cookie['secure'] ) ) {
$this->debug( 'cookie is secure, transport is not' );
continue;
}
$cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
$this->debug( 'add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value'] );
}
}
return $cookie_str;
}
}
?><?php
/**
*
* nusoap_server allows the user to create a SOAP server
* that is capable of receiving messages and returning responses
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_server extends nusoap_base {
/**
* HTTP headers of request
* @var array
* @access private
*/
var $headers = array();
/**
* HTTP request
* @var string
* @access private
*/
var $request = '';
/**
* SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
* @var string
* @access public
*/
var $requestHeaders = '';
/**
* SOAP Headers from request (parsed)
* @var mixed
* @access public
*/
var $requestHeader = null;
/**
* SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
* @var string
* @access public
*/
var $document = '';
/**
* SOAP payload for request (text)
* @var string
* @access public
*/
var $requestSOAP = '';
/**
* requested method namespace URI
* @var string
* @access private
*/
var $methodURI = '';
/**
* name of method requested
* @var string
* @access private
*/
var $methodname = '';
/**
* method parameters from request
* @var array
* @access private
*/
var $methodparams = array();
/**
* SOAP Action from request
* @var string
* @access private
*/
var $SOAPAction = '';
/**
* character set encoding of incoming (request) messages
* @var string
* @access public
*/
var $xml_encoding = '';
/**
* toggles whether the parser decodes element content w/ utf8_decode()
* @var boolean
* @access public
*/
var $decode_utf8 = true;
/**
* HTTP headers of response
* @var array
* @access public
*/
var $outgoing_headers = array();
/**
* HTTP response
* @var string
* @access private
*/
var $response = '';
/**
* SOAP headers for response (text or array of soapval or associative array)
* @var mixed
* @access public
*/
var $responseHeaders = '';
/**
* SOAP payload for response (text)
* @var string
* @access private
*/
var $responseSOAP = '';
/**
* method return value to place in response
* @var mixed
* @access private
*/
var $methodreturn = false;
/**
* whether $methodreturn is a string of literal XML
* @var boolean
* @access public
*/
var $methodreturnisliteralxml = false;
/**
* SOAP fault for response (or false)
* @var mixed
* @access private
*/
var $fault = false;
/**
* text indication of result (for debugging)
* @var string
* @access private
*/
var $result = 'successful';
/**
* assoc array of operations => opData; operations are added by the register()
* method or by parsing an external WSDL definition
* @var array
* @access private
*/
var $operations = array();
/**
* wsdl instance (if one)
* @var mixed
* @access private
*/
var $wsdl = false;
/**
* URL for WSDL (if one)
* @var mixed
* @access private
*/
var $externalWSDLURL = false;
/**
* whether to append debug to response as XML comment
* @var boolean
* @access public
*/
var $debug_flag = false;
/**
* constructor
* the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
*
* @param mixed $wsdl file path or URL (string), or wsdl instance (object)
*
* @access public
*/
function nusoap_server( $wsdl = false ) {
parent::nusoap_base();
// turn on debugging?
global $debug;
global $HTTP_SERVER_VARS;
if ( isset( $_SERVER ) ) {
$this->debug( "_SERVER is defined:" );
$this->appendDebug( $this->varDump( $_SERVER ) );
} elseif ( isset( $HTTP_SERVER_VARS ) ) {
$this->debug( "HTTP_SERVER_VARS is defined:" );
$this->appendDebug( $this->varDump( $HTTP_SERVER_VARS ) );
} else {
$this->debug( "Neither _SERVER nor HTTP_SERVER_VARS is defined." );
}
if ( isset( $debug ) ) {
$this->debug( "In nusoap_server, set debug_flag=$debug based on global flag" );
$this->debug_flag = $debug;
} elseif ( isset( $_SERVER['QUERY_STRING'] ) ) {
$qs = explode( '&', $_SERVER['QUERY_STRING'] );
foreach ( $qs as $v ) {
if ( substr( $v, 0, 6 ) == 'debug=' ) {
$this->debug( "In nusoap_server, set debug_flag=" . substr( $v, 6 ) . " based on query string #1" );
$this->debug_flag = substr( $v, 6 );
}
}
} elseif ( isset( $HTTP_SERVER_VARS['QUERY_STRING'] ) ) {
$qs = explode( '&', $HTTP_SERVER_VARS['QUERY_STRING'] );
foreach ( $qs as $v ) {
if ( substr( $v, 0, 6 ) == 'debug=' ) {
$this->debug( "In nusoap_server, set debug_flag=" . substr( $v, 6 ) . " based on query string #2" );
$this->debug_flag = substr( $v, 6 );
}
}
}
// wsdl
if ( $wsdl ) {
$this->debug( "In nusoap_server, WSDL is specified" );
if ( is_object( $wsdl ) && ( get_class( $wsdl ) == 'wsdl' ) ) {
$this->wsdl = $wsdl;
$this->externalWSDLURL = $this->wsdl->wsdl;
$this->debug( 'Use existing wsdl instance from ' . $this->externalWSDLURL );
} else {
$this->debug( 'Create wsdl from ' . $wsdl );
$this->wsdl = new wsdl( $wsdl );
$this->externalWSDLURL = $wsdl;
}
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
if ( $err = $this->wsdl->getError() ) {
die( 'WSDL ERROR: ' . $err );
}
}
}
/**
* processes request and returns response
*
* @param string $data usually is the value of $HTTP_RAW_POST_DATA
*
* @access public
*/
function service( $data ) {
global $HTTP_SERVER_VARS;
if ( isset( $_SERVER['REQUEST_METHOD'] ) ) {
$rm = $_SERVER['REQUEST_METHOD'];
} elseif ( isset( $HTTP_SERVER_VARS['REQUEST_METHOD'] ) ) {
$rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
} else {
$rm = '';
}
if ( isset( $_SERVER['QUERY_STRING'] ) ) {
$qs = $_SERVER['QUERY_STRING'];
} elseif ( isset( $HTTP_SERVER_VARS['QUERY_STRING'] ) ) {
$qs = $HTTP_SERVER_VARS['QUERY_STRING'];
} else {
$qs = '';
}
$this->debug( "In service, request method=$rm query string=$qs strlen(\$data)=" . strlen( $data ) );
if ( $rm == 'POST' ) {
$this->debug( "In service, invoke the request" );
$this->parse_request( $data );
if ( ! $this->fault ) {
$this->invoke_method();
}
if ( ! $this->fault ) {
$this->serialize_return();
}
$this->send_response();
} elseif ( preg_match( '/wsdl/', $qs ) ) {
$this->debug( "In service, this is a request for WSDL" );
if ( $this->externalWSDLURL ) {
if ( strpos( $this->externalWSDLURL, "http://" ) !== false ) { // assume URL
$this->debug( "In service, re-direct for WSDL" );
header( 'Location: ' . $this->externalWSDLURL );
} else { // assume file
$this->debug( "In service, use file passthru for WSDL" );
header( "Content-Type: text/xml\r\n" );
$pos = strpos( $this->externalWSDLURL, "file://" );
if ( $pos === false ) {
$filename = $this->externalWSDLURL;
} else {
$filename = substr( $this->externalWSDLURL, $pos + 7 );
}
$fp = fopen( $this->externalWSDLURL, 'r' );
fpassthru( $fp );
}
} elseif ( $this->wsdl ) {
$this->debug( "In service, serialize WSDL" );
header( "Content-Type: text/xml; charset=ISO-8859-1\r\n" );
print $this->wsdl->serialize( $this->debug_flag );
if ( $this->debug_flag ) {
$this->debug( 'wsdl:' );
$this->appendDebug( $this->varDump( $this->wsdl ) );
print $this->getDebugAsXMLComment();
}
} else {
$this->debug( "In service, there is no WSDL" );
header( "Content-Type: text/html; charset=ISO-8859-1\r\n" );
print "This service does not provide WSDL";
}
} elseif ( $this->wsdl ) {
$this->debug( "In service, return Web description" );
print $this->wsdl->webDescription();
} else {
$this->debug( "In service, no Web description" );
header( "Content-Type: text/html; charset=ISO-8859-1\r\n" );
print "This service does not provide a Web description";
}
}
/**
* parses HTTP request headers.
*
* The following fields are set by this function (when successful)
*
* headers
* request
* xml_encoding
* SOAPAction
*
* @access private
*/
function parse_http_headers() {
global $HTTP_SERVER_VARS;
$this->request = '';
$this->SOAPAction = '';
if ( function_exists( 'getallheaders' ) ) {
$this->debug( "In parse_http_headers, use getallheaders" );
$headers = getallheaders();
foreach ( $headers as $k => $v ) {
$k = strtolower( $k );
$this->headers[ $k ] = $v;
$this->request .= "$k: $v\r\n";
$this->debug( "$k: $v" );
}
// get SOAPAction header
if ( isset( $this->headers['soapaction'] ) ) {
$this->SOAPAction = str_replace( '"', '', $this->headers['soapaction'] );
}
// get the character encoding of the incoming request
if ( isset( $this->headers['content-type'] ) && strpos( $this->headers['content-type'], '=' ) ) {
$enc = str_replace( '"', '', substr( strstr( $this->headers["content-type"], '=' ), 1 ) );
if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
$this->xml_encoding = strtoupper( $enc );
} else {
$this->xml_encoding = 'US-ASCII';
}
} else {
// should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
$this->xml_encoding = 'ISO-8859-1';
}
} elseif ( isset( $_SERVER ) && is_array( $_SERVER ) ) {
$this->debug( "In parse_http_headers, use _SERVER" );
foreach ( $_SERVER as $k => $v ) {
if ( substr( $k, 0, 5 ) == 'HTTP_' ) {
$k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', substr( $k, 5 ) ) ) );
} else {
$k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', $k ) ) );
}
if ( $k == 'soapaction' ) {
// get SOAPAction header
$k = 'SOAPAction';
$v = str_replace( '"', '', $v );
$v = str_replace( '\\', '', $v );
$this->SOAPAction = $v;
} else if ( $k == 'content-type' ) {
// get the character encoding of the incoming request
if ( strpos( $v, '=' ) ) {
$enc = substr( strstr( $v, '=' ), 1 );
$enc = str_replace( '"', '', $enc );
$enc = str_replace( '\\', '', $enc );
if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
$this->xml_encoding = strtoupper( $enc );
} else {
$this->xml_encoding = 'US-ASCII';
}
} else {
// should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
$this->xml_encoding = 'ISO-8859-1';
}
}
$this->headers[ $k ] = $v;
$this->request .= "$k: $v\r\n";
$this->debug( "$k: $v" );
}
} elseif ( is_array( $HTTP_SERVER_VARS ) ) {
$this->debug( "In parse_http_headers, use HTTP_SERVER_VARS" );
foreach ( $HTTP_SERVER_VARS as $k => $v ) {
if ( substr( $k, 0, 5 ) == 'HTTP_' ) {
$k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', substr( $k, 5 ) ) ) );
$k = strtolower( substr( $k, 5 ) );
} else {
$k = str_replace( ' ', '-', strtolower( str_replace( '_', ' ', $k ) ) );
$k = strtolower( $k );
}
if ( $k == 'soapaction' ) {
// get SOAPAction header
$k = 'SOAPAction';
$v = str_replace( '"', '', $v );
$v = str_replace( '\\', '', $v );
$this->SOAPAction = $v;
} else if ( $k == 'content-type' ) {
// get the character encoding of the incoming request
if ( strpos( $v, '=' ) ) {
$enc = substr( strstr( $v, '=' ), 1 );
$enc = str_replace( '"', '', $enc );
$enc = str_replace( '\\', '', $enc );
if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
$this->xml_encoding = strtoupper( $enc );
} else {
$this->xml_encoding = 'US-ASCII';
}
} else {
// should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
$this->xml_encoding = 'ISO-8859-1';
}
}
$this->headers[ $k ] = $v;
$this->request .= "$k: $v\r\n";
$this->debug( "$k: $v" );
}
} else {
$this->debug( "In parse_http_headers, HTTP headers not accessible" );
$this->setError( "HTTP headers not accessible" );
}
}
/**
* parses a request
*
* The following fields are set by this function (when successful)
*
* headers
* request
* xml_encoding
* SOAPAction
* request
* requestSOAP
* methodURI
* methodname
* methodparams
* requestHeaders
* document
*
* This sets the fault field on error
*
* @param string $data XML string
*
* @access private
*/
function parse_request( $data = '' ) {
$this->debug( 'entering parse_request()' );
$this->parse_http_headers();
$this->debug( 'got character encoding: ' . $this->xml_encoding );
// uncompress if necessary
if ( isset( $this->headers['content-encoding'] ) && $this->headers['content-encoding'] != '' ) {
$this->debug( 'got content encoding: ' . $this->headers['content-encoding'] );
if ( $this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip' ) {
// if decoding works, use it. else assume data wasn't gzencoded
if ( function_exists( 'gzuncompress' ) ) {
if ( $this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress( $data ) ) {
$data = $degzdata;
} elseif ( $this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate( substr( $data, 10 ) ) ) {
$data = $degzdata;
} else {
$this->fault( 'SOAP-ENV:Client', 'Errors occurred when trying to decode the data' );
return;
}
} else {
$this->fault( 'SOAP-ENV:Client', 'This Server does not support compressed data' );
return;
}
}
}
$this->request .= "\r\n" . $data;
$data = $this->parseRequest( $this->headers, $data );
$this->requestSOAP = $data;
$this->debug( 'leaving parse_request' );
}
/**
* invokes a PHP function for the requested SOAP method
*
* The following fields are set by this function (when successful)
*
* methodreturn
*
* Note that the PHP function that is called may also set the following
* fields to affect the response sent to the client
*
* responseHeaders
* outgoing_headers
*
* This sets the fault field on error
*
* @access private
*/
function invoke_method() {
$this->debug( 'in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction );
//
// if you are debugging in this area of the code, your service uses a class to implement methods,
// you use SOAP RPC, and the client is .NET, please be aware of the following...
// when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
// method name. that is fine for naming the .NET methods. it is not fine for properly constructing
// the XML request and reading the XML response. you need to add the RequestElementName and
// ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
// generates for the method. these parameters are used to specify the correct XML element names
// for .NET to use, i.e. the names with the '.' in them.
//
$orig_methodname = $this->methodname;
if ( $this->wsdl ) {
if ( $this->opData = $this->wsdl->getOperationData( $this->methodname ) ) {
$this->debug( 'in invoke_method, found WSDL operation=' . $this->methodname );
$this->appendDebug( 'opData=' . $this->varDump( $this->opData ) );
} elseif ( $this->opData = $this->wsdl->getOperationDataForSoapAction( $this->SOAPAction ) ) {
// Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
$this->debug( 'in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name'] );
$this->appendDebug( 'opData=' . $this->varDump( $this->opData ) );
$this->methodname = $this->opData['name'];
} else {
$this->debug( 'in invoke_method, no WSDL for operation=' . $this->methodname );
$this->fault( 'SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service" );
return;
}
} else {
$this->debug( 'in invoke_method, no WSDL to validate method' );
}
// if a . is present in $this->methodname, we see if there is a class in scope,
// which could be referred to. We will also distinguish between two deliminators,
// to allow methods to be called a the class or an instance
if ( strpos( $this->methodname, '..' ) > 0 ) {
$delim = '..';
} else if ( strpos( $this->methodname, '.' ) > 0 ) {
$delim = '.';
} else {
$delim = '';
}
$this->debug( "in invoke_method, delim=$delim" );
$class = '';
$method = '';
if ( strlen( $delim ) > 0 && substr_count( $this->methodname, $delim ) == 1 ) {
$try_class = substr( $this->methodname, 0, strpos( $this->methodname, $delim ) );
if ( class_exists( $try_class ) ) {
// get the class and method name
$class = $try_class;
$method = substr( $this->methodname, strpos( $this->methodname, $delim ) + strlen( $delim ) );
$this->debug( "in invoke_method, class=$class method=$method delim=$delim" );
} else {
$this->debug( "in invoke_method, class=$try_class not found" );
}
} else {
$try_class = '';
$this->debug( "in invoke_method, no class to try" );
}
// does method exist?
if ( $class == '' ) {
if ( ! function_exists( $this->methodname ) ) {
$this->debug( "in invoke_method, function '$this->methodname' not found!" );
$this->result = 'fault: method not found';
$this->fault( 'SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')" );
return;
}
} else {
$method_to_compare = ( substr( phpversion(), 0, 2 ) == '4.' ) ? strtolower( $method ) : $method;
if ( ! in_array( $method_to_compare, get_class_methods( $class ) ) ) {
$this->debug( "in invoke_method, method '$this->methodname' not found in class '$class'!" );
$this->result = 'fault: method not found';
$this->fault( 'SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')" );
return;
}
}
// evaluate message, getting back parameters
// verify that request parameters match the method's signature
if ( ! $this->verify_method( $this->methodname, $this->methodparams ) ) {
// debug
$this->debug( 'ERROR: request not verified against method signature' );
$this->result = 'fault: request failed validation against method signature';
// return fault
$this->fault( 'SOAP-ENV:Client', "Operation '$this->methodname' not defined in service." );
return;
}
// if there are parameters to pass
$this->debug( 'in invoke_method, params:' );
$this->appendDebug( $this->varDump( $this->methodparams ) );
$this->debug( "in invoke_method, calling '$this->methodname'" );
if ( ! function_exists( 'call_user_func_array' ) ) {
if ( $class == '' ) {
$this->debug( 'in invoke_method, calling function using eval()' );
$funcCall = "\$this->methodreturn = $this->methodname(";
} else {
if ( $delim == '..' ) {
$this->debug( 'in invoke_method, calling class method using eval()' );
$funcCall = "\$this->methodreturn = " . $class . "::" . $method . "(";
} else {
$this->debug( 'in invoke_method, calling instance method using eval()' );
// generate unique instance name
$instname = "\$inst_" . time();
$funcCall = $instname . " = new " . $class . "(); ";
$funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "(";
}
}
if ( $this->methodparams ) {
foreach ( $this->methodparams as $param ) {
if ( is_array( $param ) || is_object( $param ) ) {
$this->fault( 'SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available' );
return;
}
$funcCall .= "\"$param\",";
}
$funcCall = substr( $funcCall, 0, - 1 );
}
$funcCall .= ');';
$this->debug( 'in invoke_method, function call: ' . $funcCall );
@eval( $funcCall );
} else {
if ( $class == '' ) {
$this->debug( 'in invoke_method, calling function using call_user_func_array()' );
$call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
} elseif ( $delim == '..' ) {
$this->debug( 'in invoke_method, calling class method using call_user_func_array()' );
$call_arg = array( $class, $method );
} else {
$this->debug( 'in invoke_method, calling instance method using call_user_func_array()' );
$instance = new $class ();
$call_arg = array( &$instance, $method );
}
if ( is_array( $this->methodparams ) ) {
$this->methodreturn = call_user_func_array( $call_arg, array_values( $this->methodparams ) );
} else {
$this->methodreturn = call_user_func_array( $call_arg, array() );
}
}
$this->debug( 'in invoke_method, methodreturn:' );
$this->appendDebug( $this->varDump( $this->methodreturn ) );
$this->debug( "in invoke_method, called method $this->methodname, received data of type " . gettype( $this->methodreturn ) );
}
/**
* serializes the return value from a PHP function into a full SOAP Envelope
*
* The following fields are set by this function (when successful)
*
* responseSOAP
*
* This sets the fault field on error
*
* @access private
*/
function serialize_return() {
$this->debug( 'Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI );
// if fault
if ( isset( $this->methodreturn ) && is_object( $this->methodreturn ) && ( ( get_class( $this->methodreturn ) == 'soap_fault' ) || ( get_class( $this->methodreturn ) == 'nusoap_fault' ) ) ) {
$this->debug( 'got a fault object from method' );
$this->fault = $this->methodreturn;
return;
} elseif ( $this->methodreturnisliteralxml ) {
$return_val = $this->methodreturn;
// returned value(s)
} else {
$this->debug( 'got a(n) ' . gettype( $this->methodreturn ) . ' from method' );
$this->debug( 'serializing return value' );
if ( $this->wsdl ) {
if ( sizeof( $this->opData['output']['parts'] ) > 1 ) {
$this->debug( 'more than one output part, so use the method return unchanged' );
$opParams = $this->methodreturn;
} elseif ( sizeof( $this->opData['output']['parts'] ) == 1 ) {
$this->debug( 'exactly one output part, so wrap the method return in a simple array' );
// TODO: verify that it is not already wrapped!
//foreach ($this->opData['output']['parts'] as $name => $type) {
// $this->debug('wrap in element named ' . $name);
//}
$opParams = array( $this->methodreturn );
}
$return_val = $this->wsdl->serializeRPCParameters( $this->methodname, 'output', $opParams );
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
if ( $errstr = $this->wsdl->getError() ) {
$this->debug( 'got wsdl error: ' . $errstr );
$this->fault( 'SOAP-ENV:Server', 'unable to serialize result' );
return;
}
} else {
if ( isset( $this->methodreturn ) ) {
$return_val = $this->serialize_val( $this->methodreturn, 'return' );
} else {
$return_val = '';
$this->debug( 'in absence of WSDL, assume void return for backward compatibility' );
}
}
}
$this->debug( 'return value:' );
$this->appendDebug( $this->varDump( $return_val ) );
$this->debug( 'serializing response' );
if ( $this->wsdl ) {
$this->debug( 'have WSDL for serialization: style is ' . $this->opData['style'] );
if ( $this->opData['style'] == 'rpc' ) {
$this->debug( 'style is rpc for serialization: use is ' . $this->opData['output']['use'] );
if ( $this->opData['output']['use'] == 'literal' ) {
// http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
if ( $this->methodURI ) {
$payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
} else {
$payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
}
} else {
if ( $this->methodURI ) {
$payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
} else {
$payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
}
}
} else {
$this->debug( 'style is not rpc for serialization: assume document' );
$payload = $return_val;
}
} else {
$this->debug( 'do not have WSDL for serialization: assume rpc/encoded' );
$payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . "Response>";
}
$this->result = 'successful';
if ( $this->wsdl ) {
//if($this->debug_flag){
$this->appendDebug( $this->wsdl->getDebug() );
// }
if ( isset( $this->opData['output']['encodingStyle'] ) ) {
$encodingStyle = $this->opData['output']['encodingStyle'];
} else {
$encodingStyle = '';
}
// Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
$this->responseSOAP = $this->serializeEnvelope( $payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle );
} else {
$this->responseSOAP = $this->serializeEnvelope( $payload, $this->responseHeaders );
}
$this->debug( "Leaving serialize_return" );
}
/**
* sends an HTTP response
*
* The following fields are set by this function (when successful)
*
* outgoing_headers
* response
*
* @access private
*/
function send_response() {
$this->debug( 'Enter send_response' );
if ( $this->fault ) {
$payload = $this->fault->serialize();
$this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
$this->outgoing_headers[] = "Status: 500 Internal Server Error";
} else {
$payload = $this->responseSOAP;
// Some combinations of PHP+Web server allow the Status
// to come through as a header. Since OK is the default
// just do nothing.
// $this->outgoing_headers[] = "HTTP/1.0 200 OK";
// $this->outgoing_headers[] = "Status: 200 OK";
}
// add debug data if in debug mode
if ( isset( $this->debug_flag ) && $this->debug_flag ) {
$payload .= $this->getDebugAsXMLComment();
}
$this->outgoing_headers[] = "Server: $this->title Server v$this->version";
preg_match( '/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev );
$this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")";
// Let the Web server decide about this
//$this->outgoing_headers[] = "Connection: Close\r\n";
$payload = $this->getHTTPBody( $payload );
$type = $this->getHTTPContentType();
$charset = $this->getHTTPContentTypeCharset();
$this->outgoing_headers[] = "Content-Type: $type" . ( $charset ? '; charset=' . $charset : '' );
//begin code to compress payload - by John
// NOTE: there is no way to know whether the Web server will also compress
// this data.
if ( strlen( $payload ) > 1024 && isset( $this->headers ) && isset( $this->headers['accept-encoding'] ) ) {
if ( strstr( $this->headers['accept-encoding'], 'gzip' ) ) {
if ( function_exists( 'gzencode' ) ) {
if ( isset( $this->debug_flag ) && $this->debug_flag ) {
$payload .= "<!-- Content being gzipped -->";
}
$this->outgoing_headers[] = "Content-Encoding: gzip";
$payload = gzencode( $payload );
} else {
if ( isset( $this->debug_flag ) && $this->debug_flag ) {
$payload .= "<!-- Content will not be gzipped: no gzencode -->";
}
}
} elseif ( strstr( $this->headers['accept-encoding'], 'deflate' ) ) {
// Note: MSIE requires gzdeflate output (no Zlib header and checksum),
// instead of gzcompress output,
// which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
if ( function_exists( 'gzdeflate' ) ) {
if ( isset( $this->debug_flag ) && $this->debug_flag ) {
$payload .= "<!-- Content being deflated -->";
}
$this->outgoing_headers[] = "Content-Encoding: deflate";
$payload = gzdeflate( $payload );
} else {
if ( isset( $this->debug_flag ) && $this->debug_flag ) {
$payload .= "<!-- Content will not be deflated: no gzcompress -->";
}
}
}
}
//end code
$this->outgoing_headers[] = "Content-Length: " . strlen( $payload );
reset( $this->outgoing_headers );
foreach ( $this->outgoing_headers as $hdr ) {
header( $hdr, false );
}
print $payload;
$this->response = join( "\r\n", $this->outgoing_headers ) . "\r\n\r\n" . $payload;
}
/**
* takes the value that was created by parsing the request
* and compares to the method's signature, if available.
*
* @param string $operation The operation to be invoked
* @param array $request The array of parameter values
*
* @return boolean Whether the operation was found
* @access private
*/
function verify_method( $operation, $request ) {
if ( isset( $this->wsdl ) && is_object( $this->wsdl ) ) {
if ( $this->wsdl->getOperationData( $operation ) ) {
return true;
}
} elseif ( isset( $this->operations[ $operation ] ) ) {
return true;
}
return false;
}
/**
* processes SOAP message received from client
*
* @param array $headers The HTTP headers
* @param string $data unprocessed request data from client
*
* @return mixed value of the message, decoded into a PHP type
* @access private
*/
function parseRequest( $headers, $data ) {
$this->debug( 'Entering parseRequest() for data of length ' . strlen( $data ) . ' headers:' );
$this->appendDebug( $this->varDump( $headers ) );
if ( ! isset( $headers['content-type'] ) ) {
$this->setError( 'Request not of type text/xml (no content-type header)' );
return false;
}
if ( ! strstr( $headers['content-type'], 'text/xml' ) ) {
$this->setError( 'Request not of type text/xml' );
return false;
}
if ( strpos( $headers['content-type'], '=' ) ) {
$enc = str_replace( '"', '', substr( strstr( $headers["content-type"], '=' ), 1 ) );
$this->debug( 'Got response encoding: ' . $enc );
if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
$this->xml_encoding = strtoupper( $enc );
} else {
$this->xml_encoding = 'US-ASCII';
}
} else {
// should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
$this->xml_encoding = 'ISO-8859-1';
}
$this->debug( 'Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser' );
// parse response, get soap parser obj
$parser = new nusoap_parser( $data, $this->xml_encoding, '', $this->decode_utf8 );
// parser debug
$this->debug( "parser debug: \n" . $parser->getDebug() );
// if fault occurred during message parsing
if ( $err = $parser->getError() ) {
$this->result = 'fault: error in msg parsing: ' . $err;
$this->fault( 'SOAP-ENV:Client', "error in msg parsing:\n" . $err );
// else successfully parsed request into soapval object
} else {
// get/set methodname
$this->methodURI = $parser->root_struct_namespace;
$this->methodname = $parser->root_struct_name;
$this->debug( 'methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI );
$this->debug( 'calling parser->get_soapbody()' );
$this->methodparams = $parser->get_soapbody();
// get SOAP headers
$this->requestHeaders = $parser->getHeaders();
// get SOAP Header
$this->requestHeader = $parser->get_soapheader();
// add document for doclit support
$this->document = $parser->document;
}
}
/**
* gets the HTTP body for the current response.
*
* @param string $soapmsg The SOAP payload
*
* @return string The HTTP body, which includes the SOAP payload
* @access private
*/
function getHTTPBody( $soapmsg ) {
return $soapmsg;
}
/**
* gets the HTTP content type for the current response.
*
* Note: getHTTPBody must be called before this.
*
* @return string the HTTP content type for the current response.
* @access private
*/
function getHTTPContentType() {
return 'text/xml';
}
/**
* gets the HTTP content type charset for the current response.
* returns false for non-text content types.
*
* Note: getHTTPBody must be called before this.
*
* @return string the HTTP content type charset for the current response.
* @access private
*/
function getHTTPContentTypeCharset() {
return $this->soap_defencoding;
}
/**
* add a method to the dispatch map (this has been replaced by the register method)
*
* @param string $methodname
* @param string $in array of input values
* @param string $out array of output values
*
* @access public
* @deprecated
*/
function add_to_map( $methodname, $in, $out ) {
$this->operations[ $methodname ] = array( 'name' => $methodname, 'in' => $in, 'out' => $out );
}
/**
* register a service function with the server
*
* @param string $name the name of the PHP function, class.method or class..method
* @param array $in assoc array of input values: key = param name, value = param type
* @param array $out assoc array of output values: key = param name, value = param type
* @param mixed $namespace the element namespace for the method or false
* @param mixed $soapaction the soapaction for the method or false
* @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
* @param mixed $use optional (encoded|literal) or false
* @param string $documentation optional Description to include in WSDL
* @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
*
* @access public
*/
function register( $name, $in = array(), $out = array(), $namespace = false, $soapaction = false, $style = false, $use = false, $documentation = '', $encodingStyle = '' ) {
global $HTTP_SERVER_VARS;
if ( $this->externalWSDLURL ) {
die( 'You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.' );
}
if ( ! $name ) {
die( 'You must specify a name when you register an operation' );
}
if ( ! is_array( $in ) ) {
die( 'You must provide an array for operation inputs' );
}
if ( ! is_array( $out ) ) {
die( 'You must provide an array for operation outputs' );
}
if ( false == $namespace ) {
}
if ( false == $soapaction ) {
if ( isset( $_SERVER ) ) {
$SERVER_NAME = $_SERVER['SERVER_NAME'];
$SCRIPT_NAME = isset( $_SERVER['PHP_SELF'] ) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
$HTTPS = isset( $_SERVER['HTTPS'] ) ? $_SERVER['HTTPS'] : ( isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off' );
} elseif ( isset( $HTTP_SERVER_VARS ) ) {
$SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
$SCRIPT_NAME = isset( $HTTP_SERVER_VARS['PHP_SELF'] ) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
$HTTPS = isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
} else {
$this->setError( "Neither _SERVER nor HTTP_SERVER_VARS is available" );
}
if ( $HTTPS == '1' || $HTTPS == 'on' ) {
$SCHEME = 'https';
} else {
$SCHEME = 'http';
}
$soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
}
if ( false == $style ) {
$style = "rpc";
}
if ( false == $use ) {
$use = "encoded";
}
if ( $use == 'encoded' && $encodingStyle == '' ) {
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
}
$this->operations[ $name ] = array(
'name' => $name,
'in' => $in,
'out' => $out,
'namespace' => $namespace,
'soapaction' => $soapaction,
'style' => $style
);
if ( $this->wsdl ) {
$this->wsdl->addOperation( $name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle );
}
return true;
}
/**
* Specify a fault to be returned to the client.
* This also acts as a flag to the server that a fault has occured.
*
* @param string $faultcode
* @param string $faultstring
* @param string $faultactor
* @param string $faultdetail
*
* @access public
*/
function fault( $faultcode, $faultstring, $faultactor = '', $faultdetail = '' ) {
if ( $faultdetail == '' && $this->debug_flag ) {
$faultdetail = $this->getDebug();
}
$this->fault = new nusoap_fault( $faultcode, $faultactor, $faultstring, $faultdetail );
$this->fault->soap_defencoding = $this->soap_defencoding;
}
/**
* Sets up wsdl object.
* Acts as a flag to enable internal WSDL generation
*
* @param string $serviceName , name of the service
* @param mixed $namespace optional 'tns' service namespace or false
* @param mixed $endpoint optional URL of service endpoint or false
* @param string $style optional (rpc|document) WSDL style (also specified by operation)
* @param string $transport optional SOAP transport
* @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
*/
function configureWSDL( $serviceName, $namespace = false, $endpoint = false, $style = 'rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false ) {
global $HTTP_SERVER_VARS;
if ( isset( $_SERVER ) ) {
$SERVER_NAME = $_SERVER['SERVER_NAME'];
$SERVER_PORT = $_SERVER['SERVER_PORT'];
$SCRIPT_NAME = isset( $_SERVER['PHP_SELF'] ) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
$HTTPS = isset( $_SERVER['HTTPS'] ) ? $_SERVER['HTTPS'] : ( isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off' );
} elseif ( isset( $HTTP_SERVER_VARS ) ) {
$SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
$SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
$SCRIPT_NAME = isset( $HTTP_SERVER_VARS['PHP_SELF'] ) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
$HTTPS = isset( $HTTP_SERVER_VARS['HTTPS'] ) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
} else {
$this->setError( "Neither _SERVER nor HTTP_SERVER_VARS is available" );
}
// If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
$colon = strpos( $SERVER_NAME, ":" );
if ( $colon ) {
$SERVER_NAME = substr( $SERVER_NAME, 0, $colon );
}
if ( $SERVER_PORT == 80 ) {
$SERVER_PORT = '';
} else {
$SERVER_PORT = ':' . $SERVER_PORT;
}
if ( false == $namespace ) {
$namespace = "http://$SERVER_NAME/soap/$serviceName";
}
if ( false == $endpoint ) {
if ( $HTTPS == '1' || $HTTPS == 'on' ) {
$SCHEME = 'https';
} else {
$SCHEME = 'http';
}
$endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
}
if ( false == $schemaTargetNamespace ) {
$schemaTargetNamespace = $namespace;
}
$this->wsdl = new wsdl;
$this->wsdl->serviceName = $serviceName;
$this->wsdl->endpoint = $endpoint;
$this->wsdl->namespaces['tns'] = $namespace;
$this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
$this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
if ( $schemaTargetNamespace != $namespace ) {
$this->wsdl->namespaces['types'] = $schemaTargetNamespace;
}
$this->wsdl->schemas[ $schemaTargetNamespace ][0] = new nusoap_xmlschema( '', '', $this->wsdl->namespaces );
if ( $style == 'document' ) {
$this->wsdl->schemas[ $schemaTargetNamespace ][0]->schemaInfo['elementFormDefault'] = 'qualified';
}
$this->wsdl->schemas[ $schemaTargetNamespace ][0]->schemaTargetNamespace = $schemaTargetNamespace;
$this->wsdl->schemas[ $schemaTargetNamespace ][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array(
'location' => '',
'loaded' => true
);
$this->wsdl->schemas[ $schemaTargetNamespace ][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array(
'location' => '',
'loaded' => true
);
$this->wsdl->bindings[ $serviceName . 'Binding' ] = array(
'name' => $serviceName . 'Binding',
'style' => $style,
'transport' => $transport,
'portType' => $serviceName . 'PortType'
);
$this->wsdl->ports[ $serviceName . 'Port' ] = array(
'binding' => $serviceName . 'Binding',
'location' => $endpoint,
'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/'
);
}
}
/**
* Backward compatibility
*/
class soap_server extends nusoap_server {
}
?><?php
/**
* parses a WSDL file, allows access to it's data, other utility methods.
* also builds WSDL structures programmatically.
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class wsdl extends nusoap_base {
// URL or filename of the root of this WSDL
var $wsdl;
// define internal arrays of bindings, ports, operations, messages, etc.
var $schemas = array();
var $currentSchema;
var $message = array();
var $complexTypes = array();
var $messages = array();
var $currentMessage;
var $currentOperation;
var $portTypes = array();
var $currentPortType;
var $bindings = array();
var $currentBinding;
var $ports = array();
var $currentPort;
var $opData = array();
var $status = '';
var $documentation = false;
var $endpoint = '';
// array of wsdl docs to import
var $import = array();
// parser vars
var $parser;
var $position = 0;
var $depth = 0;
var $depth_array = array();
// for getting wsdl
var $proxyhost = '';
var $proxyport = '';
var $proxyusername = '';
var $proxypassword = '';
var $timeout = 0;
var $response_timeout = 30;
var $curl_options = array(); // User-specified cURL options
var $use_curl = false; // whether to always try to use cURL
// for HTTP authentication
var $username = ''; // Username for HTTP authentication
var $password = ''; // Password for HTTP authentication
var $authtype = ''; // Type of HTTP authentication
var $certRequest = array(); // Certificate for HTTP SSL authentication
/**
* constructor
*
* @param string $wsdl WSDL document URL
* @param string $proxyhost
* @param string $proxyport
* @param string $proxyusername
* @param string $proxypassword
* @param integer $timeout set the connection timeout
* @param integer $response_timeout set the response timeout
* @param array $curl_options user-specified cURL options
* @param boolean $use_curl try to use cURL
*
* @access public
*/
function wsdl( $wsdl = '', $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $curl_options = null, $use_curl = false ) {
parent::nusoap_base();
$this->debug( "ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout" );
$this->proxyhost = $proxyhost;
$this->proxyport = $proxyport;
$this->proxyusername = $proxyusername;
$this->proxypassword = $proxypassword;
$this->timeout = $timeout;
$this->response_timeout = $response_timeout;
if ( is_array( $curl_options ) ) {
$this->curl_options = $curl_options;
}
$this->use_curl = $use_curl;
$this->fetchWSDL( $wsdl );
}
/**
* fetches the WSDL document and parses it
*
* @access public
*/
function fetchWSDL( $wsdl ) {
$this->debug( "parse and process WSDL path=$wsdl" );
$this->wsdl = $wsdl;
// parse wsdl file
if ( $this->wsdl != "" ) {
$this->parseWSDL( $this->wsdl );
}
// imports
// TODO: handle imports more properly, grabbing them in-line and nesting them
$imported_urls = array();
$imported = 1;
while ( $imported > 0 ) {
$imported = 0;
// Schema imports
foreach ( $this->schemas as $ns => $list ) {
foreach ( $list as $xs ) {
$wsdlparts = parse_url( $this->wsdl ); // this is bogusly simple!
foreach ( $xs->imports as $ns2 => $list2 ) {
for ( $ii = 0; $ii < count( $list2 ); $ii ++ ) {
if ( ! $list2[ $ii ]['loaded'] ) {
$this->schemas[ $ns ]->imports[ $ns2 ][ $ii ]['loaded'] = true;
$url = $list2[ $ii ]['location'];
if ( $url != '' ) {
$urlparts = parse_url( $url );
if ( ! isset( $urlparts['host'] ) ) {
$url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . ( isset( $wsdlparts['port'] ) ? ':' . $wsdlparts['port'] : '' ) .
substr( $wsdlparts['path'], 0, strrpos( $wsdlparts['path'], '/' ) + 1 ) . $urlparts['path'];
}
if ( ! in_array( $url, $imported_urls ) ) {
$this->parseWSDL( $url );
$imported ++;
$imported_urls[] = $url;
}
} else {
$this->debug( "Unexpected scenario: empty URL for unloaded import" );
}
}
}
}
}
}
// WSDL imports
$wsdlparts = parse_url( $this->wsdl ); // this is bogusly simple!
foreach ( $this->import as $ns => $list ) {
for ( $ii = 0; $ii < count( $list ); $ii ++ ) {
if ( ! $list[ $ii ]['loaded'] ) {
$this->import[ $ns ][ $ii ]['loaded'] = true;
$url = $list[ $ii ]['location'];
if ( $url != '' ) {
$urlparts = parse_url( $url );
if ( ! isset( $urlparts['host'] ) ) {
$url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . ( isset( $wsdlparts['port'] ) ? ':' . $wsdlparts['port'] : '' ) .
substr( $wsdlparts['path'], 0, strrpos( $wsdlparts['path'], '/' ) + 1 ) . $urlparts['path'];
}
if ( ! in_array( $url, $imported_urls ) ) {
$this->parseWSDL( $url );
$imported ++;
$imported_urls[] = $url;
}
} else {
$this->debug( "Unexpected scenario: empty URL for unloaded import" );
}
}
}
}
}
// add new data to operation data
foreach ( $this->bindings as $binding => $bindingData ) {
if ( isset( $bindingData['operations'] ) && is_array( $bindingData['operations'] ) ) {
foreach ( $bindingData['operations'] as $operation => $data ) {
$this->debug( 'post-parse data gathering for ' . $operation );
$this->bindings[ $binding ]['operations'][ $operation ]['input'] =
isset( $this->bindings[ $binding ]['operations'][ $operation ]['input'] ) ?
array_merge( $this->bindings[ $binding ]['operations'][ $operation ]['input'], $this->portTypes[ $bindingData['portType'] ][ $operation ]['input'] ) :
$this->portTypes[ $bindingData['portType'] ][ $operation ]['input'];
$this->bindings[ $binding ]['operations'][ $operation ]['output'] =
isset( $this->bindings[ $binding ]['operations'][ $operation ]['output'] ) ?
array_merge( $this->bindings[ $binding ]['operations'][ $operation ]['output'], $this->portTypes[ $bindingData['portType'] ][ $operation ]['output'] ) :
$this->portTypes[ $bindingData['portType'] ][ $operation ]['output'];
if ( isset( $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['input']['message'] ] ) ) {
$this->bindings[ $binding ]['operations'][ $operation ]['input']['parts'] = $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['input']['message'] ];
}
if ( isset( $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['output']['message'] ] ) ) {
$this->bindings[ $binding ]['operations'][ $operation ]['output']['parts'] = $this->messages[ $this->bindings[ $binding ]['operations'][ $operation ]['output']['message'] ];
}
// Set operation style if necessary, but do not override one already provided
if ( isset( $bindingData['style'] ) && ! isset( $this->bindings[ $binding ]['operations'][ $operation ]['style'] ) ) {
$this->bindings[ $binding ]['operations'][ $operation ]['style'] = $bindingData['style'];
}
$this->bindings[ $binding ]['operations'][ $operation ]['transport'] = isset( $bindingData['transport'] ) ? $bindingData['transport'] : '';
$this->bindings[ $binding ]['operations'][ $operation ]['documentation'] = isset( $this->portTypes[ $bindingData['portType'] ][ $operation ]['documentation'] ) ? $this->portTypes[ $bindingData['portType'] ][ $operation ]['documentation'] : '';
$this->bindings[ $binding ]['operations'][ $operation ]['endpoint'] = isset( $bindingData['endpoint'] ) ? $bindingData['endpoint'] : '';
}
}
}
}
/**
* parses the wsdl document
*
* @param string $wsdl path or URL
*
* @access private
*/
function parseWSDL( $wsdl = '' ) {
$this->debug( "parse WSDL at path=$wsdl" );
if ( $wsdl == '' ) {
$this->debug( 'no wsdl passed to parseWSDL()!!' );
$this->setError( 'no wsdl passed to parseWSDL()!!' );
return false;
}
// parse $wsdl for url format
$wsdl_props = parse_url( $wsdl );
if ( isset( $wsdl_props['scheme'] ) && ( $wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https' ) ) {
$this->debug( 'getting WSDL http(s) URL ' . $wsdl );
// get wsdl
$tr = new soap_transport_http( $wsdl, $this->curl_options, $this->use_curl );
$tr->request_method = 'GET';
$tr->useSOAPAction = false;
if ( $this->proxyhost && $this->proxyport ) {
$tr->setProxy( $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword );
}
if ( $this->authtype != '' ) {
$tr->setCredentials( $this->username, $this->password, $this->authtype, array(), $this->certRequest );
}
$tr->setEncoding( 'gzip, deflate' );
$wsdl_string = $tr->send( '', $this->timeout, $this->response_timeout );
//$this->debug("WSDL request\n" . $tr->outgoing_payload);
//$this->debug("WSDL response\n" . $tr->incoming_payload);
$this->appendDebug( $tr->getDebug() );
// catch errors
if ( $err = $tr->getError() ) {
$errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err;
$this->debug( $errstr );
$this->setError( $errstr );
unset( $tr );
return false;
}
unset( $tr );
$this->debug( "got WSDL URL" );
} else {
// $wsdl is not http(s), so treat it as a file URL or plain file path
if ( isset( $wsdl_props['scheme'] ) && ( $wsdl_props['scheme'] == 'file' ) && isset( $wsdl_props['path'] ) ) {
$path = isset( $wsdl_props['host'] ) ? ( $wsdl_props['host'] . ':' . $wsdl_props['path'] ) : $wsdl_props['path'];
} else {
$path = $wsdl;
}
$this->debug( 'getting WSDL file ' . $path );
if ( $fp = @fopen( $path, 'r' ) ) {
$wsdl_string = '';
while ( $data = fread( $fp, 32768 ) ) {
$wsdl_string .= $data;
}
fclose( $fp );
} else {
$errstr = "Bad path to WSDL file $path";
$this->debug( $errstr );
$this->setError( $errstr );
return false;
}
}
$this->debug( 'Parse WSDL' );
// end new code added
// Create an XML parser.
$this->parser = xml_parser_create();
// Set the options for parsing the XML data.
// xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
// Set the object for the parser.
xml_set_object( $this->parser, $this );
// Set the element handlers for the parser.
xml_set_element_handler( $this->parser, 'start_element', 'end_element' );
xml_set_character_data_handler( $this->parser, 'character_data' );
// Parse the XML file.
if ( ! xml_parse( $this->parser, $wsdl_string, true ) ) {
// Display an error message.
$errstr = sprintf(
'XML error parsing WSDL from %s on line %d: %s',
$wsdl,
xml_get_current_line_number( $this->parser ),
xml_error_string( xml_get_error_code( $this->parser ) )
);
$this->debug( $errstr );
$this->debug( "XML payload:\n" . $wsdl_string );
$this->setError( $errstr );
return false;
}
// free the parser
xml_parser_free( $this->parser );
$this->debug( 'Parsing WSDL done' );
// catch wsdl parse errors
if ( $this->getError() ) {
return false;
}
return true;
}
/**
* start-element handler
*
* @param string $parser XML parser object
* @param string $name element name
* @param string $attrs associative array of attributes
*
* @access private
*/
function start_element( $parser, $name, $attrs ) {
if ( $this->status == 'schema' ) {
$this->currentSchema->schemaStartElement( $parser, $name, $attrs );
$this->appendDebug( $this->currentSchema->getDebug() );
$this->currentSchema->clearDebug();
} elseif ( preg_match( '/schema$/', $name ) ) {
$this->debug( 'Parsing WSDL schema' );
// $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
$this->status = 'schema';
$this->currentSchema = new nusoap_xmlschema( '', '', $this->namespaces );
$this->currentSchema->schemaStartElement( $parser, $name, $attrs );
$this->appendDebug( $this->currentSchema->getDebug() );
$this->currentSchema->clearDebug();
} else {
// position in the total number of elements, starting from 0
$pos = $this->position ++;
$depth = $this->depth ++;
// set self as current value for this depth
$this->depth_array[ $depth ] = $pos;
$this->message[ $pos ] = array( 'cdata' => '' );
// process attributes
if ( count( $attrs ) > 0 ) {
// register namespace declarations
foreach ( $attrs as $k => $v ) {
if ( preg_match( '/^xmlns/', $k ) ) {
if ( $ns_prefix = substr( strrchr( $k, ':' ), 1 ) ) {
$this->namespaces[ $ns_prefix ] = $v;
} else {
$this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $v;
}
if ( $v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema' ) {
$this->XMLSchemaVersion = $v;
$this->namespaces['xsi'] = $v . '-instance';
}
}
}
// expand each attribute prefix to its namespace
foreach ( $attrs as $k => $v ) {
$k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
if ( $k != 'location' && $k != 'soapAction' && $k != 'namespace' ) {
$v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
}
$eAttrs[ $k ] = $v;
}
$attrs = $eAttrs;
} else {
$attrs = array();
}
// get element prefix, namespace and name
if ( preg_match( '/:/', $name ) ) {
// get ns prefix
$prefix = substr( $name, 0, strpos( $name, ':' ) );
// get ns
$namespace = isset( $this->namespaces[ $prefix ] ) ? $this->namespaces[ $prefix ] : '';
// get unqualified name
$name = substr( strstr( $name, ':' ), 1 );
}
// process attributes, expanding any prefixes to namespaces
// find status, register data
switch ( $this->status ) {
case 'message':
if ( $name == 'part' ) {
if ( isset( $attrs['type'] ) ) {
$this->debug( "msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode( ',', $attrs ) );
$this->messages[ $this->currentMessage ][ $attrs['name'] ] = $attrs['type'];
}
if ( isset( $attrs['element'] ) ) {
$this->debug( "msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode( ',', $attrs ) );
$this->messages[ $this->currentMessage ][ $attrs['name'] ] = $attrs['element'] . '^';
}
}
break;
case 'portType':
switch ( $name ) {
case 'operation':
$this->currentPortOperation = $attrs['name'];
$this->debug( "portType $this->currentPortType operation: $this->currentPortOperation" );
if ( isset( $attrs['parameterOrder'] ) ) {
$this->portTypes[ $this->currentPortType ][ $attrs['name'] ]['parameterOrder'] = $attrs['parameterOrder'];
}
break;
case 'documentation':
$this->documentation = true;
break;
// merge input/output data
default:
$m = isset( $attrs['message'] ) ? $this->getLocalPart( $attrs['message'] ) : '';
$this->portTypes[ $this->currentPortType ][ $this->currentPortOperation ][ $name ]['message'] = $m;
break;
}
break;
case 'binding':
switch ( $name ) {
case 'binding':
// get ns prefix
if ( isset( $attrs['style'] ) ) {
$this->bindings[ $this->currentBinding ]['prefix'] = $prefix;
}
$this->bindings[ $this->currentBinding ] = array_merge( $this->bindings[ $this->currentBinding ], $attrs );
break;
case 'header':
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ]['headers'][] = $attrs;
break;
case 'operation':
if ( isset( $attrs['soapAction'] ) ) {
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['soapAction'] = $attrs['soapAction'];
}
if ( isset( $attrs['style'] ) ) {
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['style'] = $attrs['style'];
}
if ( isset( $attrs['name'] ) ) {
$this->currentOperation = $attrs['name'];
$this->debug( "current binding operation: $this->currentOperation" );
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['name'] = $attrs['name'];
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['binding'] = $this->currentBinding;
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ]['endpoint'] = isset( $this->bindings[ $this->currentBinding ]['endpoint'] ) ? $this->bindings[ $this->currentBinding ]['endpoint'] : '';
}
break;
case 'input':
$this->opStatus = 'input';
break;
case 'output':
$this->opStatus = 'output';
break;
case 'body':
if ( isset( $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ] ) ) {
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ] = array_merge( $this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ], $attrs );
} else {
$this->bindings[ $this->currentBinding ]['operations'][ $this->currentOperation ][ $this->opStatus ] = $attrs;
}
break;
}
break;
case 'service':
switch ( $name ) {
case 'port':
$this->currentPort = $attrs['name'];
$this->debug( 'current port: ' . $this->currentPort );
$this->ports[ $this->currentPort ]['binding'] = $this->getLocalPart( $attrs['binding'] );
break;
case 'address':
$this->ports[ $this->currentPort ]['location'] = $attrs['location'];
$this->ports[ $this->currentPort ]['bindingType'] = $namespace;
$this->bindings[ $this->ports[ $this->currentPort ]['binding'] ]['bindingType'] = $namespace;
$this->bindings[ $this->ports[ $this->currentPort ]['binding'] ]['endpoint'] = $attrs['location'];
break;
}
break;
}
// set status
switch ( $name ) {
case 'import':
if ( isset( $attrs['location'] ) ) {
$this->import[ $attrs['namespace'] ][] = array(
'location' => $attrs['location'],
'loaded' => false
);
$this->debug( 'parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count( $this->import[ $attrs['namespace'] ] ) . ')' );
} else {
$this->import[ $attrs['namespace'] ][] = array( 'location' => '', 'loaded' => true );
if ( ! $this->getPrefixFromNamespace( $attrs['namespace'] ) ) {
$this->namespaces[ 'ns' . ( count( $this->namespaces ) + 1 ) ] = $attrs['namespace'];
}
$this->debug( 'parsing import ' . $attrs['namespace'] . ' - [no location] (' . count( $this->import[ $attrs['namespace'] ] ) . ')' );
}
break;
//wait for schema
//case 'types':
// $this->status = 'schema';
// break;
case 'message':
$this->status = 'message';
$this->messages[ $attrs['name'] ] = array();
$this->currentMessage = $attrs['name'];
break;
case 'portType':
$this->status = 'portType';
$this->portTypes[ $attrs['name'] ] = array();
$this->currentPortType = $attrs['name'];
break;
case "binding":
if ( isset( $attrs['name'] ) ) {
// get binding name
if ( strpos( $attrs['name'], ':' ) ) {
$this->currentBinding = $this->getLocalPart( $attrs['name'] );
} else {
$this->currentBinding = $attrs['name'];
}
$this->status = 'binding';
$this->bindings[ $this->currentBinding ]['portType'] = $this->getLocalPart( $attrs['type'] );
$this->debug( "current binding: $this->currentBinding of portType: " . $attrs['type'] );
}
break;
case 'service':
$this->serviceName = $attrs['name'];
$this->status = 'service';
$this->debug( 'current service: ' . $this->serviceName );
break;
case 'definitions':
foreach ( $attrs as $name => $value ) {
$this->wsdl_info[ $name ] = $value;
}
break;
}
}
}
/**
* end-element handler
*
* @param string $parser XML parser object
* @param string $name element name
*
* @access private
*/
function end_element( $parser, $name ) {
// unset schema status
if (/*preg_match('/types$/', $name) ||*/
preg_match( '/schema$/', $name ) ) {
$this->status = "";
$this->appendDebug( $this->currentSchema->getDebug() );
$this->currentSchema->clearDebug();
$this->schemas[ $this->currentSchema->schemaTargetNamespace ][] = $this->currentSchema;
$this->debug( 'Parsing WSDL schema done' );
}
if ( $this->status == 'schema' ) {
$this->currentSchema->schemaEndElement( $parser, $name );
} else {
// bring depth down a notch
$this->depth --;
}
// end documentation
if ( $this->documentation ) {
//TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
//$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
$this->documentation = false;
}
}
/**
* element content handler
*
* @param string $parser XML parser object
* @param string $data element content
*
* @access private
*/
function character_data( $parser, $data ) {
$pos = isset( $this->depth_array[ $this->depth ] ) ? $this->depth_array[ $this->depth ] : 0;
if ( isset( $this->message[ $pos ]['cdata'] ) ) {
$this->message[ $pos ]['cdata'] .= $data;
}
if ( $this->documentation ) {
$this->documentation .= $data;
}
}
/**
* if authenticating, set user credentials here
*
* @param string $username
* @param string $password
* @param string $authtype (basic|digest|certificate|ntlm)
* @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
*
* @access public
*/
function setCredentials( $username, $password, $authtype = 'basic', $certRequest = array() ) {
$this->debug( "setCredentials username=$username authtype=$authtype certRequest=" );
$this->appendDebug( $this->varDump( $certRequest ) );
$this->username = $username;
$this->password = $password;
$this->authtype = $authtype;
$this->certRequest = $certRequest;
}
function getBindingData( $binding ) {
if ( is_array( $this->bindings[ $binding ] ) ) {
return $this->bindings[ $binding ];
}
}
/**
* returns an assoc array of operation names => operation data
*
* @param string $portName WSDL port name
* @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
*
* @return array
* @access public
*/
function getOperations( $portName = '', $bindingType = 'soap' ) {
$ops = array();
if ( $bindingType == 'soap' ) {
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
} elseif ( $bindingType == 'soap12' ) {
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
} else {
$this->debug( "getOperations bindingType $bindingType may not be supported" );
}
$this->debug( "getOperations for port '$portName' bindingType $bindingType" );
// loop thru ports
foreach ( $this->ports as $port => $portData ) {
$this->debug( "getOperations checking port $port bindingType " . $portData['bindingType'] );
if ( $portName == '' || $port == $portName ) {
// binding type of port matches parameter
if ( $portData['bindingType'] == $bindingType ) {
$this->debug( "getOperations found port $port bindingType $bindingType" );
//$this->debug("port data: " . $this->varDump($portData));
//$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
// merge bindings
if ( isset( $this->bindings[ $portData['binding'] ]['operations'] ) ) {
$ops = array_merge( $ops, $this->bindings[ $portData['binding'] ]['operations'] );
}
}
}
}
if ( count( $ops ) == 0 ) {
$this->debug( "getOperations found no operations for port '$portName' bindingType $bindingType" );
}
return $ops;
}
/**
* returns an associative array of data necessary for calling an operation
*
* @param string $operation name of operation
* @param string $bindingType type of binding eg: soap, soap12
*
* @return array
* @access public
*/
function getOperationData( $operation, $bindingType = 'soap' ) {
if ( $bindingType == 'soap' ) {
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
} elseif ( $bindingType == 'soap12' ) {
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
}
// loop thru ports
foreach ( $this->ports as $port => $portData ) {
// binding type of port matches parameter
if ( $portData['bindingType'] == $bindingType ) {
// get binding
//foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
foreach ( array_keys( $this->bindings[ $portData['binding'] ]['operations'] ) as $bOperation ) {
// note that we could/should also check the namespace here
if ( $operation == $bOperation ) {
$opData = $this->bindings[ $portData['binding'] ]['operations'][ $operation ];
return $opData;
}
}
}
}
}
/**
* returns an associative array of data necessary for calling an operation
*
* @param string $soapAction soapAction for operation
* @param string $bindingType type of binding eg: soap, soap12
*
* @return array
* @access public
*/
function getOperationDataForSoapAction( $soapAction, $bindingType = 'soap' ) {
if ( $bindingType == 'soap' ) {
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
} elseif ( $bindingType == 'soap12' ) {
$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
}
// loop thru ports
foreach ( $this->ports as $port => $portData ) {
// binding type of port matches parameter
if ( $portData['bindingType'] == $bindingType ) {
// loop through operations for the binding
foreach ( $this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData ) {
if ( $opData['soapAction'] == $soapAction ) {
return $opData;
}
}
}
}
}
/**
* returns an array of information about a given type
* returns false if no type exists by the given name
*
* typeDef = array(
* 'elements' => array(), // refs to elements array
* 'restrictionBase' => '',
* 'phpType' => '',
* 'order' => '(sequence|all)',
* 'attrs' => array() // refs to attributes array
* )
*
* @param string $type the type
* @param string $ns namespace (not prefix) of the type
*
* @return mixed
* @access public
* @see nusoap_xmlschema
*/
function getTypeDef( $type, $ns ) {
$this->debug( "in getTypeDef: type=$type, ns=$ns" );
if ( ( ! $ns ) && isset( $this->namespaces['tns'] ) ) {
$ns = $this->namespaces['tns'];
$this->debug( "in getTypeDef: type namespace forced to $ns" );
}
if ( ! isset( $this->schemas[ $ns ] ) ) {
foreach ( $this->schemas as $ns0 => $schema0 ) {
if ( strcasecmp( $ns, $ns0 ) == 0 ) {
$this->debug( "in getTypeDef: replacing schema namespace $ns with $ns0" );
$ns = $ns0;
break;
}
}
}
if ( isset( $this->schemas[ $ns ] ) ) {
$this->debug( "in getTypeDef: have schema for namespace $ns" );
for ( $i = 0; $i < count( $this->schemas[ $ns ] ); $i ++ ) {
$xs = &$this->schemas[ $ns ][ $i ];
$t = $xs->getTypeDef( $type );
$this->appendDebug( $xs->getDebug() );
$xs->clearDebug();
if ( $t ) {
$this->debug( "in getTypeDef: found type $type" );
if ( ! isset( $t['phpType'] ) ) {
// get info for type to tack onto the element
$uqType = substr( $t['type'], strrpos( $t['type'], ':' ) + 1 );
$ns = substr( $t['type'], 0, strrpos( $t['type'], ':' ) );
$etype = $this->getTypeDef( $uqType, $ns );
if ( $etype ) {
$this->debug( "found type for [element] $type:" );
$this->debug( $this->varDump( $etype ) );
if ( isset( $etype['phpType'] ) ) {
$t['phpType'] = $etype['phpType'];
}
if ( isset( $etype['elements'] ) ) {
$t['elements'] = $etype['elements'];
}
if ( isset( $etype['attrs'] ) ) {
$t['attrs'] = $etype['attrs'];
}
} else {
$this->debug( "did not find type for [element] $type" );
}
}
return $t;
}
}
$this->debug( "in getTypeDef: did not find type $type" );
} else {
$this->debug( "in getTypeDef: do not have schema for namespace $ns" );
}
return false;
}
/**
* prints html description of services
*
* @access private
*/
function webDescription() {
global $HTTP_SERVER_VARS;
if ( isset( $_SERVER ) ) {
$PHP_SELF = $_SERVER['PHP_SELF'];
} elseif ( isset( $HTTP_SERVER_VARS ) ) {
$PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
} else {
$this->setError( "Neither _SERVER nor HTTP_SERVER_VARS is available" );
}
$b = '
<html><head><title>NuSOAP: ' . $this->serviceName . '</title>
<style type="text/css">
body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
ul { margin-top: 10px; margin-left: 20px; }
li { list-style-type: none; margin-top: 10px; color: #000000; }
.content{
margin-left: 0px; padding-bottom: 2em; }
.nav {
padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
margin-top: 10px; margin-left: 0px; color: #000000;
background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
.title {
font-family: arial; font-size: 26px; color: #ffffff;
background-color: #999999; width: 100%;
margin-left: 0px; margin-right: 0px;
padding-top: 10px; padding-bottom: 10px;}
.hidden {
position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
font-family: arial; overflow: hidden; width: 600;
padding: 20px; font-size: 10px; background-color: #999999;
layer-background-color:#FFFFFF; }
a,a:active { color: charcoal; font-weight: bold; }
a:visited { color: #666666; font-weight: bold; }
a:hover { color: cc3300; font-weight: bold; }
</style>
<script language="JavaScript" type="text/javascript">
<!--
// POP-UP CAPTIONS...
function lib_bwcheck(){ //Browsercheck (needed)
this.ver=navigator.appVersion
this.agent=navigator.userAgent
this.dom=document.getElementById?1:0
this.opera5=this.agent.indexOf("Opera 5")>-1
this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
this.ie=this.ie4||this.ie5||this.ie6
this.mac=this.agent.indexOf("Mac")>-1
this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
this.ns4=(document.layers && !this.dom)?1:0;
this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
return this
}
var bw = new lib_bwcheck()
//Makes crossbrowser object.
function makeObj(obj){
this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
if(!this.evnt) return false
this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
this.writeIt=b_writeIt;
return this
}
// A unit of measure that will be added when setting the position of a layer.
//var px = bw.ns4||window.opera?"":"px";
function b_writeIt(text){
if (bw.ns4){this.wref.write(text);this.wref.close()}
else this.wref.innerHTML = text
}
//Shows the messages
var oDesc;
function popup(divid){
if(oDesc = new makeObj(divid)){
oDesc.css.visibility = "visible"
}
}
function popout(){ // Hides message
if(oDesc) oDesc.css.visibility = "hidden"
}
//-->
</script>
</head>
<body>
<div class=content>
<br><br>
<div class=title>' . $this->serviceName . '</div>
<div class=nav>
<p>View the <a href="' . $PHP_SELF . '?wsdl">WSDL</a> for the service.
Click on an operation name to view it's details.</p>
<ul>';
foreach ( $this->getOperations() as $op => $data ) {
$b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
// create hidden div
$b .= "<div id='$op' class='hidden'>
<a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
foreach ( $data as $donnie => $marie ) { // loop through opdata
if ( $donnie == 'input' || $donnie == 'output' ) { // show input/output data
$b .= "<font color='white'>" . ucfirst( $donnie ) . ':</font><br>';
foreach ( $marie as $captain => $tenille ) { // loop through data
if ( $captain == 'parts' ) { // loop thru parts
$b .= " $captain:<br>";
//if(is_array($tenille)){
foreach ( $tenille as $joanie => $chachi ) {
$b .= " $joanie: $chachi<br>";
}
//}
} else {
$b .= " $captain: $tenille<br>";
}
}
} else {
$b .= "<font color='white'>" . ucfirst( $donnie ) . ":</font> $marie<br>";
}
}
$b .= '</div>';
}
$b .= '
<ul>
</div>
</div></body></html>';
return $b;
}
/**
* serialize the parsed wsdl
*
* @param mixed $debug whether to put debug=1 in endpoint URL
*
* @return string serialization of WSDL
* @access public
*/
function serialize( $debug = 0 ) {
$xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
$xml .= "\n<definitions";
foreach ( $this->namespaces as $k => $v ) {
$xml .= " xmlns:$k=\"$v\"";
}
// 10.9.02 - add poulter fix for wsdl and tns declarations
if ( isset( $this->namespaces['wsdl'] ) ) {
$xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
}
if ( isset( $this->namespaces['tns'] ) ) {
$xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
}
$xml .= '>';
// imports
if ( sizeof( $this->import ) > 0 ) {
foreach ( $this->import as $ns => $list ) {
foreach ( $list as $ii ) {
if ( $ii['location'] != '' ) {
$xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
} else {
$xml .= '<import namespace="' . $ns . '" />';
}
}
}
}
// types
if ( count( $this->schemas ) >= 1 ) {
$xml .= "\n<types>\n";
foreach ( $this->schemas as $ns => $list ) {
foreach ( $list as $xs ) {
$xml .= $xs->serializeSchema();
}
}
$xml .= '</types>';
}
// messages
if ( count( $this->messages ) >= 1 ) {
foreach ( $this->messages as $msgName => $msgParts ) {
$xml .= "\n<message name=\"" . $msgName . '">';
if ( is_array( $msgParts ) ) {
foreach ( $msgParts as $partName => $partType ) {
// print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
if ( strpos( $partType, ':' ) ) {
$typePrefix = $this->getPrefixFromNamespace( $this->getPrefix( $partType ) );
} elseif ( isset( $this->typemap[ $this->namespaces['xsd'] ][ $partType ] ) ) {
// print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
$typePrefix = 'xsd';
} else {
foreach ( $this->typemap as $ns => $types ) {
if ( isset( $types[ $partType ] ) ) {
$typePrefix = $this->getPrefixFromNamespace( $ns );
}
}
if ( ! isset( $typePrefix ) ) {
die( "$partType has no namespace!" );
}
}
$ns = $this->getNamespaceFromPrefix( $typePrefix );
$localPart = $this->getLocalPart( $partType );
$typeDef = $this->getTypeDef( $localPart, $ns );
if ( $typeDef['typeClass'] == 'element' ) {
$elementortype = 'element';
if ( substr( $localPart, - 1 ) == '^' ) {
$localPart = substr( $localPart, 0, - 1 );
}
} else {
$elementortype = 'type';
}
$xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
}
}
$xml .= '</message>';
}
}
// bindings & porttypes
if ( count( $this->bindings ) >= 1 ) {
$binding_xml = '';
$portType_xml = '';
foreach ( $this->bindings as $bindingName => $attrs ) {
$binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
$binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
$portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
foreach ( $attrs['operations'] as $opName => $opParts ) {
$binding_xml .= "\n" . ' <operation name="' . $opName . '">';
$binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '"/>';
if ( isset( $opParts['input']['encodingStyle'] ) && $opParts['input']['encodingStyle'] != '' ) {
$enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
} else {
$enc_style = '';
}
$binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
if ( isset( $opParts['output']['encodingStyle'] ) && $opParts['output']['encodingStyle'] != '' ) {
$enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
} else {
$enc_style = '';
}
$binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
$binding_xml .= "\n" . ' </operation>';
$portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
if ( isset( $opParts['parameterOrder'] ) ) {
$portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
}
$portType_xml .= '>';
if ( isset( $opParts['documentation'] ) && $opParts['documentation'] != '' ) {
$portType_xml .= "\n" . ' <documentation>' . htmlspecialchars( $opParts['documentation'] ) . '</documentation>';
}
$portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
$portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
$portType_xml .= "\n" . ' </operation>';
}
$portType_xml .= "\n" . '</portType>';
$binding_xml .= "\n" . '</binding>';
}
$xml .= $portType_xml . $binding_xml;
}
// services
$xml .= "\n<service name=\"" . $this->serviceName . '">';
if ( count( $this->ports ) >= 1 ) {
foreach ( $this->ports as $pName => $attrs ) {
$xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
$xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ( $debug ? '?debug=1' : '' ) . '"/>';
$xml .= "\n" . ' </port>';
}
}
$xml .= "\n" . '</service>';
return $xml . "\n</definitions>";
}
/**
* determine whether a set of parameters are unwrapped
* when they are expect to be wrapped, Microsoft-style.
*
* @param string $type the type (element name) of the wrapper
* @param array $parameters the parameter values for the SOAP call
*
* @return boolean whether they parameters are unwrapped (and should be wrapped)
* @access private
*/
function parametersMatchWrapped( $type, &$parameters ) {
$this->debug( "in parametersMatchWrapped type=$type, parameters=" );
$this->appendDebug( $this->varDump( $parameters ) );
// split type into namespace:unqualified-type
if ( strpos( $type, ':' ) ) {
$uqType = substr( $type, strrpos( $type, ':' ) + 1 );
$ns = substr( $type, 0, strrpos( $type, ':' ) );
$this->debug( "in parametersMatchWrapped: got a prefixed type: $uqType, $ns" );
if ( $this->getNamespaceFromPrefix( $ns ) ) {
$ns = $this->getNamespaceFromPrefix( $ns );
$this->debug( "in parametersMatchWrapped: expanded prefixed type: $uqType, $ns" );
}
} else {
// TODO: should the type be compared to types in XSD, and the namespace
// set to XSD if the type matches?
$this->debug( "in parametersMatchWrapped: No namespace for type $type" );
$ns = '';
$uqType = $type;
}
// get the type information
if ( ! $typeDef = $this->getTypeDef( $uqType, $ns ) ) {
$this->debug( "in parametersMatchWrapped: $type ($uqType) is not a supported type." );
return false;
}
$this->debug( "in parametersMatchWrapped: found typeDef=" );
$this->appendDebug( $this->varDump( $typeDef ) );
if ( substr( $uqType, - 1 ) == '^' ) {
$uqType = substr( $uqType, 0, - 1 );
}
$phpType = $typeDef['phpType'];
$arrayType = ( isset( $typeDef['arrayType'] ) ? $typeDef['arrayType'] : '' );
$this->debug( "in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType" );
// we expect a complexType or element of complexType
if ( $phpType != 'struct' ) {
$this->debug( "in parametersMatchWrapped: not a struct" );
return false;
}
// see whether the parameter names match the elements
if ( isset( $typeDef['elements'] ) && is_array( $typeDef['elements'] ) ) {
$elements = 0;
$matches = 0;
foreach ( $typeDef['elements'] as $name => $attrs ) {
if ( isset( $parameters[ $name ] ) ) {
$this->debug( "in parametersMatchWrapped: have parameter named $name" );
$matches ++;
} else {
$this->debug( "in parametersMatchWrapped: do not have parameter named $name" );
}
$elements ++;
}
$this->debug( "in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names" );
if ( $matches == 0 ) {
return false;
}
return true;
}
// since there are no elements for the type, if the user passed no
// parameters, the parameters match wrapped.
$this->debug( "in parametersMatchWrapped: no elements type $ns:$uqType" );
return count( $parameters ) == 0;
}
/**
* serialize PHP values according to a WSDL message definition
* contrary to the method name, this is not limited to RPC
*
* TODO
* - multi-ref serialization
* - validate PHP values against type definitions, return errors if invalid
*
* @param string $operation operation name
* @param string $direction (input|output)
* @param mixed $parameters parameter value(s)
* @param string $bindingType (soap|soap12)
*
* @return mixed parameters serialized as XML or false on error (e.g. operation not found)
* @access public
*/
function serializeRPCParameters( $operation, $direction, $parameters, $bindingType = 'soap' ) {
$this->debug( "in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType" );
$this->appendDebug( 'parameters=' . $this->varDump( $parameters ) );
if ( $direction != 'input' && $direction != 'output' ) {
$this->debug( 'The value of the \$direction argument needs to be either "input" or "output"' );
$this->setError( 'The value of the \$direction argument needs to be either "input" or "output"' );
return false;
}
if ( ! $opData = $this->getOperationData( $operation, $bindingType ) ) {
$this->debug( 'Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType );
$this->setError( 'Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType );
return false;
}
$this->debug( 'in serializeRPCParameters: opData:' );
$this->appendDebug( $this->varDump( $opData ) );
// Get encoding style for output and set to current
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
if ( ( $direction == 'input' ) && isset( $opData['output']['encodingStyle'] ) && ( $opData['output']['encodingStyle'] != $encodingStyle ) ) {
$encodingStyle = $opData['output']['encodingStyle'];
$enc_style = $encodingStyle;
}
// set input params
$xml = '';
if ( isset( $opData[ $direction ]['parts'] ) && sizeof( $opData[ $direction ]['parts'] ) > 0 ) {
$parts = &$opData[ $direction ]['parts'];
$part_count = sizeof( $parts );
$style = $opData['style'];
$use = $opData[ $direction ]['use'];
$this->debug( "have $part_count part(s) to serialize using $style/$use" );
if ( is_array( $parameters ) ) {
$parametersArrayType = $this->isArraySimpleOrStruct( $parameters );
$parameter_count = count( $parameters );
$this->debug( "have $parameter_count parameter(s) provided as $parametersArrayType to serialize" );
// check for Microsoft-style wrapped parameters
if ( $style == 'document' && $use == 'literal' && $part_count == 1 && isset( $parts['parameters'] ) ) {
$this->debug( 'check whether the caller has wrapped the parameters' );
if ( $direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1 ) {
// TODO: consider checking here for double-wrapping, when
// service function wraps, then NuSOAP wraps again
$this->debug( "change simple array to associative with 'parameters' element" );
$parameters['parameters'] = $parameters[0];
unset( $parameters[0] );
}
if ( ( $parametersArrayType == 'arrayStruct' || $parameter_count == 0 ) && ! isset( $parameters['parameters'] ) ) {
$this->debug( 'check whether caller\'s parameters match the wrapped ones' );
if ( $this->parametersMatchWrapped( $parts['parameters'], $parameters ) ) {
$this->debug( 'wrap the parameters for the caller' );
$parameters = array( 'parameters' => $parameters );
$parameter_count = 1;
}
}
}
foreach ( $parts as $name => $type ) {
$this->debug( "serializing part $name of type $type" );
// Track encoding style
if ( isset( $opData[ $direction ]['encodingStyle'] ) && $encodingStyle != $opData[ $direction ]['encodingStyle'] ) {
$encodingStyle = $opData[ $direction ]['encodingStyle'];
$enc_style = $encodingStyle;
} else {
$enc_style = false;
}
// NOTE: add error handling here
// if serializeType returns false, then catch global error and fault
if ( $parametersArrayType == 'arraySimple' ) {
$p = array_shift( $parameters );
$this->debug( 'calling serializeType w/indexed param' );
$xml .= $this->serializeType( $name, $type, $p, $use, $enc_style );
} elseif ( isset( $parameters[ $name ] ) ) {
$this->debug( 'calling serializeType w/named param' );
$xml .= $this->serializeType( $name, $type, $parameters[ $name ], $use, $enc_style );
} else {
// TODO: only send nillable
$this->debug( 'calling serializeType w/null param' );
$xml .= $this->serializeType( $name, $type, null, $use, $enc_style );
}
}
} else {
$this->debug( 'no parameters passed.' );
}
}
$this->debug( "serializeRPCParameters returning: $xml" );
return $xml;
}
/**
* serialize a PHP value according to a WSDL message definition
*
* TODO
* - multi-ref serialization
* - validate PHP values against type definitions, return errors if invalid
*
* @param string $operation operation name
* @param string $direction (input|output)
* @param mixed $parameters parameter value(s)
*
* @return mixed parameters serialized as XML or false on error (e.g. operation not found)
* @access public
* @deprecated
*/
function serializeParameters( $operation, $direction, $parameters ) {
$this->debug( "in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion" );
$this->appendDebug( 'parameters=' . $this->varDump( $parameters ) );
if ( $direction != 'input' && $direction != 'output' ) {
$this->debug( 'The value of the \$direction argument needs to be either "input" or "output"' );
$this->setError( 'The value of the \$direction argument needs to be either "input" or "output"' );
return false;
}
if ( ! $opData = $this->getOperationData( $operation ) ) {
$this->debug( 'Unable to retrieve WSDL data for operation: ' . $operation );
$this->setError( 'Unable to retrieve WSDL data for operation: ' . $operation );
return false;
}
$this->debug( 'opData:' );
$this->appendDebug( $this->varDump( $opData ) );
// Get encoding style for output and set to current
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
if ( ( $direction == 'input' ) && isset( $opData['output']['encodingStyle'] ) && ( $opData['output']['encodingStyle'] != $encodingStyle ) ) {
$encodingStyle = $opData['output']['encodingStyle'];
$enc_style = $encodingStyle;
}
// set input params
$xml = '';
if ( isset( $opData[ $direction ]['parts'] ) && sizeof( $opData[ $direction ]['parts'] ) > 0 ) {
$use = $opData[ $direction ]['use'];
$this->debug( "use=$use" );
$this->debug( 'got ' . count( $opData[ $direction ]['parts'] ) . ' part(s)' );
if ( is_array( $parameters ) ) {
$parametersArrayType = $this->isArraySimpleOrStruct( $parameters );
$this->debug( 'have ' . $parametersArrayType . ' parameters' );
foreach ( $opData[ $direction ]['parts'] as $name => $type ) {
$this->debug( 'serializing part "' . $name . '" of type "' . $type . '"' );
// Track encoding style
if ( isset( $opData[ $direction ]['encodingStyle'] ) && $encodingStyle != $opData[ $direction ]['encodingStyle'] ) {
$encodingStyle = $opData[ $direction ]['encodingStyle'];
$enc_style = $encodingStyle;
} else {
$enc_style = false;
}
// NOTE: add error handling here
// if serializeType returns false, then catch global error and fault
if ( $parametersArrayType == 'arraySimple' ) {
$p = array_shift( $parameters );
$this->debug( 'calling serializeType w/indexed param' );
$xml .= $this->serializeType( $name, $type, $p, $use, $enc_style );
} elseif ( isset( $parameters[ $name ] ) ) {
$this->debug( 'calling serializeType w/named param' );
$xml .= $this->serializeType( $name, $type, $parameters[ $name ], $use, $enc_style );
} else {
// TODO: only send nillable
$this->debug( 'calling serializeType w/null param' );
$xml .= $this->serializeType( $name, $type, null, $use, $enc_style );
}
}
} else {
$this->debug( 'no parameters passed.' );
}
}
$this->debug( "serializeParameters returning: $xml" );
return $xml;
}
/**
* serializes a PHP value according a given type definition
*
* @param string $name name of value (part or element)
* @param string $type XML schema type of value (type or element)
* @param mixed $value a native PHP value (parameter value)
* @param string $use use for part (encoded|literal)
* @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
* @param boolean $unqualified a kludge for what should be XML namespace form handling
*
* @return string value serialized as an XML string
* @access private
*/
function serializeType( $name, $type, $value, $use = 'encoded', $encodingStyle = false, $unqualified = false ) {
$this->debug( "in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ( $unqualified ? "unqualified" : "qualified" ) );
$this->appendDebug( "value=" . $this->varDump( $value ) );
if ( $use == 'encoded' && $encodingStyle ) {
$encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
}
// if a soapval has been supplied, let its type override the WSDL
if ( is_object( $value ) && get_class( $value ) == 'soapval' ) {
if ( $value->type_ns ) {
$type = $value->type_ns . ':' . $value->type;
$forceType = true;
$this->debug( "in serializeType: soapval overrides type to $type" );
} elseif ( $value->type ) {
$type = $value->type;
$forceType = true;
$this->debug( "in serializeType: soapval overrides type to $type" );
} else {
$forceType = false;
$this->debug( "in serializeType: soapval does not override type" );
}
$attrs = $value->attributes;
$value = $value->value;
$this->debug( "in serializeType: soapval overrides value to $value" );
if ( $attrs ) {
if ( ! is_array( $value ) ) {
$value['!'] = $value;
}
foreach ( $attrs as $n => $v ) {
$value[ '!' . $n ] = $v;
}
$this->debug( "in serializeType: soapval provides attributes" );
}
} else {
$forceType = false;
}
$xml = '';
if ( strpos( $type, ':' ) ) {
$uqType = substr( $type, strrpos( $type, ':' ) + 1 );
$ns = substr( $type, 0, strrpos( $type, ':' ) );
$this->debug( "in serializeType: got a prefixed type: $uqType, $ns" );
if ( $this->getNamespaceFromPrefix( $ns ) ) {
$ns = $this->getNamespaceFromPrefix( $ns );
$this->debug( "in serializeType: expanded prefixed type: $uqType, $ns" );
}
if ( $ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/' ) {
$this->debug( 'in serializeType: type namespace indicates XML Schema or SOAP Encoding type' );
if ( $unqualified && $use == 'literal' ) {
$elementNS = " xmlns=\"\"";
} else {
$elementNS = '';
}
if ( is_null( $value ) ) {
if ( $use == 'literal' ) {
// TODO: depends on minOccurs
$xml = "<$name$elementNS/>";
} else {
// TODO: depends on nillable, which should be checked before calling this method
$xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"/>";
}
$this->debug( "in serializeType: returning: $xml" );
return $xml;
}
if ( $uqType == 'Array' ) {
// JBoss/Axis does this sometimes
return $this->serialize_val( $value, $name, false, false, false, false, $use );
}
if ( $uqType == 'boolean' ) {
if ( ( is_string( $value ) && $value == 'false' ) || ( ! $value ) ) {
$value = 'false';
} else {
$value = 'true';
}
}
if ( $uqType == 'string' && gettype( $value ) == 'string' ) {
$value = $this->expandEntities( $value );
}
if ( ( $uqType == 'long' || $uqType == 'unsignedLong' ) && gettype( $value ) == 'double' ) {
$value = sprintf( "%.0lf", $value );
}
// it's a scalar
// TODO: what about null/nil values?
// check type isn't a custom type extending xmlschema namespace
if ( ! $this->getTypeDef( $uqType, $ns ) ) {
if ( $use == 'literal' ) {
if ( $forceType ) {
$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\">$value</$name>";
} else {
$xml = "<$name$elementNS>$value</$name>";
}
} else {
$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"$encodingStyle>$value</$name>";
}
$this->debug( "in serializeType: returning: $xml" );
return $xml;
}
$this->debug( 'custom type extends XML Schema or SOAP Encoding namespace (yuck)' );
} else if ( $ns == 'http://xml.apache.org/xml-soap' ) {
$this->debug( 'in serializeType: appears to be Apache SOAP type' );
if ( $uqType == 'Map' ) {
$tt_prefix = $this->getPrefixFromNamespace( 'http://xml.apache.org/xml-soap' );
if ( ! $tt_prefix ) {
$this->debug( 'in serializeType: Add namespace for Apache SOAP type' );
$tt_prefix = 'ns' . rand( 1000, 9999 );
$this->namespaces[ $tt_prefix ] = 'http://xml.apache.org/xml-soap';
// force this to be added to usedNamespaces
$tt_prefix = $this->getPrefixFromNamespace( 'http://xml.apache.org/xml-soap' );
}
$contents = '';
foreach ( $value as $k => $v ) {
$this->debug( "serializing map element: key $k, value $v" );
$contents .= '<item>';
$contents .= $this->serialize_val( $k, 'key', false, false, false, false, $use );
$contents .= $this->serialize_val( $v, 'value', false, false, false, false, $use );
$contents .= '</item>';
}
if ( $use == 'literal' ) {
if ( $forceType ) {
$xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
} else {
$xml = "<$name>$contents</$name>";
}
} else {
$xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
}
$this->debug( "in serializeType: returning: $xml" );
return $xml;
}
$this->debug( 'in serializeType: Apache SOAP type, but only support Map' );
}
} else {
// TODO: should the type be compared to types in XSD, and the namespace
// set to XSD if the type matches?
$this->debug( "in serializeType: No namespace for type $type" );
$ns = '';
$uqType = $type;
}
if ( ! $typeDef = $this->getTypeDef( $uqType, $ns ) ) {
$this->setError( "$type ($uqType) is not a supported type." );
$this->debug( "in serializeType: $type ($uqType) is not a supported type." );
return false;
} else {
$this->debug( "in serializeType: found typeDef" );
$this->appendDebug( 'typeDef=' . $this->varDump( $typeDef ) );
if ( substr( $uqType, - 1 ) == '^' ) {
$uqType = substr( $uqType, 0, - 1 );
}
}
if ( ! isset( $typeDef['phpType'] ) ) {
$this->setError( "$type ($uqType) has no phpType." );
$this->debug( "in serializeType: $type ($uqType) has no phpType." );
return false;
}
$phpType = $typeDef['phpType'];
$this->debug( "in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . ( isset( $typeDef['arrayType'] ) ? $typeDef['arrayType'] : '' ) );
// if php type == struct, map value to the <all> element names
if ( $phpType == 'struct' ) {
if ( isset( $typeDef['typeClass'] ) && $typeDef['typeClass'] == 'element' ) {
$elementName = $uqType;
if ( isset( $typeDef['form'] ) && ( $typeDef['form'] == 'qualified' ) ) {
$elementNS = " xmlns=\"$ns\"";
} else {
$elementNS = " xmlns=\"\"";
}
} else {
$elementName = $name;
if ( $unqualified ) {
$elementNS = " xmlns=\"\"";
} else {
$elementNS = '';
}
}
if ( is_null( $value ) ) {
if ( $use == 'literal' ) {
// TODO: depends on minOccurs and nillable
$xml = "<$elementName$elementNS/>";
} else {
$xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"/>";
}
$this->debug( "in serializeType: returning: $xml" );
return $xml;
}
if ( is_object( $value ) ) {
$value = get_object_vars( $value );
}
if ( is_array( $value ) ) {
$elementAttrs = $this->serializeComplexTypeAttributes( $typeDef, $value, $ns, $uqType );
if ( $use == 'literal' ) {
if ( $forceType ) {
$xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\">";
} else {
$xml = "<$elementName$elementNS$elementAttrs>";
}
} else {
$xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"$encodingStyle>";
}
if ( isset( $typeDef['simpleContent'] ) && $typeDef['simpleContent'] == 'true' ) {
if ( isset( $value['!'] ) ) {
$xml .= $value['!'];
$this->debug( "in serializeType: serialized simpleContent for type $type" );
} else {
$this->debug( "in serializeType: no simpleContent to serialize for type $type" );
}
} else {
// complexContent
$xml .= $this->serializeComplexTypeElements( $typeDef, $value, $ns, $uqType, $use, $encodingStyle );
}
$xml .= "</$elementName>";
} else {
$this->debug( "in serializeType: phpType is struct, but value is not an array" );
$this->setError( "phpType is struct, but value is not an array: see debug output for details" );
$xml = '';
}
} elseif ( $phpType == 'array' ) {
if ( isset( $typeDef['form'] ) && ( $typeDef['form'] == 'qualified' ) ) {
$elementNS = " xmlns=\"$ns\"";
} else {
if ( $unqualified ) {
$elementNS = " xmlns=\"\"";
} else {
$elementNS = '';
}
}
if ( is_null( $value ) ) {
if ( $use == 'literal' ) {
// TODO: depends on minOccurs
$xml = "<$name$elementNS/>";
} else {
$xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
$this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' ) .
":Array\" " .
$this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' ) .
':arrayType="' .
$this->getPrefixFromNamespace( $this->getPrefix( $typeDef['arrayType'] ) ) .
':' .
$this->getLocalPart( $typeDef['arrayType'] ) . "[0]\"/>";
}
$this->debug( "in serializeType: returning: $xml" );
return $xml;
}
if ( isset( $typeDef['multidimensional'] ) ) {
$nv = array();
foreach ( $value as $v ) {
$cols = ',' . sizeof( $v );
$nv = array_merge( $nv, $v );
}
$value = $nv;
} else {
$cols = '';
}
if ( is_array( $value ) && sizeof( $value ) >= 1 ) {
$rows = sizeof( $value );
$contents = '';
foreach ( $value as $k => $v ) {
$this->debug( "serializing array element: $k, $v of type: $typeDef[arrayType]" );
//if (strpos($typeDef['arrayType'], ':') ) {
if ( ! in_array( $typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'] ) ) {
$contents .= $this->serializeType( 'item', $typeDef['arrayType'], $v, $use );
} else {
$contents .= $this->serialize_val( $v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use );
}
}
} else {
$rows = 0;
$contents = null;
}
// TODO: for now, an empty value will be serialized as a zero element
// array. Revisit this when coding the handling of null/nil values.
if ( $use == 'literal' ) {
$xml = "<$name$elementNS>"
. $contents
. "</$name>";
} else {
$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' ) . ':Array" ' .
$this->getPrefixFromNamespace( 'http://schemas.xmlsoap.org/soap/encoding/' )
. ':arrayType="'
. $this->getPrefixFromNamespace( $this->getPrefix( $typeDef['arrayType'] ) )
. ":" . $this->getLocalPart( $typeDef['arrayType'] ) . "[$rows$cols]\">"
. $contents
. "</$name>";
}
} elseif ( $phpType == 'scalar' ) {
if ( isset( $typeDef['form'] ) && ( $typeDef['form'] == 'qualified' ) ) {
$elementNS = " xmlns=\"$ns\"";
} else {
if ( $unqualified ) {
$elementNS = " xmlns=\"\"";
} else {
$elementNS = '';
}
}
if ( $use == 'literal' ) {
if ( $forceType ) {
$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\">$value</$name>";
} else {
$xml = "<$name$elementNS>$value</$name>";
}
} else {
$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace( $ns ) . ":$uqType\"$encodingStyle>$value</$name>";
}
}
$this->debug( "in serializeType: returning: $xml" );
return $xml;
}
/**
* serializes the attributes for a complexType
*
* @param array $typeDef our internal representation of an XML schema type (or element)
* @param mixed $value a native PHP value (parameter value)
* @param string $ns the namespace of the type
* @param string $uqType the local part of the type
*
* @return string value serialized as an XML string
* @access private
*/
function serializeComplexTypeAttributes( $typeDef, $value, $ns, $uqType ) {
$this->debug( "serializeComplexTypeAttributes for XML Schema type $ns:$uqType" );
$xml = '';
if ( isset( $typeDef['extensionBase'] ) ) {
$nsx = $this->getPrefix( $typeDef['extensionBase'] );
$uqTypex = $this->getLocalPart( $typeDef['extensionBase'] );
if ( $this->getNamespaceFromPrefix( $nsx ) ) {
$nsx = $this->getNamespaceFromPrefix( $nsx );
}
if ( $typeDefx = $this->getTypeDef( $uqTypex, $nsx ) ) {
$this->debug( "serialize attributes for extension base $nsx:$uqTypex" );
$xml .= $this->serializeComplexTypeAttributes( $typeDefx, $value, $nsx, $uqTypex );
} else {
$this->debug( "extension base $nsx:$uqTypex is not a supported type" );
}
}
if ( isset( $typeDef['attrs'] ) && is_array( $typeDef['attrs'] ) ) {
$this->debug( "serialize attributes for XML Schema type $ns:$uqType" );
if ( is_array( $value ) ) {
$xvalue = $value;
} elseif ( is_object( $value ) ) {
$xvalue = get_object_vars( $value );
} else {
$this->debug( "value is neither an array nor an object for XML Schema type $ns:$uqType" );
$xvalue = array();
}
foreach ( $typeDef['attrs'] as $aName => $attrs ) {
if ( isset( $xvalue[ '!' . $aName ] ) ) {
$xname = '!' . $aName;
$this->debug( "value provided for attribute $aName with key $xname" );
} elseif ( isset( $xvalue[ $aName ] ) ) {
$xname = $aName;
$this->debug( "value provided for attribute $aName with key $xname" );
} elseif ( isset( $attrs['default'] ) ) {
$xname = '!' . $aName;
$xvalue[ $xname ] = $attrs['default'];
$this->debug( 'use default value of ' . $xvalue[ $aName ] . ' for attribute ' . $aName );
} else {
$xname = '';
$this->debug( "no value provided for attribute $aName" );
}
if ( $xname ) {
$xml .= " $aName=\"" . $this->expandEntities( $xvalue[ $xname ] ) . "\"";
}
}
} else {
$this->debug( "no attributes to serialize for XML Schema type $ns:$uqType" );
}
return $xml;
}
/**
* serializes the elements for a complexType
*
* @param array $typeDef our internal representation of an XML schema type (or element)
* @param mixed $value a native PHP value (parameter value)
* @param string $ns the namespace of the type
* @param string $uqType the local part of the type
* @param string $use use for part (encoded|literal)
* @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
*
* @return string value serialized as an XML string
* @access private
*/
function serializeComplexTypeElements( $typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false ) {
$this->debug( "in serializeComplexTypeElements for XML Schema type $ns:$uqType" );
$xml = '';
if ( isset( $typeDef['extensionBase'] ) ) {
$nsx = $this->getPrefix( $typeDef['extensionBase'] );
$uqTypex = $this->getLocalPart( $typeDef['extensionBase'] );
if ( $this->getNamespaceFromPrefix( $nsx ) ) {
$nsx = $this->getNamespaceFromPrefix( $nsx );
}
if ( $typeDefx = $this->getTypeDef( $uqTypex, $nsx ) ) {
$this->debug( "serialize elements for extension base $nsx:$uqTypex" );
$xml .= $this->serializeComplexTypeElements( $typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle );
} else {
$this->debug( "extension base $nsx:$uqTypex is not a supported type" );
}
}
if ( isset( $typeDef['elements'] ) && is_array( $typeDef['elements'] ) ) {
$this->debug( "in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType" );
if ( is_array( $value ) ) {
$xvalue = $value;
} elseif ( is_object( $value ) ) {
$xvalue = get_object_vars( $value );
} else {
$this->debug( "value is neither an array nor an object for XML Schema type $ns:$uqType" );
$xvalue = array();
}
// toggle whether all elements are present - ideally should validate against schema
if ( count( $typeDef['elements'] ) != count( $xvalue ) ) {
$optionals = true;
}
foreach ( $typeDef['elements'] as $eName => $attrs ) {
if ( ! isset( $xvalue[ $eName ] ) ) {
if ( isset( $attrs['default'] ) ) {
$xvalue[ $eName ] = $attrs['default'];
$this->debug( 'use default value of ' . $xvalue[ $eName ] . ' for element ' . $eName );
}
}
// if user took advantage of a minOccurs=0, then only serialize named parameters
if ( isset( $optionals )
&& ( ! isset( $xvalue[ $eName ] ) )
&& ( ( ! isset( $attrs['nillable'] ) ) || $attrs['nillable'] != 'true' )
) {
if ( isset( $attrs['minOccurs'] ) && $attrs['minOccurs'] <> '0' ) {
$this->debug( "apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs'] );
}
// do nothing
$this->debug( "no value provided for complexType element $eName and element is not nillable, so serialize nothing" );
} else {
// get value
if ( isset( $xvalue[ $eName ] ) ) {
$v = $xvalue[ $eName ];
} else {
$v = null;
}
if ( isset( $attrs['form'] ) ) {
$unqualified = ( $attrs['form'] == 'unqualified' );
} else {
$unqualified = false;
}
if ( isset( $attrs['maxOccurs'] ) && ( $attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1 ) && isset( $v ) && is_array( $v ) && $this->isArraySimpleOrStruct( $v ) == 'arraySimple' ) {
$vv = $v;
foreach ( $vv as $k => $v ) {
if ( isset( $attrs['type'] ) || isset( $attrs['ref'] ) ) {
// serialize schema-defined type
$xml .= $this->serializeType( $eName, isset( $attrs['type'] ) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified );
} else {
// serialize generic type (can this ever really happen?)
$this->debug( "calling serialize_val() for $v, $eName, false, false, false, false, $use" );
$xml .= $this->serialize_val( $v, $eName, false, false, false, false, $use );
}
}
} else {
if ( is_null( $v ) && isset( $attrs['minOccurs'] ) && $attrs['minOccurs'] == '0' ) {
// do nothing
} elseif ( is_null( $v ) && isset( $attrs['nillable'] ) && $attrs['nillable'] == 'true' ) {
// TODO: serialize a nil correctly, but for now serialize schema-defined type
$xml .= $this->serializeType( $eName, isset( $attrs['type'] ) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified );
} elseif ( isset( $attrs['type'] ) || isset( $attrs['ref'] ) ) {
// serialize schema-defined type
$xml .= $this->serializeType( $eName, isset( $attrs['type'] ) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified );
} else {
// serialize generic type (can this ever really happen?)
$this->debug( "calling serialize_val() for $v, $eName, false, false, false, false, $use" );
$xml .= $this->serialize_val( $v, $eName, false, false, false, false, $use );
}
}
}
}
} else {
$this->debug( "no elements to serialize for XML Schema type $ns:$uqType" );
}
return $xml;
}
/**
* adds an XML Schema complex type to the WSDL types
*
* @param string $name
* @param string $typeClass (complexType|simpleType|attribute)
* @param string $phpType currently supported are array and struct (php assoc array)
* @param string $compositor (all|sequence|choice)
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param array $elements e.g. array ( name => array(name=>'',type=>'') )
* @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
* @param string $arrayType as namespace:name (xsd:string)
*
* @see nusoap_xmlschema
* @access public
*/
function addComplexType( $name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '' ) {
if ( count( $elements ) > 0 ) {
$eElements = array();
foreach ( $elements as $n => $e ) {
// expand each element
$ee = array();
foreach ( $e as $k => $v ) {
$k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
$v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
$ee[ $k ] = $v;
}
$eElements[ $n ] = $ee;
}
$elements = $eElements;
}
if ( count( $attrs ) > 0 ) {
foreach ( $attrs as $n => $a ) {
// expand each attribute
foreach ( $a as $k => $v ) {
$k = strpos( $k, ':' ) ? $this->expandQname( $k ) : $k;
$v = strpos( $v, ':' ) ? $this->expandQname( $v ) : $v;
$aa[ $k ] = $v;
}
$eAttrs[ $n ] = $aa;
}
$attrs = $eAttrs;
}
$restrictionBase = strpos( $restrictionBase, ':' ) ? $this->expandQname( $restrictionBase ) : $restrictionBase;
$arrayType = strpos( $arrayType, ':' ) ? $this->expandQname( $arrayType ) : $arrayType;
$typens = isset( $this->namespaces['types'] ) ? $this->namespaces['types'] : $this->namespaces['tns'];
$this->schemas[ $typens ][0]->addComplexType( $name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType );
}
/**
* adds an XML Schema simple type to the WSDL types
*
* @param string $name
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
* @param string $typeClass (should always be simpleType)
* @param string $phpType (should always be scalar)
* @param array $enumeration array of values
*
* @see nusoap_xmlschema
* @access public
*/
function addSimpleType( $name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array() ) {
$restrictionBase = strpos( $restrictionBase, ':' ) ? $this->expandQname( $restrictionBase ) : $restrictionBase;
$typens = isset( $this->namespaces['types'] ) ? $this->namespaces['types'] : $this->namespaces['tns'];
$this->schemas[ $typens ][0]->addSimpleType( $name, $restrictionBase, $typeClass, $phpType, $enumeration );
}
/**
* adds an element to the WSDL types
*
* @param array $attrs attributes that must include name and type
*
* @see nusoap_xmlschema
* @access public
*/
function addElement( $attrs ) {
$typens = isset( $this->namespaces['types'] ) ? $this->namespaces['types'] : $this->namespaces['tns'];
$this->schemas[ $typens ][0]->addElement( $attrs );
}
/**
* register an operation with the server
*
* @param string $name operation (method) name
* @param array $in assoc array of input values: key = param name, value = param type
* @param array $out assoc array of output values: key = param name, value = param type
* @param string $namespace optional The namespace for the operation
* @param string $soapaction optional The soapaction for the operation
* @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically
* @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
* @param string $documentation optional The description to include in the WSDL
* @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
*
* @access public
*/
function addOperation( $name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '' ) {
if ( $use == 'encoded' && $encodingStyle == '' ) {
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
}
if ( $style == 'document' ) {
$elements = array();
foreach ( $in as $n => $t ) {
$elements[ $n ] = array( 'name' => $n, 'type' => $t, 'form' => 'unqualified' );
}
$this->addComplexType( $name . 'RequestType', 'complexType', 'struct', 'all', '', $elements );
$this->addElement( array( 'name' => $name, 'type' => $name . 'RequestType' ) );
$in = array( 'parameters' => 'tns:' . $name . '^' );
$elements = array();
foreach ( $out as $n => $t ) {
$elements[ $n ] = array( 'name' => $n, 'type' => $t, 'form' => 'unqualified' );
}
$this->addComplexType( $name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements );
$this->addElement( array(
'name' => $name . 'Response',
'type' => $name . 'ResponseType',
'form' => 'qualified'
) );
$out = array( 'parameters' => 'tns:' . $name . 'Response' . '^' );
}
// get binding
$this->bindings[ $this->serviceName . 'Binding' ]['operations'][ $name ] =
array(
'name' => $name,
'binding' => $this->serviceName . 'Binding',
'endpoint' => $this->endpoint,
'soapAction' => $soapaction,
'style' => $style,
'input' => array(
'use' => $use,
'namespace' => $namespace,
'encodingStyle' => $encodingStyle,
'message' => $name . 'Request',
'parts' => $in
),
'output' => array(
'use' => $use,
'namespace' => $namespace,
'encodingStyle' => $encodingStyle,
'message' => $name . 'Response',
'parts' => $out
),
'namespace' => $namespace,
'transport' => 'http://schemas.xmlsoap.org/soap/http',
'documentation' => $documentation
);
// add portTypes
// add messages
if ( $in ) {
foreach ( $in as $pName => $pType ) {
if ( strpos( $pType, ':' ) ) {
$pType = $this->getNamespaceFromPrefix( $this->getPrefix( $pType ) ) . ":" . $this->getLocalPart( $pType );
}
$this->messages[ $name . 'Request' ][ $pName ] = $pType;
}
} else {
$this->messages[ $name . 'Request' ] = '0';
}
if ( $out ) {
foreach ( $out as $pName => $pType ) {
if ( strpos( $pType, ':' ) ) {
$pType = $this->getNamespaceFromPrefix( $this->getPrefix( $pType ) ) . ":" . $this->getLocalPart( $pType );
}
$this->messages[ $name . 'Response' ][ $pName ] = $pType;
}
} else {
$this->messages[ $name . 'Response' ] = '0';
}
return true;
}
}
?><?php
/**
*
* nusoap_parser class parses SOAP XML messages into native PHP values
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_parser extends nusoap_base {
var $xml = '';
var $xml_encoding = '';
var $method = '';
var $root_struct = '';
var $root_struct_name = '';
var $root_struct_namespace = '';
var $root_header = '';
var $document = ''; // incoming SOAP body (text)
// determines where in the message we are (envelope,header,body,method)
var $status = '';
var $position = 0;
var $depth = 0;
var $default_namespace = '';
var $namespaces = array();
var $message = array();
var $parent = '';
var $fault = false;
var $fault_code = '';
var $fault_str = '';
var $fault_detail = '';
var $depth_array = array();
var $debug_flag = true;
var $soapresponse = null; // parsed SOAP Body
var $soapheader = null; // parsed SOAP Header
var $responseHeaders = ''; // incoming SOAP headers (text)
var $body_position = 0;
// for multiref parsing:
// array of id => pos
var $ids = array();
// array of id => hrefs => pos
var $multirefs = array();
// toggle for auto-decoding element content
var $decode_utf8 = true;
/**
* constructor that actually does the parsing
*
* @param string $xml SOAP message
* @param string $encoding character encoding scheme of message
* @param string $method method for which XML is parsed (unused?)
* @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
*
* @access public
*/
function nusoap_parser( $xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true ) {
parent::nusoap_base();
$this->xml = $xml;
$this->xml_encoding = $encoding;
$this->method = $method;
$this->decode_utf8 = $decode_utf8;
// Check whether content has been read.
if ( ! empty( $xml ) ) {
// Check XML encoding
$pos_xml = strpos( $xml, '<?xml' );
if ( $pos_xml !== false ) {
$xml_decl = substr( $xml, $pos_xml, strpos( $xml, '?>', $pos_xml + 2 ) - $pos_xml + 1 );
if ( preg_match( "/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res ) ) {
$xml_encoding = $res[1];
if ( strtoupper( $xml_encoding ) != $encoding ) {
$err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
$this->debug( $err );
if ( $encoding != 'ISO-8859-1' || strtoupper( $xml_encoding ) != 'UTF-8' ) {
$this->setError( $err );
return;
}
// when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
} else {
$this->debug( 'Charset from HTTP Content-Type matches encoding from XML declaration' );
}
} else {
$this->debug( 'No encoding specified in XML declaration' );
}
} else {
$this->debug( 'No XML declaration' );
}
$this->debug( 'Entering nusoap_parser(), length=' . strlen( $xml ) . ', encoding=' . $encoding );
// Create an XML parser - why not xml_parser_create_ns?
$this->parser = xml_parser_create( $this->xml_encoding );
// Set the options for parsing the XML data.
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
xml_parser_set_option( $this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding );
// Set the object for the parser.
xml_set_object( $this->parser, $this );
// Set the element handlers for the parser.
xml_set_element_handler( $this->parser, 'start_element', 'end_element' );
xml_set_character_data_handler( $this->parser, 'character_data' );
// Parse the XML file.
if ( ! xml_parse( $this->parser, $xml, true ) ) {
// Display an error message.
$err = sprintf( 'XML error parsing SOAP payload on line %d: %s',
xml_get_current_line_number( $this->parser ),
xml_error_string( xml_get_error_code( $this->parser ) ) );
$this->debug( $err );
$this->debug( "XML payload:\n" . $xml );
$this->setError( $err );
} else {
$this->debug( 'in nusoap_parser ctor, message:' );
$this->appendDebug( $this->varDump( $this->message ) );
$this->debug( 'parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name );
// get final value
$this->soapresponse = $this->message[ $this->root_struct ]['result'];
// get header value
if ( $this->root_header != '' && isset( $this->message[ $this->root_header ]['result'] ) ) {
$this->soapheader = $this->message[ $this->root_header ]['result'];
}
// resolve hrefs/ids
if ( sizeof( $this->multirefs ) > 0 ) {
foreach ( $this->multirefs as $id => $hrefs ) {
$this->debug( 'resolving multirefs for id: ' . $id );
$idVal = $this->buildVal( $this->ids[ $id ] );
if ( is_array( $idVal ) && isset( $idVal['!id'] ) ) {
unset( $idVal['!id'] );
}
foreach ( $hrefs as $refPos => $ref ) {
$this->debug( 'resolving href at pos ' . $refPos );
$this->multirefs[ $id ][ $refPos ] = $idVal;
}
}
}
}
xml_parser_free( $this->parser );
} else {
$this->debug( 'xml was empty, didn\'t parse!' );
$this->setError( 'xml was empty, didn\'t parse!' );
}
}
/**
* start-element handler
*
* @param resource $parser XML parser object
* @param string $name element name
* @param array $attrs associative array of attributes
*
* @access private
*/
function start_element( $parser, $name, $attrs ) {
// position in a total number of elements, starting from 0
// update class level pos
$pos = $this->position ++;
// and set mine
$this->message[ $pos ] = array( 'pos' => $pos, 'children' => '', 'cdata' => '' );
// depth = how many levels removed from root?
// set mine as current global depth and increment global depth value
$this->message[ $pos ]['depth'] = $this->depth ++;
// else add self as child to whoever the current parent is
if ( $pos != 0 ) {
$this->message[ $this->parent ]['children'] .= '|' . $pos;
}
// set my parent
$this->message[ $pos ]['parent'] = $this->parent;
// set self as current parent
$this->parent = $pos;
// set self as current value for this depth
$this->depth_array[ $this->depth ] = $pos;
// get element prefix
if ( strpos( $name, ':' ) ) {
// get ns prefix
$prefix = substr( $name, 0, strpos( $name, ':' ) );
// get unqualified name
$name = substr( strstr( $name, ':' ), 1 );
}
// set status
if ( $name == 'Envelope' && $this->status == '' ) {
$this->status = 'envelope';
} elseif ( $name == 'Header' && $this->status == 'envelope' ) {
$this->root_header = $pos;
$this->status = 'header';
} elseif ( $name == 'Body' && $this->status == 'envelope' ) {
$this->status = 'body';
$this->body_position = $pos;
// set method
} elseif ( $this->status == 'body' && $pos == ( $this->body_position + 1 ) ) {
$this->status = 'method';
$this->root_struct_name = $name;
$this->root_struct = $pos;
$this->message[ $pos ]['type'] = 'struct';
$this->debug( "found root struct $this->root_struct_name, pos $this->root_struct" );
}
// set my status
$this->message[ $pos ]['status'] = $this->status;
// set name
$this->message[ $pos ]['name'] = htmlspecialchars( $name );
// set attrs
$this->message[ $pos ]['attrs'] = $attrs;
// loop through atts, logging ns and type declarations
$attstr = '';
foreach ( $attrs as $key => $value ) {
$key_prefix = $this->getPrefix( $key );
$key_localpart = $this->getLocalPart( $key );
// if ns declarations, add to class level array of valid namespaces
if ( $key_prefix == 'xmlns' ) {
if ( preg_match( '/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value ) ) {
$this->XMLSchemaVersion = $value;
$this->namespaces['xsd'] = $this->XMLSchemaVersion;
$this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
}
$this->namespaces[ $key_localpart ] = $value;
// set method namespace
if ( $name == $this->root_struct_name ) {
$this->methodNamespace = $value;
}
// if it's a type declaration, set type
} elseif ( $key_localpart == 'type' ) {
if ( isset( $this->message[ $pos ]['type'] ) && $this->message[ $pos ]['type'] == 'array' ) {
// do nothing: already processed arrayType
} else {
$value_prefix = $this->getPrefix( $value );
$value_localpart = $this->getLocalPart( $value );
$this->message[ $pos ]['type'] = $value_localpart;
$this->message[ $pos ]['typePrefix'] = $value_prefix;
if ( isset( $this->namespaces[ $value_prefix ] ) ) {
$this->message[ $pos ]['type_namespace'] = $this->namespaces[ $value_prefix ];
} else if ( isset( $attrs[ 'xmlns:' . $value_prefix ] ) ) {
$this->message[ $pos ]['type_namespace'] = $attrs[ 'xmlns:' . $value_prefix ];
}
// should do something here with the namespace of specified type?
}
} elseif ( $key_localpart == 'arrayType' ) {
$this->message[ $pos ]['type'] = 'array';
/* do arrayType ereg here
[1] arrayTypeValue ::= atype asize
[2] atype ::= QName rank*
[3] rank ::= '[' (',')* ']'
[4] asize ::= '[' length~ ']'
[5] length ::= nextDimension* Digit+
[6] nextDimension ::= Digit+ ','
*/
$expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
if ( preg_match( $expr, $value, $regs ) ) {
$this->message[ $pos ]['typePrefix'] = $regs[1];
$this->message[ $pos ]['arrayTypePrefix'] = $regs[1];
if ( isset( $this->namespaces[ $regs[1] ] ) ) {
$this->message[ $pos ]['arrayTypeNamespace'] = $this->namespaces[ $regs[1] ];
} else if ( isset( $attrs[ 'xmlns:' . $regs[1] ] ) ) {
$this->message[ $pos ]['arrayTypeNamespace'] = $attrs[ 'xmlns:' . $regs[1] ];
}
$this->message[ $pos ]['arrayType'] = $regs[2];
$this->message[ $pos ]['arraySize'] = $regs[3];
$this->message[ $pos ]['arrayCols'] = $regs[4];
}
// specifies nil value (or not)
} elseif ( $key_localpart == 'nil' ) {
$this->message[ $pos ]['nil'] = ( $value == 'true' || $value == '1' );
// some other attribute
} elseif ( $key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root' ) {
$this->message[ $pos ]['xattrs'][ '!' . $key ] = $value;
}
if ( $key == 'xmlns' ) {
$this->default_namespace = $value;
}
// log id
if ( $key == 'id' ) {
$this->ids[ $value ] = $pos;
}
// root
if ( $key_localpart == 'root' && $value == 1 ) {
$this->status = 'method';
$this->root_struct_name = $name;
$this->root_struct = $pos;
$this->debug( "found root struct $this->root_struct_name, pos $pos" );
}
// for doclit
$attstr .= " $key=\"$value\"";
}
// get namespace - must be done after namespace atts are processed
if ( isset( $prefix ) ) {
$this->message[ $pos ]['namespace'] = $this->namespaces[ $prefix ];
$this->default_namespace = $this->namespaces[ $prefix ];
} else {
$this->message[ $pos ]['namespace'] = $this->default_namespace;
}
if ( $this->status == 'header' ) {
if ( $this->root_header != $pos ) {
$this->responseHeaders .= "<" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name$attstr>";
}
} elseif ( $this->root_struct_name != '' ) {
$this->document .= "<" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name$attstr>";
}
}
/**
* end-element handler
*
* @param resource $parser XML parser object
* @param string $name element name
*
* @access private
*/
function end_element( $parser, $name ) {
// position of current element is equal to the last value left in depth_array for my depth
$pos = $this->depth_array[ $this->depth -- ];
// get element prefix
if ( strpos( $name, ':' ) ) {
// get ns prefix
$prefix = substr( $name, 0, strpos( $name, ':' ) );
// get unqualified name
$name = substr( strstr( $name, ':' ), 1 );
}
// build to native type
if ( isset( $this->body_position ) && $pos > $this->body_position ) {
// deal w/ multirefs
if ( isset( $this->message[ $pos ]['attrs']['href'] ) ) {
// get id
$id = substr( $this->message[ $pos ]['attrs']['href'], 1 );
// add placeholder to href array
$this->multirefs[ $id ][ $pos ] = 'placeholder';
// add set a reference to it as the result value
$this->message[ $pos ]['result'] =& $this->multirefs[ $id ][ $pos ];
// build complexType values
} elseif ( $this->message[ $pos ]['children'] != '' ) {
// if result has already been generated (struct/array)
if ( ! isset( $this->message[ $pos ]['result'] ) ) {
$this->message[ $pos ]['result'] = $this->buildVal( $pos );
}
// build complexType values of attributes and possibly simpleContent
} elseif ( isset( $this->message[ $pos ]['xattrs'] ) ) {
if ( isset( $this->message[ $pos ]['nil'] ) && $this->message[ $pos ]['nil'] ) {
$this->message[ $pos ]['xattrs']['!'] = null;
} elseif ( isset( $this->message[ $pos ]['cdata'] ) && trim( $this->message[ $pos ]['cdata'] ) != '' ) {
if ( isset( $this->message[ $pos ]['type'] ) ) {
$this->message[ $pos ]['xattrs']['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
} else {
$parent = $this->message[ $pos ]['parent'];
if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
$this->message[ $pos ]['xattrs']['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
} else {
$this->message[ $pos ]['xattrs']['!'] = $this->message[ $pos ]['cdata'];
}
}
}
$this->message[ $pos ]['result'] = $this->message[ $pos ]['xattrs'];
// set value of simpleType (or nil complexType)
} else {
//$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
if ( isset( $this->message[ $pos ]['nil'] ) && $this->message[ $pos ]['nil'] ) {
$this->message[ $pos ]['xattrs']['!'] = null;
} elseif ( isset( $this->message[ $pos ]['type'] ) ) {
$this->message[ $pos ]['result'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
} else {
$parent = $this->message[ $pos ]['parent'];
if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
$this->message[ $pos ]['result'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
} else {
$this->message[ $pos ]['result'] = $this->message[ $pos ]['cdata'];
}
}
/* add value to parent's result, if parent is struct/array
$parent = $this->message[$pos]['parent'];
if($this->message[$parent]['type'] != 'map'){
if(strtolower($this->message[$parent]['type']) == 'array'){
$this->message[$parent]['result'][] = $this->message[$pos]['result'];
} else {
$this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
}
}
*/
}
}
// for doclit
if ( $this->status == 'header' ) {
if ( $this->root_header != $pos ) {
$this->responseHeaders .= "</" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name>";
}
} elseif ( $pos >= $this->root_struct ) {
$this->document .= "</" . ( isset( $prefix ) ? $prefix . ':' : '' ) . "$name>";
}
// switch status
if ( $pos == $this->root_struct ) {
$this->status = 'body';
$this->root_struct_namespace = $this->message[ $pos ]['namespace'];
} elseif ( $pos == $this->root_header ) {
$this->status = 'envelope';
} elseif ( $name == 'Body' && $this->status == 'body' ) {
$this->status = 'envelope';
} elseif ( $name == 'Header' && $this->status == 'header' ) { // will never happen
$this->status = 'envelope';
} elseif ( $name == 'Envelope' && $this->status == 'envelope' ) {
$this->status = '';
}
// set parent back to my parent
$this->parent = $this->message[ $pos ]['parent'];
}
/**
* element content handler
*
* @param resource $parser XML parser object
* @param string $data element content
*
* @access private
*/
function character_data( $parser, $data ) {
$pos = $this->depth_array[ $this->depth ];
if ( $this->xml_encoding == 'UTF-8' ) {
// TODO: add an option to disable this for folks who want
// raw UTF-8 that, e.g., might not map to iso-8859-1
// TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
if ( $this->decode_utf8 ) {
$data = utf8_decode( $data );
}
}
$this->message[ $pos ]['cdata'] .= $data;
// for doclit
if ( $this->status == 'header' ) {
$this->responseHeaders .= $data;
} else {
$this->document .= $data;
}
}
/**
* get the parsed message (SOAP Body)
*
* @return mixed
* @access public
* @deprecated use get_soapbody instead
*/
function get_response() {
return $this->soapresponse;
}
/**
* get the parsed SOAP Body (NULL if there was none)
*
* @return mixed
* @access public
*/
function get_soapbody() {
return $this->soapresponse;
}
/**
* get the parsed SOAP Header (NULL if there was none)
*
* @return mixed
* @access public
*/
function get_soapheader() {
return $this->soapheader;
}
/**
* get the unparsed SOAP Header
*
* @return string XML or empty if no Header
* @access public
*/
function getHeaders() {
return $this->responseHeaders;
}
/**
* decodes simple types into PHP variables
*
* @param string $value value to decode
* @param string $type XML type to decode
* @param string $typens XML type namespace to decode
*
* @return mixed PHP value
* @access private
*/
function decodeSimple( $value, $type, $typens ) {
// TODO: use the namespace!
if ( ( ! isset( $type ) ) || $type == 'string' || $type == 'long' || $type == 'unsignedLong' ) {
return (string) $value;
}
if ( $type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte' ) {
return (int) $value;
}
if ( $type == 'float' || $type == 'double' || $type == 'decimal' ) {
return (double) $value;
}
if ( $type == 'boolean' ) {
if ( strtolower( $value ) == 'false' || strtolower( $value ) == 'f' ) {
return false;
}
return (boolean) $value;
}
if ( $type == 'base64' || $type == 'base64Binary' ) {
$this->debug( 'Decode base64 value' );
return base64_decode( $value );
}
// obscure numeric types
if ( $type == 'nonPositiveInteger' || $type == 'negativeInteger'
|| $type == 'nonNegativeInteger' || $type == 'positiveInteger'
|| $type == 'unsignedInt'
|| $type == 'unsignedShort' || $type == 'unsignedByte' ) {
return (int) $value;
}
// bogus: parser treats array with no elements as a simple type
if ( $type == 'array' ) {
return array();
}
// everything else
return (string) $value;
}
/**
* builds response structures for compound values (arrays/structs)
* and scalars
*
* @param integer $pos position in node tree
*
* @return mixed PHP value
* @access private
*/
function buildVal( $pos ) {
if ( ! isset( $this->message[ $pos ]['type'] ) ) {
$this->message[ $pos ]['type'] = '';
}
$this->debug( 'in buildVal() for ' . $this->message[ $pos ]['name'] . "(pos $pos) of type " . $this->message[ $pos ]['type'] );
// if there are children...
if ( $this->message[ $pos ]['children'] != '' ) {
$this->debug( 'in buildVal, there are children' );
$children = explode( '|', $this->message[ $pos ]['children'] );
array_shift( $children ); // knock off empty
// md array
if ( isset( $this->message[ $pos ]['arrayCols'] ) && $this->message[ $pos ]['arrayCols'] != '' ) {
$r = 0; // rowcount
$c = 0; // colcount
foreach ( $children as $child_pos ) {
$this->debug( "in buildVal, got an MD array element: $r, $c" );
$params[ $r ][] = $this->message[ $child_pos ]['result'];
$c ++;
if ( $c == $this->message[ $pos ]['arrayCols'] ) {
$c = 0;
$r ++;
}
}
// array
} elseif ( $this->message[ $pos ]['type'] == 'array' || $this->message[ $pos ]['type'] == 'Array' ) {
$this->debug( 'in buildVal, adding array ' . $this->message[ $pos ]['name'] );
foreach ( $children as $child_pos ) {
$params[] = &$this->message[ $child_pos ]['result'];
}
// apache Map type: java hashtable
} elseif ( $this->message[ $pos ]['type'] == 'Map' && $this->message[ $pos ]['type_namespace'] == 'http://xml.apache.org/xml-soap' ) {
$this->debug( 'in buildVal, Java Map ' . $this->message[ $pos ]['name'] );
foreach ( $children as $child_pos ) {
$kv = explode( "|", $this->message[ $child_pos ]['children'] );
$params[ $this->message[ $kv[1] ]['result'] ] = &$this->message[ $kv[2] ]['result'];
}
// generic compound type
//} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
} else {
// Apache Vector type: treat as an array
$this->debug( 'in buildVal, adding Java Vector or generic compound type ' . $this->message[ $pos ]['name'] );
if ( $this->message[ $pos ]['type'] == 'Vector' && $this->message[ $pos ]['type_namespace'] == 'http://xml.apache.org/xml-soap' ) {
$notstruct = 1;
} else {
$notstruct = 0;
}
//
foreach ( $children as $child_pos ) {
if ( $notstruct ) {
$params[] = &$this->message[ $child_pos ]['result'];
} else {
if ( isset( $params[ $this->message[ $child_pos ]['name'] ] ) ) {
// de-serialize repeated element name into an array
if ( ( ! is_array( $params[ $this->message[ $child_pos ]['name'] ] ) ) || ( ! isset( $params[ $this->message[ $child_pos ]['name'] ][0] ) ) ) {
$params[ $this->message[ $child_pos ]['name'] ] = array( $params[ $this->message[ $child_pos ]['name'] ] );
}
$params[ $this->message[ $child_pos ]['name'] ][] = &$this->message[ $child_pos ]['result'];
} else {
$params[ $this->message[ $child_pos ]['name'] ] = &$this->message[ $child_pos ]['result'];
}
}
}
}
if ( isset( $this->message[ $pos ]['xattrs'] ) ) {
$this->debug( 'in buildVal, handling attributes' );
foreach ( $this->message[ $pos ]['xattrs'] as $n => $v ) {
$params[ $n ] = $v;
}
}
// handle simpleContent
if ( isset( $this->message[ $pos ]['cdata'] ) && trim( $this->message[ $pos ]['cdata'] ) != '' ) {
$this->debug( 'in buildVal, handling simpleContent' );
if ( isset( $this->message[ $pos ]['type'] ) ) {
$params['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
} else {
$parent = $this->message[ $pos ]['parent'];
if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
$params['!'] = $this->decodeSimple( $this->message[ $pos ]['cdata'], $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
} else {
$params['!'] = $this->message[ $pos ]['cdata'];
}
}
}
$ret = is_array( $params ) ? $params : array();
$this->debug( 'in buildVal, return:' );
$this->appendDebug( $this->varDump( $ret ) );
return $ret;
} else {
$this->debug( 'in buildVal, no children, building scalar' );
$cdata = isset( $this->message[ $pos ]['cdata'] ) ? $this->message[ $pos ]['cdata'] : '';
if ( isset( $this->message[ $pos ]['type'] ) ) {
$ret = $this->decodeSimple( $cdata, $this->message[ $pos ]['type'], isset( $this->message[ $pos ]['type_namespace'] ) ? $this->message[ $pos ]['type_namespace'] : '' );
$this->debug( "in buildVal, return: $ret" );
return $ret;
}
$parent = $this->message[ $pos ]['parent'];
if ( isset( $this->message[ $parent ]['type'] ) && ( $this->message[ $parent ]['type'] == 'array' ) && isset( $this->message[ $parent ]['arrayType'] ) ) {
$ret = $this->decodeSimple( $cdata, $this->message[ $parent ]['arrayType'], isset( $this->message[ $parent ]['arrayTypeNamespace'] ) ? $this->message[ $parent ]['arrayTypeNamespace'] : '' );
$this->debug( "in buildVal, return: $ret" );
return $ret;
}
$ret = $this->message[ $pos ]['cdata'];
$this->debug( "in buildVal, return: $ret" );
return $ret;
}
}
}
/**
* Backward compatibility
*/
class soap_parser extends nusoap_parser {
}
?><?php
/**
*
* [nu]soapclient higher level class for easy usage.
*
* usage:
*
* // instantiate client with server info
* $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
*
* // call method, get results
* echo $soapclient->call( string methodname [ ,array parameters] );
*
* // bye bye client
* unset($soapclient);
*
* @author Dietrich Ayala <dietrich@ganx4.com>
* @author Scott Nichol <snichol@users.sourceforge.net>
* @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
* @access public
*/
class nusoap_client extends nusoap_base {
var $username = ''; // Username for HTTP authentication
var $password = ''; // Password for HTTP authentication
var $authtype = ''; // Type of HTTP authentication
var $certRequest = array(); // Certificate for HTTP SSL authentication
var $requestHeaders = false; // SOAP headers in request (text)
var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
var $responseHeader = null; // SOAP Header from response (parsed)
var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
var $endpoint;
var $forceEndpoint = ''; // overrides WSDL endpoint
var $proxyhost = '';
var $proxyport = '';
var $proxyusername = '';
var $proxypassword = '';
var $portName = ''; // port name to use in WSDL
var $xml_encoding = ''; // character set encoding of incoming (response) messages
var $http_encoding = false;
var $timeout = 0; // HTTP connection timeout
var $response_timeout = 30; // HTTP response timeout
var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
var $persistentConnection = false;
var $defaultRpcParams = false; // This is no longer used
var $request = ''; // HTTP request
var $response = ''; // HTTP response
var $responseData = ''; // SOAP payload of response
var $cookies = array(); // Cookies from response or for request
var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
var $operations = array(); // WSDL operations, empty for WSDL initialization error
var $curl_options = array(); // User-specified cURL options
var $bindingType = ''; // WSDL operation binding type
var $use_curl = false; // whether to always try to use cURL
/*
* fault related variables
*/
/**
* @var fault
* @access public
*/
var $fault;
/**
* @var faultcode
* @access public
*/
var $faultcode;
/**
* @var faultstring
* @access public
*/
var $faultstring;
/**
* @var faultdetail
* @access public
*/
var $faultdetail;
/**
* constructor
*
* @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
* @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL
* @param string $proxyhost optional
* @param string $proxyport optional
* @param string $proxyusername optional
* @param string $proxypassword optional
* @param integer $timeout set the connection timeout
* @param integer $response_timeout set the response timeout
* @param string $portName optional portName in WSDL document
*
* @access public
*/
function nusoap_client( $endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = '' ) {
parent::nusoap_base();
$this->endpoint = $endpoint;
$this->proxyhost = $proxyhost;
$this->proxyport = $proxyport;
$this->proxyusername = $proxyusername;
$this->proxypassword = $proxypassword;
$this->timeout = $timeout;
$this->response_timeout = $response_timeout;
$this->portName = $portName;
$this->debug( "ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout" );
$this->appendDebug( 'endpoint=' . $this->varDump( $endpoint ) );
// make values
if ( $wsdl ) {
if ( is_object( $endpoint ) && ( get_class( $endpoint ) == 'wsdl' ) ) {
$this->wsdl = $endpoint;
$this->endpoint = $this->wsdl->wsdl;
$this->wsdlFile = $this->endpoint;
$this->debug( 'existing wsdl instance created from ' . $this->endpoint );
$this->checkWSDL();
} else {
$this->wsdlFile = $this->endpoint;
$this->wsdl = null;
$this->debug( 'will use lazy evaluation of wsdl from ' . $this->endpoint );
}
$this->endpointType = 'wsdl';
} else {
$this->debug( "instantiate SOAP with endpoint at $endpoint" );
$this->endpointType = 'soap';
}
}
/**
* calls method, returns PHP native type
*
* @param string $operation SOAP server URL or path
* @param mixed $params An array, associative or simple, of the parameters
* for the method call, or a string that is the XML
* for the call. For rpc style, this call will
* wrap the XML in a tag named after the method, as
* well as the SOAP Envelope and Body. For document
* style, this will only wrap with the Envelope and Body.
* IMPORTANT: when using an array with document style,
* in which case there
* is really one parameter, the root of the fragment
* used in the call, which encloses what programmers
* normally think of parameters. A parameter array
* *must* include the wrapper.
* @param string $namespace optional method namespace (WSDL can override)
* @param string $soapAction optional SOAPAction value (WSDL can override)
* @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
* @param boolean $rpcParams optional (no longer used)
* @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
* @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
*
* @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
* @access public
*/
function call( $operation, $params = array(), $namespace = 'http://tempuri.org', $soapAction = '', $headers = false, $rpcParams = null, $style = 'rpc', $use = 'encoded' ) {
$this->operation = $operation;
$this->fault = false;
$this->setError( '' );
$this->request = '';
$this->response = '';
$this->responseData = '';
$this->faultstring = '';
$this->faultcode = '';
$this->opData = array();
$this->debug( "call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType" );
$this->appendDebug( 'params=' . $this->varDump( $params ) );
$this->appendDebug( 'headers=' . $this->varDump( $headers ) );
if ( $headers ) {
$this->requestHeaders = $headers;
}
if ( $this->endpointType == 'wsdl' && is_null( $this->wsdl ) ) {
$this->loadWSDL();
if ( $this->getError() ) {
return false;
}
}
// serialize parameters
if ( $this->endpointType == 'wsdl' && $opData = $this->getOperationData( $operation ) ) {
// use WSDL for operation
$this->opData = $opData;
$this->debug( "found operation" );
$this->appendDebug( 'opData=' . $this->varDump( $opData ) );
if ( isset( $opData['soapAction'] ) ) {
$soapAction = $opData['soapAction'];
}
if ( ! $this->forceEndpoint ) {
$this->endpoint = $opData['endpoint'];
} else {
$this->endpoint = $this->forceEndpoint;
}
$namespace = isset( $opData['input']['namespace'] ) ? $opData['input']['namespace'] : $namespace;
$style = $opData['style'];
$use = $opData['input']['use'];
// add ns to ns array
if ( $namespace != '' && ! isset( $this->wsdl->namespaces[ $namespace ] ) ) {
$nsPrefix = 'ns' . rand( 1000, 9999 );
$this->wsdl->namespaces[ $nsPrefix ] = $namespace;
}
$nsPrefix = $this->wsdl->getPrefixFromNamespace( $namespace );
// serialize payload
if ( is_string( $params ) ) {
$this->debug( "serializing param string for WSDL operation $operation" );
$payload = $params;
} elseif ( is_array( $params ) ) {
$this->debug( "serializing param array for WSDL operation $operation" );
$payload = $this->wsdl->serializeRPCParameters( $operation, 'input', $params, $this->bindingType );
} else {
$this->debug( 'params must be array or string' );
$this->setError( 'params must be array or string' );
return false;
}
$usedNamespaces = $this->wsdl->usedNamespaces;
if ( isset( $opData['input']['encodingStyle'] ) ) {
$encodingStyle = $opData['input']['encodingStyle'];
} else {
$encodingStyle = '';
}
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
if ( $errstr = $this->wsdl->getError() ) {
$this->debug( 'got wsdl error: ' . $errstr );
$this->setError( 'wsdl error: ' . $errstr );
return false;
}
} elseif ( $this->endpointType == 'wsdl' ) {
// operation not in WSDL
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
$this->setError( 'operation ' . $operation . ' not present in WSDL.' );
$this->debug( "operation '$operation' not present in WSDL." );
return false;
} else {
// no WSDL
//$this->namespaces['ns1'] = $namespace;
$nsPrefix = 'ns' . rand( 1000, 9999 );
// serialize
$payload = '';
if ( is_string( $params ) ) {
$this->debug( "serializing param string for operation $operation" );
$payload = $params;
} elseif ( is_array( $params ) ) {
$this->debug( "serializing param array for operation $operation" );
foreach ( $params as $k => $v ) {
$payload .= $this->serialize_val( $v, $k, false, false, false, false, $use );
}
} else {
$this->debug( 'params must be array or string' );
$this->setError( 'params must be array or string' );
return false;
}
$usedNamespaces = array();
if ( $use == 'encoded' ) {
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
} else {
$encodingStyle = '';
}
}
// wrap RPC calls with method element
if ( $style == 'rpc' ) {
if ( $use == 'literal' ) {
$this->debug( "wrapping RPC request with literal method element" );
if ( $namespace ) {
// http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
$payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
$payload .
"</$nsPrefix:$operation>";
} else {
$payload = "<$operation>" . $payload . "</$operation>";
}
} else {
$this->debug( "wrapping RPC request with encoded method element" );
if ( $namespace ) {
$payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
$payload .
"</$nsPrefix:$operation>";
} else {
$payload = "<$operation>" .
$payload .
"</$operation>";
}
}
}
// serialize envelope
$soapmsg = $this->serializeEnvelope( $payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle );
$this->debug( "endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle" );
$this->debug( 'SOAP message length=' . strlen( $soapmsg ) . ' contents (max 1000 bytes)=' . substr( $soapmsg, 0, 1000 ) );
// send
$return = $this->send( $this->getHTTPBody( $soapmsg ), $soapAction, $this->timeout, $this->response_timeout );
if ( $errstr = $this->getError() ) {
$this->debug( 'Error: ' . $errstr );
return false;
} else {
$this->return = $return;
$this->debug( 'sent message successfully and got a(n) ' . gettype( $return ) );
$this->appendDebug( 'return=' . $this->varDump( $return ) );
// fault?
if ( is_array( $return ) && isset( $return['faultcode'] ) ) {
$this->debug( 'got fault' );
$this->setError( $return['faultcode'] . ': ' . $return['faultstring'] );
$this->fault = true;
foreach ( $return as $k => $v ) {
$this->$k = $v;
$this->debug( "$k = $v<br>" );
}
return $return;
} elseif ( $style == 'document' ) {
// NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
// we are only going to return the first part here...sorry about that
return $return;
} else {
// array of return values
if ( is_array( $return ) ) {
// multiple 'out' parameters, which we return wrapped up
// in the array
if ( sizeof( $return ) > 1 ) {
return $return;
}
// single 'out' parameter (normally the return value)
$return = array_shift( $return );
$this->debug( 'return shifted value: ' );
$this->appendDebug( $this->varDump( $return ) );
return $return;
// nothing returned (ie, echoVoid)
} else {
return "";
}
}
}
}
/**
* check WSDL passed as an instance or pulled from an endpoint
*
* @access private
*/
function checkWSDL() {
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
$this->debug( 'checkWSDL' );
// catch errors
if ( $errstr = $this->wsdl->getError() ) {
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
$this->debug( 'got wsdl error: ' . $errstr );
$this->setError( 'wsdl error: ' . $errstr );
} elseif ( $this->operations = $this->wsdl->getOperations( $this->portName, 'soap' ) ) {
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
$this->bindingType = 'soap';
$this->debug( 'got ' . count( $this->operations ) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType );
} elseif ( $this->operations = $this->wsdl->getOperations( $this->portName, 'soap12' ) ) {
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
$this->bindingType = 'soap12';
$this->debug( 'got ' . count( $this->operations ) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType );
$this->debug( '**************** WARNING: SOAP 1.2 BINDING *****************' );
} else {
$this->appendDebug( $this->wsdl->getDebug() );
$this->wsdl->clearDebug();
$this->debug( 'getOperations returned false' );
$this->setError( 'no operations defined in the WSDL document!' );
}
}
/**
* instantiate wsdl object and parse wsdl file
*
* @access public
*/
function loadWSDL() {
$this->debug( 'instantiating wsdl class with doc: ' . $this->wsdlFile );
$this->wsdl = new wsdl( '', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl );
$this->wsdl->setCredentials( $this->username, $this->password, $this->authtype, $this->certRequest );
$this->wsdl->fetchWSDL( $this->wsdlFile );
$this->checkWSDL();
}
/**
* get available data pertaining to an operation
*
* @param string $operation operation name
*
* @return array array of data pertaining to the operation
* @access public
*/
function getOperationData( $operation ) {
if ( $this->endpointType == 'wsdl' && is_null( $this->wsdl ) ) {
$this->loadWSDL();
if ( $this->getError() ) {
return false;
}
}
if ( isset( $this->operations[ $operation ] ) ) {
return $this->operations[ $operation ];
}
$this->debug( "No data for operation: $operation" );
}
/**
* send the SOAP message
*
* Note: if the operation has multiple return values
* the return value of this method will be an array
* of those values.
*
* @param string $msg a SOAPx4 soapmsg object
* @param string $soapaction SOAPAction value
* @param integer $timeout set connection timeout in seconds
* @param integer $response_timeout set response timeout in seconds
*
* @return mixed native PHP types.
* @access private
*/
function send( $msg, $soapaction = '', $timeout = 0, $response_timeout = 30 ) {
$this->checkCookies();
// detect transport
switch ( true ) {
// http(s)
case preg_match( '/^http/', $this->endpoint ):
$this->debug( 'transporting via HTTP' );
if ( $this->persistentConnection == true && is_object( $this->persistentConnection ) ) {
$http =& $this->persistentConnection;
} else {
$http = new soap_transport_http( $this->endpoint, $this->curl_options, $this->use_curl );
if ( $this->persistentConnection ) {
$http->usePersistentConnection();
}
}
$http->setContentType( $this->getHTTPContentType(), $this->getHTTPContentTypeCharset() );
$http->setSOAPAction( $soapaction );
if ( $this->proxyhost && $this->proxyport ) {
$http->setProxy( $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword );
}
if ( $this->authtype != '' ) {
$http->setCredentials( $this->username, $this->password, $this->authtype, array(), $this->certRequest );
}
if ( $this->http_encoding != '' ) {
$http->setEncoding( $this->http_encoding );
}
$this->debug( 'sending message, length=' . strlen( $msg ) );
if ( preg_match( '/^http:/', $this->endpoint ) ) {
//if(strpos($this->endpoint,'http:')){
$this->responseData = $http->send( $msg, $timeout, $response_timeout, $this->cookies );
} elseif ( preg_match( '/^https/', $this->endpoint ) ) {
//} elseif(strpos($this->endpoint,'https:')){
//if(phpversion() == '4.3.0-dev'){
//$response = $http->send($msg,$timeout,$response_timeout);
//$this->request = $http->outgoing_payload;
//$this->response = $http->incoming_payload;
//} else
$this->responseData = $http->sendHTTPS( $msg, $timeout, $response_timeout, $this->cookies );
} else {
$this->setError( 'no http/s in endpoint url' );
}
$this->request = $http->outgoing_payload;
$this->response = $http->incoming_payload;
$this->appendDebug( $http->getDebug() );
$this->UpdateCookies( $http->incoming_cookies );
// save transport object if using persistent connections
if ( $this->persistentConnection ) {
$http->clearDebug();
if ( ! is_object( $this->persistentConnection ) ) {
$this->persistentConnection = $http;
}
}
if ( $err = $http->getError() ) {
$this->setError( 'HTTP Error: ' . $err );
return false;
} elseif ( $this->getError() ) {
return false;
} else {
$this->debug( 'got response, length=' . strlen( $this->responseData ) . ' type=' . $http->incoming_headers['content-type'] );
return $this->parseResponse( $http->incoming_headers, $this->responseData );
}
break;
default:
$this->setError( 'no transport found, or selected transport is not yet supported!' );
return false;
break;
}
}
/**
* processes SOAP message returned from server
*
* @param array $headers The HTTP headers
* @param string $data unprocessed response data from server
*
* @return mixed value of the message, decoded into a PHP type
* @access private
*/
function parseResponse( $headers, $data ) {
$this->debug( 'Entering parseResponse() for data of length ' . strlen( $data ) . ' headers:' );
$this->appendDebug( $this->varDump( $headers ) );
if ( ! isset( $headers['content-type'] ) ) {
$this->setError( 'Response not of type text/xml (no content-type header)' );
return false;
}
if ( ! strstr( $headers['content-type'], 'text/xml' ) ) {
$this->setError( 'Response not of type text/xml: ' . $headers['content-type'] );
return false;
}
if ( strpos( $headers['content-type'], '=' ) ) {
$enc = str_replace( '"', '', substr( strstr( $headers["content-type"], '=' ), 1 ) );
$this->debug( 'Got response encoding: ' . $enc );
if ( preg_match( '/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc ) ) {
$this->xml_encoding = strtoupper( $enc );
} else {
$this->xml_encoding = 'US-ASCII';
}
} else {
// should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
$this->xml_encoding = 'ISO-8859-1';
}
$this->debug( 'Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser' );
$parser = new nusoap_parser( $data, $this->xml_encoding, $this->operation, $this->decode_utf8 );
// add parser debug data to our debug
$this->appendDebug( $parser->getDebug() );
// if parse errors
if ( $errstr = $parser->getError() ) {
$this->setError( $errstr );
// destroy the parser object
unset( $parser );
return false;
} else {
// get SOAP headers
$this->responseHeaders = $parser->getHeaders();
// get SOAP headers
$this->responseHeader = $parser->get_soapheader();
// get decoded message
$return = $parser->get_soapbody();
// add document for doclit support
$this->document = $parser->document;
// destroy the parser object
unset( $parser );
// return decode message
return $return;
}
}
/**
* sets user-specified cURL options
*
* @param mixed $option The cURL option (always integer?)
* @param mixed $value The cURL option value
*
* @access public
*/
function setCurlOption( $option, $value ) {
$this->debug( "setCurlOption option=$option, value=" );
$this->appendDebug( $this->varDump( $value ) );
$this->curl_options[ $option ] = $value;
}
/**
* sets the SOAP endpoint, which can override WSDL
*
* @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
*
* @access public
*/
function setEndpoint( $endpoint ) {
$this->debug( "setEndpoint(\"$endpoint\")" );
$this->forceEndpoint = $endpoint;
}
/**
* set the SOAP headers
*
* @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
*
* @access public
*/
function setHeaders( $headers ) {
$this->debug( "setHeaders headers=" );
$this->appendDebug( $this->varDump( $headers ) );
$this->requestHeaders = $headers;
}
/**
* get the SOAP response headers (namespace resolution incomplete)
*
* @return string
* @access public
*/
function getHeaders() {
return $this->responseHeaders;
}
/**
* get the SOAP response Header (parsed)
*
* @return mixed
* @access public
*/
function getHeader() {
return $this->responseHeader;
}
/**
* set proxy info here
*
* @param string $proxyhost
* @param string $proxyport
* @param string $proxyusername
* @param string $proxypassword
*
* @access public
*/
function setHTTPProxy( $proxyhost, $proxyport, $proxyusername = '', $proxypassword = '' ) {
$this->proxyhost = $proxyhost;
$this->proxyport = $proxyport;
$this->proxyusername = $proxyusername;
$this->proxypassword = $proxypassword;
}
/**
* if authenticating, set user credentials here
*
* @param string $username
* @param string $password
* @param string $authtype (basic|digest|certificate|ntlm)
* @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
*
* @access public
*/
function setCredentials( $username, $password, $authtype = 'basic', $certRequest = array() ) {
$this->debug( "setCredentials username=$username authtype=$authtype certRequest=" );
$this->appendDebug( $this->varDump( $certRequest ) );
$this->username = $username;
$this->password = $password;
$this->authtype = $authtype;
$this->certRequest = $certRequest;
}
/**
* use HTTP encoding
*
* @param string $enc HTTP encoding
*
* @access public
*/
function setHTTPEncoding( $enc = 'gzip, deflate' ) {
$this->debug( "setHTTPEncoding(\"$enc\")" );
$this->http_encoding = $enc;
}
/**
* Set whether to try to use cURL connections if possible
*
* @param boolean $use Whether to try to use cURL
*
* @access public
*/
function setUseCURL( $use ) {
$this->debug( "setUseCURL($use)" );
$this->use_curl = $use;
}
/**
* use HTTP persistent connections if possible
*
* @access public
*/
function useHTTPPersistentConnection() {
$this->debug( "useHTTPPersistentConnection" );
$this->persistentConnection = true;
}
/**
* gets the default RPC parameter setting.
* If true, default is that call params are like RPC even for document style.
* Each call() can override this value.
*
* This is no longer used.
*
* @return boolean
* @access public
* @deprecated
*/
function getDefaultRpcParams() {
return $this->defaultRpcParams;
}
/**
* sets the default RPC parameter setting.
* If true, default is that call params are like RPC even for document style
* Each call() can override this value.
*
* This is no longer used.
*
* @param boolean $rpcParams
*
* @access public
* @deprecated
*/
function setDefaultRpcParams( $rpcParams ) {
$this->defaultRpcParams = $rpcParams;
}
/**
* dynamically creates an instance of a proxy class,
* allowing user to directly call methods from wsdl
*
* @return object soap_proxy object
* @access public
*/
function getProxy() {
$r = rand();
$evalStr = $this->_getProxyClassCode( $r );
//$this->debug("proxy class: $evalStr");
if ( $this->getError() ) {
$this->debug( "Error from _getProxyClassCode, so return NULL" );
return null;
}
// eval the class
eval( $evalStr );
// instantiate proxy object
eval( "\$proxy = new nusoap_proxy_$r('');" );
// transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
$proxy->endpointType = 'wsdl';
$proxy->wsdlFile = $this->wsdlFile;
$proxy->wsdl = $this->wsdl;
$proxy->operations = $this->operations;
$proxy->defaultRpcParams = $this->defaultRpcParams;
// transfer other state
$proxy->soap_defencoding = $this->soap_defencoding;
$proxy->username = $this->username;
$proxy->password = $this->password;
$proxy->authtype = $this->authtype;
$proxy->certRequest = $this->certRequest;
$proxy->requestHeaders = $this->requestHeaders;
$proxy->endpoint = $this->endpoint;
$proxy->forceEndpoint = $this->forceEndpoint;
$proxy->proxyhost = $this->proxyhost;
$proxy->proxyport = $this->proxyport;
$proxy->proxyusername = $this->proxyusername;
$proxy->proxypassword = $this->proxypassword;
$proxy->http_encoding = $this->http_encoding;
$proxy->timeout = $this->timeout;
$proxy->response_timeout = $this->response_timeout;
$proxy->persistentConnection = &$this->persistentConnection;
$proxy->decode_utf8 = $this->decode_utf8;
$proxy->curl_options = $this->curl_options;
$proxy->bindingType = $this->bindingType;
$proxy->use_curl = $this->use_curl;
return $proxy;
}
/**
* dynamically creates proxy class code
*
* @return string PHP/NuSOAP code for the proxy class
* @access private
*/
function _getProxyClassCode( $r ) {
$this->debug( "in getProxy endpointType=$this->endpointType" );
$this->appendDebug( "wsdl=" . $this->varDump( $this->wsdl ) );
if ( $this->endpointType != 'wsdl' ) {
$evalStr = 'A proxy can only be created for a WSDL client';
$this->setError( $evalStr );
$evalStr = "echo \"$evalStr\";";
return $evalStr;
}
if ( $this->endpointType == 'wsdl' && is_null( $this->wsdl ) ) {
$this->loadWSDL();
if ( $this->getError() ) {
return "echo \"" . $this->getError() . "\";";
}
}
$evalStr = '';
foreach ( $this->operations as $operation => $opData ) {
if ( $operation != '' ) {
// create param string and param comment string
if ( sizeof( $opData['input']['parts'] ) > 0 ) {
$paramStr = '';
$paramArrayStr = '';
$paramCommentStr = '';
foreach ( $opData['input']['parts'] as $name => $type ) {
$paramStr .= "\$$name, ";
$paramArrayStr .= "'$name' => \$$name, ";
$paramCommentStr .= "$type \$$name, ";
}
$paramStr = substr( $paramStr, 0, strlen( $paramStr ) - 2 );
$paramArrayStr = substr( $paramArrayStr, 0, strlen( $paramArrayStr ) - 2 );
$paramCommentStr = substr( $paramCommentStr, 0, strlen( $paramCommentStr ) - 2 );
} else {
$paramStr = '';
$paramArrayStr = '';
$paramCommentStr = 'void';
}
$opData['namespace'] = ! isset( $opData['namespace'] ) ? 'http://testuri.com' : $opData['namespace'];
$evalStr .= "// $paramCommentStr
function " . str_replace( '.', '__', $operation ) . "($paramStr) {
\$params = array($paramArrayStr);
return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . ( isset( $opData['soapAction'] ) ? $opData['soapAction'] : '' ) . "');
}
";
unset( $paramStr );
unset( $paramCommentStr );
}
}
$evalStr = 'class nusoap_proxy_' . $r . ' extends nusoap_client {
' . $evalStr . '
}';
return $evalStr;
}
/**
* dynamically creates proxy class code
*
* @return string PHP/NuSOAP code for the proxy class
* @access public
*/
function getProxyClassCode() {
$r = rand();
return $this->_getProxyClassCode( $r );
}
/**
* gets the HTTP body for the current request.
*
* @param string $soapmsg The SOAP payload
*
* @return string The HTTP body, which includes the SOAP payload
* @access private
*/
function getHTTPBody( $soapmsg ) {
return $soapmsg;
}
/**
* gets the HTTP content type for the current request.
*
* Note: getHTTPBody must be called before this.
*
* @return string the HTTP content type for the current request.
* @access private
*/
function getHTTPContentType() {
return 'text/xml';
}
/**
* gets the HTTP content type charset for the current request.
* returns false for non-text content types.
*
* Note: getHTTPBody must be called before this.
*
* @return string the HTTP content type charset for the current request.
* @access private
*/
function getHTTPContentTypeCharset() {
return $this->soap_defencoding;
}
/*
* whether or not parser should decode utf8 element content
*
* @return always returns true
* @access public
*/
function decodeUTF8( $bool ) {
$this->decode_utf8 = $bool;
return true;
}
/**
* adds a new Cookie into $this->cookies array
*
* @param string $name Cookie Name
* @param string $value Cookie Value
*
* @return boolean if cookie-set was successful returns true, else false
* @access public
*/
function setCookie( $name, $value ) {
if ( strlen( $name ) == 0 ) {
return false;
}
$this->cookies[] = array( 'name' => $name, 'value' => $value );
return true;
}
/**
* gets all Cookies
*
* @return array with all internal cookies
* @access public
*/
function getCookies() {
return $this->cookies;
}
/**
* checks all Cookies and delete those which are expired
*
* @return boolean always return true
* @access private
*/
function checkCookies() {
if ( sizeof( $this->cookies ) == 0 ) {
return true;
}
$this->debug( 'checkCookie: check ' . sizeof( $this->cookies ) . ' cookies' );
$curr_cookies = $this->cookies;
$this->cookies = array();
foreach ( $curr_cookies as $cookie ) {
if ( ! is_array( $cookie ) ) {
$this->debug( 'Remove cookie that is not an array' );
continue;
}
if ( ( isset( $cookie['expires'] ) ) && ( ! empty( $cookie['expires'] ) ) ) {
if ( strtotime( $cookie['expires'] ) > time() ) {
$this->cookies[] = $cookie;
} else {
$this->debug( 'Remove expired cookie ' . $cookie['name'] );
}
} else {
$this->cookies[] = $cookie;
}
}
$this->debug( 'checkCookie: ' . sizeof( $this->cookies ) . ' cookies left in array' );
return true;
}
/**
* updates the current cookies with a new set
*
* @param array $cookies new cookies with which to update current ones
*
* @return boolean always return true
* @access private
*/
function UpdateCookies( $cookies ) {
if ( sizeof( $this->cookies ) == 0 ) {
// no existing cookies: take whatever is new
if ( sizeof( $cookies ) > 0 ) {
$this->debug( 'Setting new cookie(s)' );
$this->cookies = $cookies;
}
return true;
}
if ( sizeof( $cookies ) == 0 ) {
// no new cookies: keep what we've got
return true;
}
// merge
foreach ( $cookies as $newCookie ) {
if ( ! is_array( $newCookie ) ) {
continue;
}
if ( ( ! isset( $newCookie['name'] ) ) || ( ! isset( $newCookie['value'] ) ) ) {
continue;
}
$newName = $newCookie['name'];
$found = false;
for ( $i = 0; $i < count( $this->cookies ); $i ++ ) {
$cookie = $this->cookies[ $i ];
if ( ! is_array( $cookie ) ) {
continue;
}
if ( ! isset( $cookie['name'] ) ) {
continue;
}
if ( $newName != $cookie['name'] ) {
continue;
}
$newDomain = isset( $newCookie['domain'] ) ? $newCookie['domain'] : 'NODOMAIN';
$domain = isset( $cookie['domain'] ) ? $cookie['domain'] : 'NODOMAIN';
if ( $newDomain != $domain ) {
continue;
}
$newPath = isset( $newCookie['path'] ) ? $newCookie['path'] : 'NOPATH';
$path = isset( $cookie['path'] ) ? $cookie['path'] : 'NOPATH';
if ( $newPath != $path ) {
continue;
}
$this->cookies[ $i ] = $newCookie;
$found = true;
$this->debug( 'Update cookie ' . $newName . '=' . $newCookie['value'] );
break;
}
if ( ! $found ) {
$this->debug( 'Add cookie ' . $newName . '=' . $newCookie['value'] );
$this->cookies[] = $newCookie;
}
}
return true;
}
}
if ( ! extension_loaded( 'soap' ) ) {
/**
* For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
*/
class soapclient extends nusoap_client {
}
}
?>