diff --git a/lib/nusoap/nusoap.php b/lib/nusoap/nusoap.php
index 7222e33beac63..78deafef54ad7 100644
--- a/lib/nusoap/nusoap.php
+++ b/lib/nusoap/nusoap.php
@@ -35,7 +35,7 @@
/* load classes
// necessary classes
-require_once('class.soapclient.php');
+require_once('class.soap_client.php');
require_once('class.soap_val.php');
require_once('class.soap_parser.php');
require_once('class.soap_fault.php');
@@ -63,54 +63,102 @@
* @access public
*/
class nusoap_base {
-
+ /**
+ * Identification for HTTP headers.
+ *
+ * @var string
+ * @access private
+ */
var $title = 'NuSOAP';
- var $version = '0.6.9';
+ /**
+ * Version for HTTP headers.
+ *
+ * @var string
+ * @access private
+ */
+ var $version = '0.7.2';
+ /**
+ * CVS revision for HTTP headers.
+ *
+ * @var string
+ * @access private
+ */
var $revision = '$Revision$';
+ /**
+ * 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)
+ /**
+ * 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
+ /**
+ * the debug level for this instance
+ *
+ * @var integer
+ * @access private
+ */
var $debugLevel;
/**
- * set schema version
+ * set schema version
*
- * @var XMLSchemaVersion
+ * @var string
* @access public
*/
var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
/**
- * set charset encoding for outgoing messages
+ * charset encoding for outgoing messages
*
- * @var soap_defencoding
+ * @var string
* @access public
*/
- //var $soap_defencoding = 'UTF-8';
var $soap_defencoding = 'ISO-8859-1';
+ //var $soap_defencoding = 'UTF-8';
/**
- * load namespace uris into an array of uri => prefix
+ * namespaces in an array of prefix => uri
*
- * @var namespaces
+ * 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/',
- 'si' => 'http://soapinterop.org/xsd');
+ '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();
/**
- * load types into typemap 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 xmlschema class to verify type => namespace mappings.
- * @var typemap
+ * @var array
* @access public
*/
var $typemap = array(
@@ -139,10 +187,12 @@ class nusoap_base {
);
/**
- * entities to convert
+ * XML entities to convert
*
- * @var xmlEntities
+ * @var array
* @access public
+ * @deprecated
+ * @see expandEntities
*/
var $xmlEntities = array('quot' => '"','amp' => '&',
'lt' => '<','gt' => '>','apos' => "'");
@@ -159,7 +209,7 @@ function nusoap_base() {
/**
* gets the global debug level, which applies to future instances
*
- * @return int Debug level 0-9, where 0 turns off
+ * @return integer Debug level 0-9, where 0 turns off
* @access public
*/
function getGlobalDebugLevel() {
@@ -212,7 +262,7 @@ function debug($string){
* adds debug data to the instance debug string without formatting
*
* @param string $string debug data
- * @access private
+ * @access public
*/
function appendDebug($string){
if ($this->debugLevel > 0) {
@@ -304,7 +354,7 @@ function setError($str){
/**
* detect if array is a simple array or a struct (associative array)
*
- * @param $val The PHP array
+ * @param mixed $val The PHP array
* @return string (arraySimple|arrayStruct)
* @access private
*/
@@ -322,16 +372,30 @@ function isArraySimpleOrStruct($val) {
* serializes PHP values in accordance w/ section 5. Type information is
* not serialized if $use == 'literal'.
*
- * @return string
+ * @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)
+ * @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'){
+ $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
+ $this->appendDebug('value=' . $this->varDump($val));
+ $this->appendDebug('attributes=' . $this->varDump($attributes));
+
if(is_object($val) && get_class($val) == 'soapval'){
return $val->serialize($use);
}
- $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
- // if no name, use item
- $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
+ // 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){
@@ -352,16 +416,21 @@ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=fals
$atts = '';
if($attributes){
foreach($attributes as $k => $v){
- $atts .= ' $k="'.$this->expandEntities($v).'"';
+ $atts .= " $k=\"".$this->expandEntities($v).'"';
}
}
// serialize null value
if (is_null($val)) {
if ($use == 'literal') {
- // TODO: depends on nillable
+ // TODO: depends on minOccurs
return "<$name$xmlns $atts/>";
} else {
- return "<$name$xmlns $atts xsi:nil=\"true\"/>";
+ if (isset($type) && isset($type_prefix)) {
+ $type_str = " xsi:type=\"$type_prefix:$type\"";
+ } else {
+ $type_str = '';
+ }
+ return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
}
}
// serialize if an xsd built-in primitive type
@@ -419,7 +488,12 @@ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=fals
}
break;
case is_object($val):
- $name = get_class($val);
+ 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);
}
@@ -442,6 +516,7 @@ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=fals
$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;
}
@@ -483,9 +558,10 @@ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=fals
} else if (isset($type) && isset($type_prefix)) {
$type_str = " xsi:type=\"$type_prefix:$type\"";
} else {
- $type_str = " xsi:type=\"SOAP-ENC:Array\"";
+ $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
@@ -521,32 +597,47 @@ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=fals
}
/**
- * serialize message
+ * serializes a message
*
- * @param string body
- * @param string headers optional
- * @param array namespaces optional
- * @param string style optional (rpc|document)
- * @param string use optional (encoded|literal)
- * @return string 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
+ * @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'){
+ 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($style == 'rpc' && $use == 'encoded') {
- $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
+ if($encodingStyle) {
+ $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
}
// serialize headers
if($headers){
+ if (is_array($headers)) {
+ $xml = '';
+ foreach ($headers as $header) {
+ $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
+ }
+ $headers = $xml;
+ $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
+ }
$headers = "".$headers."";
}
// serialize envelope
@@ -560,15 +651,23 @@ function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc'
"";
}
+ /**
+ * 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 a qualified name
+ * contracts (changes namespace to prefix) a qualified name
*
- * @param string $string qname
+ * @param string $qname qname
* @return string contracted qname
* @access private
*/
@@ -591,7 +690,7 @@ function contractQname($qname){
}
/**
- * expands a qualified name
+ * expands (changes prefix to namespace) a qualified name
*
* @param string $string qname
* @return string expanded qname
@@ -618,8 +717,8 @@ function expandQname($qname){
* returns the local part of a prefixed string
* returns the original string, if not prefixed
*
- * @param string
- * @return string
+ * @param string $str The prefixed string
+ * @return string The local part
* @access public
*/
function getLocalPart($str){
@@ -635,8 +734,8 @@ function getLocalPart($str){
* returns the prefix part of a prefixed string
* returns false, if not prefixed
*
- * @param string
- * @return mixed
+ * @param string $str The prefixed string
+ * @return mixed The prefix or false if there is no prefix
* @access public
*/
function getPrefix($str){
@@ -649,10 +748,9 @@ function getPrefix($str){
/**
* pass it a prefix, it returns a namespace
- * returns false if no namespace registered with the given prefix
*
- * @param string
- * @return mixed
+ * @param string $prefix The prefix
+ * @return mixed The namespace, false if no namespace has the specified prefix
* @access public
*/
function getNamespaceFromPrefix($prefix){
@@ -667,8 +765,8 @@ function getNamespaceFromPrefix($prefix){
* returns the prefix for a given namespace (or prefix)
* or false if no prefixes registered for the given namespace
*
- * @param string
- * @return mixed
+ * @param string $ns The namespace
+ * @return mixed The prefix, false if the namespace has no prefixes
* @access public
*/
function getPrefixFromNamespace($ns) {
@@ -684,7 +782,7 @@ function getPrefixFromNamespace($ns) {
/**
* returns the time in ODBC canonical form with microseconds
*
- * @return string
+ * @return string The time in ODBC canonical form with microseconds
* @access public
*/
function getmicrotime() {
@@ -699,6 +797,13 @@ function getmicrotime() {
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);
@@ -776,6 +881,13 @@ function iso8601_to_timestamp($datestr){
}
}
+/**
+* sleeps some number of microseconds
+*
+* @param string $usec the number of microseconds to sleep
+* @access public
+* @deprecated
+*/
function usleepWindows($usec)
{
$start = gettimeofday();
@@ -794,27 +906,46 @@ function usleepWindows($usec)
/**
-* soap_fault class, allows for creation of faults
-* mainly used for returning faults from deployed functions
+* Contains information for a SOAP fault.
+* Mainly used for returning faults from deployed functions
* in a server instance.
* @author Dietrich Ayala
* @version $Id$
* @access public
*/
class soap_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 (client | server)
+ * @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 string $faultdetail
+ * @param mixed $faultdetail detail, typically a string or array of string
*/
function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
parent::nusoap_base();
@@ -827,6 +958,7 @@ function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
/**
* serialize a fault
*
+ * @return string The serialization of the fault instance.
* @access public
*/
function serialize(){
@@ -839,10 +971,10 @@ function serialize(){
'\n".
''.
''.
- ''.$this->expandEntities($this->faultcode).''.
- ''.$this->expandEntities($this->faultactor).''.
- ''.$this->expandEntities($this->faultstring).''.
- ''.$this->serialize_val($this->faultdetail).''.
+ $this->serialize_val($this->faultcode, 'faultcode').
+ $this->serialize_val($this->faultactor, 'faultactor').
+ $this->serialize_val($this->faultstring, 'faultstring').
+ $this->serialize_val($this->faultdetail, 'detail').
''.
''.
'';
@@ -1390,29 +1522,35 @@ function serializeSchema(){
$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 ref=\"".$this->contractQName($aParts['ref']).'"';
- if(isset($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
- $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
- $contentStr .= ' wsdl:arrayType="'.$this->contractQName($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType']).'"';
+ $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'] != ''){
+ if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
$contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." $schemaPrefix:restriction>\n";
- }
- // compositor obviates complex/simple content
- if(isset($attrs['compositor']) && ($attrs['compositor'] != '')){
- $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." $schemaPrefix:$attrs[compositor]>\n";
- }
- // complex or simple content
- elseif((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
- $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." $schemaPrefix:complexContent>\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 != ''){
@@ -1449,7 +1587,7 @@ function serializeSchema(){
// finish 'er up
$el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
- $el .= " xmlns:$nsp=\"$ns\"\n";
+ $el .= " xmlns:$nsp=\"$ns\"";
}
$xml = $el . ">\n".$xml."$schemaPrefix:schema>\n";
return $xml;
@@ -1475,6 +1613,7 @@ function xdebug($string){
* @param string $ns, namespace of type
* @return mixed
* @access public
+ * @deprecated
*/
function getPHPType($type,$ns){
if(isset($this->typemap[$ns][$type])){
@@ -1488,20 +1627,26 @@ function getPHPType($type,$ns){
}
/**
- * returns an array of information about a given type
+ * returns an associative 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
+ * For a complexType typeDef = array(
* 'restrictionBase' => '',
* 'phpType' => '',
- * 'order' => '(sequence|all)',
+ * '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
* @return mixed
* @access public
+ * @see addComplexType
+ * @see addSimpleType
+ * @see addElement
*/
function getTypeDef($type){
//$this->debug("in getTypeDef for type $type");
@@ -1517,7 +1662,8 @@ function getTypeDef($type){
$ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
$etype = $this->getTypeDef($uqType);
if ($etype) {
- $this->xdebug("in getTypeDef, found type $etype for simpleType $type");
+ $this->xdebug("in getTypeDef, found type for simpleType $type:");
+ $this->xdebug($this->varDump($etype));
if (isset($etype['phpType'])) {
$this->simpleTypes[$type]['phpType'] = $etype['phpType'];
}
@@ -1535,7 +1681,8 @@ function getTypeDef($type){
$ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
$etype = $this->getTypeDef($uqType);
if ($etype) {
- $this->xdebug("in getTypeDef, found type $etype for element $type");
+ $this->xdebug("in getTypeDef, found type for element $type:");
+ $this->xdebug($this->varDump($etype));
if (isset($etype['phpType'])) {
$this->elements[$type]['phpType'] = $etype['phpType'];
}
@@ -1568,6 +1715,7 @@ function getTypeDef($type){
* @param string $type, name of type
* @return mixed
* @access public
+ * @deprecated
*/
function serializeTypeDef($type){
//print "in sTD() for type $type
";
@@ -1603,6 +1751,7 @@ function serializeTypeDef($type){
* @param string $type, name of type
* @return string
* @access public
+ * @deprecated
*/
function typeToForm($name,$type){
// get typedef
@@ -1673,7 +1822,8 @@ function typeToForm($name,$type){
* )
* )
* @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(
@@ -1694,19 +1844,22 @@ function addComplexType($name,$typeClass='complexType',$phpType='array',$composi
/**
* adds a simple type to the schema
*
- * @param name
- * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
- * @param typeClass (simpleType)
- * @param phpType: (scalar)
+ * @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 xmlschema
- *
+ * @see getTypeDef
*/
- function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
+ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
$this->simpleTypes[$name] = array(
- 'name' => $name,
- 'typeClass' => $typeClass,
- 'phpType' => $phpType,
- 'type' => $restrictionBase
+ 'name' => $name,
+ 'typeClass' => $typeClass,
+ 'phpType' => $phpType,
+ 'type' => $restrictionBase,
+ 'enumeration' => $enumeration
);
$this->xdebug("addSimpleType $name:");
@@ -1716,9 +1869,9 @@ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $php
/**
* adds an element to the schema
*
- * @param name
* @param array $attrs attributes that must include name and type
* @see xmlschema
+ * @access public
*/
function addElement($attrs) {
if (! $this->getPrefix($attrs['type'])) {
@@ -1739,30 +1892,76 @@ function addElement($attrs) {
/**
-* for creating serializable abstractions of native PHP types
-* NOTE: this is only really used when WSDL is not available.
+* 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
* @version $Id$
* @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 string $type optional type name
+ * @param mixed $type optional type name
* @param mixed $value optional value
- * @param string $namespace optional namespace of value
- * @param string $type_namespace optional namespace of type
- * @param array $attributes associative array of attributes to add to element serialization
+ * @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->value = $value;
$this->type = $type;
+ $this->value = $value;
$this->element_ns = $element_ns;
$this->type_ns = $type_ns;
$this->attributes = $attributes;
@@ -1771,8 +1970,9 @@ function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_n
/**
* return serialized value
*
+ * @param string $use The WSDL use value (encoded|literal)
* @return string XML data
- * @access private
+ * @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);
@@ -1781,7 +1981,6 @@ function serialize($use='encoded') {
/**
* decodes a soapval object into a PHP native type
*
- * @param object $soapval optional SOAPx4 soapval object, else uses self
* @return mixed
* @access public
*/
@@ -1844,6 +2043,7 @@ function soap_transport_http($url){
$this->setURL($url);
ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
$this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
+ $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']);
}
function setURL($url) {
@@ -1878,7 +2078,8 @@ function setURL($url) {
} else {
$this->outgoing_headers['Host'] = $this->host.':'.$this->port;
}
-
+ $this->debug('set Host: ' . $this->outgoing_headers['Host']);
+
if (isset($u['user']) && $u['user'] != '') {
$this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
}
@@ -1974,11 +2175,19 @@ function connect($connection_timeout=0,$response_timeout=30){
//curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
$this->persistentConnection = false;
$this->outgoing_headers['Connection'] = 'close';
+ $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
}
- // set timeout (NOTE: cURL does not have separate connection and response timeouts)
+ // set timeout
if ($connection_timeout != 0) {
curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
}
+ // TODO: cURL has added a connection timeout separate from the response timeout
+ //if ($connection_timeout != 0) {
+ // curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
+ //}
+ //if ($response_timeout != 0) {
+ // curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_timeout);
+ //}
// recent versions of cURL turn on peer/host checking by default,
// while PHP binaries are not compiled with a default location for the
@@ -2086,8 +2295,6 @@ function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
* @access public
*/
function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
- global $_SERVER;
-
$this->debug("Set credentials for authtype $authtype");
// cf. RFC 2617
if ($authtype == 'basic') {
@@ -2143,7 +2350,7 @@ function setCredentials($username, $password, $authtype = 'basic', $digestReques
$this->digestRequest = $digestRequest;
if (isset($this->outgoing_headers['Authorization'])) {
- $this->debug('Authorization header set: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
+ $this->debug('set Authorization: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
} else {
$this->debug('Authorization header not set');
}
@@ -2157,6 +2364,7 @@ function setCredentials($username, $password, $authtype = 'basic', $digestReques
*/
function setSOAPAction($soapaction) {
$this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
+ $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']);
}
/**
@@ -2169,9 +2377,11 @@ function setEncoding($enc='gzip, deflate') {
if (function_exists('gzdeflate')) {
$this->protocol_version = '1.1';
$this->outgoing_headers['Accept-Encoding'] = $enc;
+ $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']);
if (!isset($this->outgoing_headers['Connection'])) {
$this->outgoing_headers['Connection'] = 'close';
$this->persistentConnection = false;
+ $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
}
set_magic_quotes_runtime(0);
// deprecated
@@ -2194,6 +2404,7 @@ function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword =
$this->port = $proxyport;
if ($proxyusername != '' && $proxypassword != '') {
$this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
+ $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']);
}
}
@@ -2262,7 +2473,8 @@ function decodeChunked($buffer, $lb){
function buildPayload($data, $cookie_str = '') {
// add content-length header
$this->outgoing_headers['Content-Length'] = strlen($data);
-
+ $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']);
+
// start building outgoing payload:
$req = "$this->request_method $this->uri HTTP/$this->protocol_version";
$this->debug("HTTP request: $req");
@@ -2503,6 +2715,7 @@ function getResponse(){
$cErr = curl_error($this->ch);
if ($cErr != '') {
$err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'
';
+ // 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
";
}
@@ -2519,8 +2732,8 @@ function getResponse(){
$this->debug('No cURL error, closing cURL');
curl_close($this->ch);
- // remove 100 header
- if (ereg('^HTTP/1.1 100',$data)) {
+ // remove 100 header(s)
+ while (ereg('^HTTP/1.1 100',$data)) {
if ($pos = strpos($data,"\r\n\r\n")) {
$data = ltrim(substr($data,$pos));
} elseif($pos = strpos($data,"\n\n") ) {
@@ -2611,7 +2824,7 @@ function getResponse(){
($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)");
+ $this->setError("Unsupported HTTP response status $http_status $http_reason (soap_client->response has contents of the response)");
return false;
}
@@ -2685,6 +2898,7 @@ function getResponse(){
function setContentType($type, $charset = false) {
$this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
+ $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']);
}
function usePersistentConnection(){
@@ -2694,6 +2908,7 @@ function usePersistentConnection(){
$this->protocol_version = '1.1';
$this->persistentConnection = true;
$this->outgoing_headers['Connection'] = 'Keep-Alive';
+ $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
return true;
}
@@ -2703,7 +2918,8 @@ function usePersistentConnection(){
* @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) {
@@ -2826,31 +3042,147 @@ function getCookiesForRequest($cookies, $secure=false) {
* @access public
*/
class soap_server extends nusoap_base {
- var $headers = array(); // HTTP headers of request
- var $request = ''; // HTTP request
- var $requestHeaders = ''; // SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
- var $document = ''; // SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
- var $requestSOAP = ''; // SOAP payload for request (text)
- var $methodURI = ''; // requested method namespace URI
- var $methodname = ''; // name of method requested
- var $methodparams = array(); // method parameters from request
- var $xml_encoding = ''; // character set encoding of incoming (request) messages
- var $SOAPAction = ''; // SOAP Action from request
- var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
+ /**
+ * 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 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;
- var $outgoing_headers = array();// HTTP headers of response
- var $response = ''; // HTTP response
- var $responseHeaders = ''; // SOAP headers for response (text)
- var $responseSOAP = ''; // SOAP payload for response (text)
- var $methodreturn = false; // method return to place in response
- var $methodreturnisliteralxml = false; // whether $methodreturn is a string of literal XML
- var $fault = false; // SOAP fault for response
- var $result = 'successful'; // text indication of result (for debugging)
+ /**
+ * 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)
+ * @var string
+ * @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';
- var $operations = array(); // assoc array of operations => opData
- var $wsdl = false; // wsdl instance
- var $externalWSDLURL = false; // URL for WSDL
- var $debug_flag = false; // whether to append debug to response as XML comment
+ /**
+ * 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;
/**
@@ -2864,25 +3196,34 @@ function soap_server($wsdl=false){
parent::nusoap_base();
// turn on debugging?
global $debug;
- global $_REQUEST;
- global $_SERVER;
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 soap_server, set debug_flag=$debug based on global flag");
$this->debug_flag = $debug;
- } else if (isset($_REQUEST['debug'])) {
- $this->debug_flag = $_REQUEST['debug'];
- } else if (isset($_SERVER['QUERY_STRING'])) {
+ } elseif (isset($_SERVER['QUERY_STRING'])) {
$qs = explode('&', $_SERVER['QUERY_STRING']);
foreach ($qs as $v) {
if (substr($v, 0, 6) == 'debug=') {
+ $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
$this->debug_flag = substr($v, 6);
}
}
- } else if (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
+ } 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 soap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
$this->debug_flag = substr($v, 6);
}
}
@@ -2890,6 +3231,7 @@ function soap_server($wsdl=false){
// wsdl
if($wsdl){
+ $this->debug("In soap_server, WSDL is specified");
if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
$this->wsdl = $wsdl;
$this->externalWSDLURL = $this->wsdl->wsdl;
@@ -2914,19 +3256,19 @@ function soap_server($wsdl=false){
* @access public
*/
function service($data){
- global $QUERY_STRING;
- global $_SERVER;
+ global $HTTP_SERVER_VARS;
- if(isset($_SERVER['QUERY_STRING'])){
+ if (isset($_SERVER['QUERY_STRING'])) {
$qs = $_SERVER['QUERY_STRING'];
- } elseif(isset($GLOBALS['QUERY_STRING'])){
- $qs = $GLOBALS['QUERY_STRING'];
- } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
- $qs = $QUERY_STRING;
+ } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
+ $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
+ } else {
+ $qs = '';
}
+ $this->debug("In service, query string=$qs");
- if(isset($qs) && ereg('wsdl', $qs) ){
- // This is a request for WSDL
+ if (ereg('wsdl', $qs) ){
+ $this->debug("In service, this is a request for WSDL");
if($this->externalWSDLURL){
if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
header('Location: '.$this->externalWSDLURL);
@@ -2938,15 +3280,20 @@ function service($data){
} elseif ($this->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 {
header("Content-Type: text/html; charset=ISO-8859-1\r\n");
print "This service does not provide WSDL";
}
} elseif ($data == '' && $this->wsdl) {
- // print web interface
+ $this->debug("In service, there is no data, so return Web description");
print $this->wsdl->webDescription();
} else {
- // handle the request
+ $this->debug("In service, invoke the request");
$this->parse_request($data);
if (! $this->fault) {
$this->invoke_method();
@@ -2972,22 +3319,25 @@ function service($data){
*/
function parse_http_headers() {
global $HTTP_SERVER_VARS;
- global $_SERVER;
$this->request = '';
+ $this->SOAPAction = '';
if(function_exists('getallheaders')){
- $this->headers = getallheaders();
- foreach($this->headers as $k=>$v){
+ $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']);
+ 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(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
+ $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
$this->xml_encoding = strtoupper($enc);
} else {
@@ -2998,19 +3348,20 @@ function parse_http_headers() {
$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(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
+ $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5));
} else {
- $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
+ $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k);
}
- if ($k == 'Soapaction') {
+ if ($k == 'soapaction') {
// get SOAPAction header
$k = 'SOAPAction';
$v = str_replace('"', '', $v);
$v = str_replace('\\', '', $v);
$this->SOAPAction = $v;
- } else if ($k == 'Content-Type') {
+ } else if ($k == 'content-type') {
// get the character encoding of the incoming request
if (strpos($v, '=')) {
$enc = substr(strstr($v, '='), 1);
@@ -3031,36 +3382,42 @@ function parse_http_headers() {
$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(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
- 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 (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
- $this->xml_encoding = strtoupper($enc);
- } else {
- $this->xml_encoding = 'US-ASCII';
- }
+ $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 (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
+ $this->xml_encoding = strtoupper($enc);
} else {
- // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
- $this->xml_encoding = 'ISO-8859-1';
+ $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");
}
+ $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");
}
}
@@ -3091,48 +3448,28 @@ function parse_request($data='') {
$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 (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)) {
+ if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
$data = $degzdata;
- } elseif ($this->headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
+ } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
$data = $degzdata;
} else {
- $this->fault('Client', 'Errors occurred when trying to decode the data');
+ $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
return;
}
} else {
- $this->fault('Client', 'This Server does not support compressed data');
+ $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;
- // parse response, get soap parser obj
- $parser = new soap_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('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_response()');
- $this->methodparams = $parser->get_response();
- // get SOAP headers
- $this->requestHeaders = $parser->getHeaders();
- // add document for doclit support
- $this->document = $parser->document;
- }
$this->debug('leaving parse_request');
}
@@ -3154,7 +3491,26 @@ function parse_request($data='') {
* @access private
*/
function invoke_method() {
- $this->debug('entering invoke_method methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
+ $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
+
+ 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
@@ -3173,37 +3529,27 @@ class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
// get the class and method name
$class = substr($this->methodname, 0, strpos($this->methodname, $delim));
$method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
- $this->debug("class: $class method: $method delim: $delim");
+ $this->debug("in invoke_method, class=$class method=$method delim=$delim");
}
// does method exist?
if ($class == '') {
if (!function_exists($this->methodname)) {
- $this->debug("function '$this->methodname' not found!");
+ $this->debug("in invoke_method, function '$this->methodname' not found!");
$this->result = 'fault: method not found';
- $this->fault('Client',"method '$this->methodname' not defined in service");
+ $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
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("method '$this->methodname' not found in class '$class'!");
+ $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
$this->result = 'fault: method not found';
- $this->fault('Client',"method '$this->methodname' not defined in service");
+ $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
return;
}
}
- if($this->wsdl){
- if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){
- //if(
- $this->fault('Client',"Operation '$this->methodname' is not defined in the WSDL for this service");
- return;
- }
- $this->debug('opData:');
- $this->appendDebug($this->varDump($this->opData));
- }
- $this->debug("method '$this->methodname' exists");
// evaluate message, getting back parameters
// verify that request parameters match the method's signature
if(! $this->verify_method($this->methodname,$this->methodparams)){
@@ -3211,24 +3557,24 @@ class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
$this->debug('ERROR: request not verified against method signature');
$this->result = 'fault: request failed validation against method signature';
// return fault
- $this->fault('Client',"Operation '$this->methodname' not defined in service.");
+ $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
return;
}
// if there are parameters to pass
- $this->debug('params:');
+ $this->debug('in invoke_method, params:');
$this->appendDebug($this->varDump($this->methodparams));
- $this->debug("calling '$this->methodname'");
+ $this->debug("in invoke_method, calling '$this->methodname'");
if (!function_exists('call_user_func_array')) {
if ($class == '') {
- $this->debug('calling function using eval()');
+ $this->debug('in invoke_method, calling function using eval()');
$funcCall = "\$this->methodreturn = $this->methodname(";
} else {
if ($delim == '..') {
- $this->debug('calling class method using eval()');
+ $this->debug('in invoke_method, calling class method using eval()');
$funcCall = "\$this->methodreturn = ".$class."::".$method."(";
} else {
- $this->debug('calling instance method using eval()');
+ $this->debug('in invoke_method, calling instance method using eval()');
// generate unique instance name
$instname = "\$inst_".time();
$funcCall = $instname." = new ".$class."(); ";
@@ -3238,7 +3584,7 @@ class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
if ($this->methodparams) {
foreach ($this->methodparams as $param) {
if (is_array($param)) {
- $this->fault('Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
+ $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\",";
@@ -3246,25 +3592,25 @@ class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
$funcCall = substr($funcCall, 0, -1);
}
$funcCall .= ');';
- $this->debug('function call: '.$funcCall);
+ $this->debug('in invoke_method, function call: '.$funcCall);
@eval($funcCall);
} else {
if ($class == '') {
- $this->debug('calling function using call_user_func_array()');
+ $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('calling class method using call_user_func_array()');
+ $this->debug('in invoke_method, calling class method using call_user_func_array()');
$call_arg = array ($class, $method);
} else {
- $this->debug('calling instance method using call_user_func_array()');
+ $this->debug('in invoke_method, calling instance method using call_user_func_array()');
$instance = new $class ();
$call_arg = array(&$instance, $method);
}
- $this->methodreturn = call_user_func_array($call_arg, $this->methodparams);
+ $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
}
- $this->debug('methodreturn:');
+ $this->debug('in invoke_method, methodreturn:');
$this->appendDebug($this->varDump($this->methodreturn));
- $this->debug("leaving invoke_method: called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
+ $this->debug("in invoke_method, called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
}
/**
@@ -3304,7 +3650,7 @@ function serialize_return() {
$this->wsdl->clearDebug();
if($errstr = $this->wsdl->getError()){
$this->debug('got wsdl error: '.$errstr);
- $this->fault('Server', 'unable to serialize result');
+ $this->fault('SOAP-ENV:Server', 'unable to serialize result');
return;
}
} else {
@@ -3342,8 +3688,13 @@ function serialize_return() {
//if($this->debug_flag){
$this->appendDebug($this->wsdl->getDebug());
// }
+ if (isset($opData['output']['encodingStyle'])) {
+ $encodingStyle = $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->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$encodingStyle);
} else {
$this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
}
@@ -3383,12 +3734,15 @@ function send_response() {
$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";
- $this->outgoing_headers[] = "Content-Type: text/xml; charset=$this->soap_defencoding";
+ $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 (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 .= "";
@@ -3400,7 +3754,7 @@ function send_response() {
$payload .= "";
}
}
- } elseif (strstr($this->headers['Accept-Encoding'], 'deflate')) {
+ } 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)
@@ -3431,8 +3785,9 @@ function send_response() {
* takes the value that was created by parsing the request
* and compares to the method's signature, if available.
*
- * @param mixed
- * @return boolean
+ * @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){
@@ -3447,39 +3802,145 @@ function verify_method($operation,$request){
}
/**
- * add a method to the dispatch map
+ * processes SOAP message received from client
*
- * @param string $methodname
- * @param string $in array of input values
- * @param string $out array of output values
- * @access public
+ * @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 add_to_map($methodname,$in,$out){
- $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
- }
-
- /**
- * register a service with the server
+ function parseRequest($headers, $data) {
+ $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
+ 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(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$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 soap_parser');
+ // parse response, get soap parser obj
+ $parser = new soap_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_response()');
+ $this->methodparams = $parser->get_response();
+ // get SOAP headers
+ $this->requestHeaders = $parser->getHeaders();
+ // 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 assoc array of input values: key = param name, value = param type
- * @param string $out assoc array of output values: key = param name, value = param type
- * @param string $namespace
- * @param string $soapaction
- * @param string $style optional (rpc|document)
- * @param string $use optional (encoded|literal)
+ * @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=''){
+ 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) {
- $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
- $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
+ if (isset($_SERVER)) {
+ $SERVER_NAME = $_SERVER['SERVER_NAME'];
+ $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
+ } 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'];
+ } else {
+ $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
+ }
$soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name";
}
if(false == $style) {
@@ -3488,7 +3949,10 @@ function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=fa
if(false == $use) {
$use = "encoded";
}
-
+ if ($use == 'encoded' && $encodingStyle = '') {
+ $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
+ }
+
$this->operations[$name] = array(
'name' => $name,
'in' => $in,
@@ -3497,58 +3961,67 @@ function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=fa
'soapaction' => $soapaction,
'style' => $style);
if($this->wsdl){
- $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation);
+ $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
}
return true;
}
/**
- * create a fault. this also acts as a flag to the server that a fault has occured.
+ * 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
+ * @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 soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
$this->fault->soap_defencoding = $this->soap_defencoding;
}
/**
- * sets up wsdl object
- * this acts as a flag to enable internal WSDL generation
+ * Sets up wsdl object.
+ * Acts as a flag to enable internal WSDL generation
*
* @param string $serviceName, name of the service
- * @param string $namespace optional tns namespace
- * @param string $endpoint optional URL of service endpoint
+ * @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 string $schemaTargetNamespace optional targetNamespace for service schema
+ * @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)
{
- $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
- $SERVER_PORT = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : $GLOBALS['SERVER_PORT'];
+ 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_PORT == 80) {
$SERVER_PORT = '';
} else {
$SERVER_PORT = ':' . $SERVER_PORT;
}
- $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
if(false == $namespace) {
$namespace = "http://$SERVER_NAME/soap/$serviceName";
}
if(false == $endpoint) {
- if (isset($_SERVER['HTTPS'])) {
- $HTTPS = $_SERVER['HTTPS'];
- } elseif (isset($GLOBALS['HTTPS'])) {
- $HTTPS = $GLOBALS['HTTPS'];
- } else {
- $HTTPS = '0';
- }
if ($HTTPS == '1' || $HTTPS == 'on') {
$SCHEME = 'https';
} else {
@@ -3680,7 +4153,7 @@ function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,
if ($url != '') {
$urlparts = parse_url($url);
if (!isset($urlparts['host'])) {
- $url = $wsdlparts['scheme'] . '://' . $wsdlparts['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)) {
@@ -3706,7 +4179,7 @@ function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,
if ($url != '') {
$urlparts = parse_url($url);
if (!isset($urlparts['host'])) {
- $url = $wsdlparts['scheme'] . '://' . $wsdlparts['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)) {
@@ -3878,19 +4351,10 @@ function start_element($parser, $name, $attrs)
// set self as current value for this depth
$this->depth_array[$depth] = $pos;
$this->message[$pos] = array('cdata' => '');
- // get element prefix
- if (ereg(':', $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
if (count($attrs) > 0) {
+ // register namespace declarations
foreach($attrs as $k => $v) {
- // if ns declarations, add to class level array of valid namespaces
if (ereg("^xmlns", $k)) {
if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
$this->namespaces[$ns_prefix] = $v;
@@ -3901,8 +4365,10 @@ function start_element($parser, $name, $attrs)
$this->XMLSchemaVersion = $v;
$this->namespaces['xsi'] = $v . '-instance';
}
- } //
- // expand each attribute
+ }
+ }
+ // 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;
@@ -3913,6 +4379,16 @@ function start_element($parser, $name, $attrs)
} else {
$attrs = array();
}
+ // get element prefix, namespace and name
+ if (ereg(':', $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':
@@ -4071,6 +4547,8 @@ function end_element($parser, $name){
// unset schema status
if (/*ereg('types$', $name) ||*/ ereg('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');
}
@@ -4162,6 +4640,7 @@ function getOperationData($operation, $bindingType = 'soap')
// 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;
@@ -4171,6 +4650,32 @@ function getOperationData($operation, $bindingType = 'soap')
}
}
+ /**
+ * 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
+ * @return array
+ * @access public
+ */
+ function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
+ if ($bindingType == 'soap') {
+ $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
+ }
+ // 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
@@ -4183,19 +4688,20 @@ function getOperationData($operation, $bindingType = 'soap')
* 'attrs' => array() // refs to attributes array
* )
*
- * @param $type string
- * @param $ns string
+ * @param $type string the type
+ * @param $ns string namespace (not prefix) of the type
* @return mixed
* @access public
* @see 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("type namespace forced to $ns");
+ $this->debug("in getTypeDef: type namespace forced to $ns");
}
if (isset($this->schemas[$ns])) {
- $this->debug("have schema for namespace $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);
@@ -4208,20 +4714,24 @@ function getTypeDef($type, $ns) {
$ns = substr($t['type'], 0, strrpos($t['type'], ':'));
$etype = $this->getTypeDef($uqType, $ns);
if ($etype) {
- $this->debug("found type $etype for [element] $type");
+ $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'];
+ }
}
}
return $t;
}
}
} else {
- $this->debug("do not have schema for namespace $ns");
+ $this->debug("in getTypeDef: do not have schema for namespace $ns");
}
return false;
}
@@ -4232,6 +4742,16 @@ function getTypeDef($type, $ns) {
* @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 = '
NuSOAP: '.$this->serviceName.'