Spaces:
Sleeping
Sleeping
| /* | |
| $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 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 | |
| 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 | |
| */ | |
| /* 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> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ | |
| * @access public | |
| */ | |
| 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.7.2'; | |
| /** | |
| * CVS revision for HTTP headers. | |
| * | |
| * @var string | |
| * @access private | |
| */ | |
| var $revision = '$Revision: 1.94 $'; | |
| /** | |
| * 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 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); | |
| } | |
| return "<!--\n" . $this->debug_str . "\n-->"; | |
| } | |
| /** | |
| * 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) | |
| * @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); | |
| } | |
| // 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)) { | |
| if ($use == 'literal') { | |
| // TODO: depends on minOccurs | |
| return "<$name$xmlns $atts/>"; | |
| } else { | |
| 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 | |
| if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$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') { | |
| return "<$name$xmlns $atts>$val</$name>"; | |
| } else { | |
| return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>"; | |
| } | |
| } | |
| // detect type and serialize | |
| $xml = ''; | |
| switch(true) { | |
| case (is_bool($val) || $type == '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'): | |
| 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'): | |
| 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'): | |
| $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): | |
| 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); | |
| } | |
| $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>'; | |
| break; | |
| break; | |
| case (is_array($val) || $type): | |
| // detect if struct or array | |
| $valueType = $this->isArraySimpleOrStruct($val); | |
| if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ | |
| $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 | |
| 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: | |
| $xml .= 'not detected, got '.gettype($val).' for '.$val; | |
| break; | |
| } | |
| 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 | |
| * @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 $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 = "<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 $string qname | |
| * @return string expanded qname | |
| * @access private | |
| */ | |
| function expandQname($qname){ | |
| // get element prefix | |
| if(strpos($qname,':') && !ereg('^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(); | |
| if (!class_exists('G')) { | |
| $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
| $docuroot = explode( '/', $realdocuroot ); | |
| array_pop( $docuroot ); | |
| $pathhome = implode( '/', $docuroot ) . '/'; | |
| array_pop( $docuroot ); | |
| $pathTrunk = implode( '/', $docuroot ) . '/'; | |
| require_once($pathTrunk.'gulliver/system/class.g.php'); | |
| } | |
| $filter = new InputFilter(); | |
| $data = $filter->xssFilterHard($data); | |
| var_dump($data); | |
| $ret_val = ob_get_contents(); | |
| ob_end_clean(); | |
| return $ret_val; | |
| } | |
| } | |
| // XML Schema Datatype Helper Functions | |
| //xsd:dateTime helpers | |
| /** | |
| * convert unix timestamp to ISO 8601 compliant date string | |
| * | |
| * @param string $timestamp Unix time stamp | |
| * @access public | |
| */ | |
| function timestamp_to_iso8601($timestamp,$utc=true){ | |
| $datestr = date('Y-m-d\TH:i:sO',$timestamp); | |
| if($utc){ | |
| $eregStr = | |
| '([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(ereg($eregStr,$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 | |
| * @access public | |
| */ | |
| function iso8601_to_timestamp($datestr){ | |
| $eregStr = | |
| '([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(ereg($eregStr,$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 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); | |
| } | |
| /** | |
| * 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.94 2005/08/04 01:27:42 snichol Exp $ | |
| * @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 $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 soap_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; | |
| } | |
| } | |
| /** | |
| * parses an XML Schema, allows access to it's data, other utility methods | |
| * no validation... yet. | |
| * very experimental and limited. As is discussed on XML-DEV, I'm one of the people | |
| * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty | |
| * tutorials I refer to :) | |
| * | |
| * @author Dietrich Ayala <dietrich@ganx4.com> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ | |
| * @access public | |
| */ | |
| class 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 XMLSchema($schema='',$xml='',$namespaces=array()){ | |
| parent::nusoap_base(); | |
| $this->debug('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()!!'); | |
| } | |
| } | |
| /** | |
| * 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(ereg("^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'])) { | |
| $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 | |
| break; | |
| case 'complexType': | |
| array_push($this->complexTypeStack, $this->currentComplexType); | |
| if(isset($attrs['name'])){ | |
| $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']) && ereg(':Array$',$attrs['base'])){ | |
| $this->xdebug('complexType is unusual array'); | |
| $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; | |
| } else { | |
| $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; | |
| } | |
| }else{ | |
| $this->xdebug('processing unnamed complexType for element '.$this->currentElement); | |
| $this->currentComplexType = $this->currentElement . '_ContainedType'; | |
| //$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']) && ereg(':Array$',$attrs['base'])){ | |
| $this->xdebug('complexType is unusual array'); | |
| $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; | |
| } else { | |
| $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; | |
| } | |
| } | |
| break; | |
| case 'element': | |
| array_push($this->elementStack, $this->currentElement); | |
| // elements defined as part of a complex type should | |
| // not really be added to $this->elements, but for some | |
| // reason, they are | |
| if (!isset($attrs['form'])) { | |
| $attrs['form'] = $this->schemaInfo['elementFormDefault']; | |
| } | |
| 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']; | |
| $this->elements[ $attrs['name'] ] = $attrs; | |
| $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; | |
| $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 { | |
| $this->xdebug("processing untyped element ".$attrs['name']); | |
| $this->currentElement = $attrs['name']; | |
| $this->elements[ $attrs['name'] ] = $attrs; | |
| $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; | |
| $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType'; | |
| $this->elements[ $attrs['name'] ]['type'] = $attrs['type']; | |
| $ename = $attrs['name']; | |
| } | |
| if(isset($ename) && $this->currentComplexType){ | |
| $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; | |
| } | |
| 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) { | |
| $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; | |
| } | |
| 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 'list': // simpleType value list | |
| 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 | |
| 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 { | |
| $this->xdebug('processing unnamed simpleType for element '.$this->currentElement); | |
| $this->currentSimpleType = $this->currentElement . '_ContainedType'; | |
| //$this->currentElement = false; | |
| $this->simpleTypes[$this->currentSimpleType] = $attrs; | |
| $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; | |
| } | |
| break; | |
| case 'union': // simpleType type list | |
| break; | |
| default: | |
| //$this->xdebug("do not have anything to do for 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->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->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: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 | |
| $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n"; | |
| foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { | |
| $el .= " xmlns:$nsp=\"$ns\"\n"; | |
| } | |
| $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 | |
| * @return mixed | |
| * @access public | |
| * @see addComplexType | |
| * @see addSimpleType | |
| * @see addElement | |
| */ | |
| function getTypeDef($type){ | |
| //$this->debug("in getTypeDef for type $type"); | |
| if(isset($this->complexTypes[$type])){ | |
| $this->xdebug("in getTypeDef, found complexType $type"); | |
| return $this->complexTypes[$type]; | |
| } elseif(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']; | |
| } | |
| } 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 (ereg('_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($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 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 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'] ])); | |
| } | |
| } | |
| /** | |
| * 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.94 2005/08/04 01:27:42 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); | |
| } | |
| /** | |
| * decodes a soapval object into a PHP native type | |
| * | |
| * @return mixed | |
| * @access public | |
| */ | |
| function decode(){ | |
| return $this->value; | |
| } | |
| } | |
| /** | |
| * 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> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 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 $useSOAPAction = true; | |
| var $persistentConnection = false; | |
| var $ch = false; // cURL handle | |
| var $username = ''; | |
| var $password = ''; | |
| var $authtype = ''; | |
| var $digestRequest = array(); | |
| var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, 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 | |
| // verifypeer: default is 1 | |
| // verifyhost: default is 1 | |
| /** | |
| * constructor | |
| */ | |
| function soap_transport_http($url){ | |
| parent::nusoap_base(); | |
| $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) { | |
| $this->url = $url; | |
| $u = parse_url($url); | |
| foreach($u as $k => $v){ | |
| $this->debug("$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->outgoing_headers['Host'] = $this->host; | |
| } 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']) : ''); | |
| } | |
| } | |
| 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->scheme == 'http' || $this->scheme == 'ssl') { | |
| // 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://' . $this->host; | |
| } else { | |
| $host = $this->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->scheme == 'https') { | |
| if (!extension_loaded('curl')) { | |
| $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); | |
| return false; | |
| } | |
| $this->debug('connect using https'); | |
| // init CURL | |
| $this->ch = curl_init(); | |
| // set url | |
| $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host"; | |
| // add path | |
| $hostURL .= $this->path; | |
| curl_setopt($this->ch, CURLOPT_URL, $hostURL); | |
| // follow location headers (re-directs) | |
| curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1); | |
| // ask for headers in the response output | |
| curl_setopt($this->ch, CURLOPT_HEADER, 1); | |
| // ask for the response output as the return value | |
| curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1); | |
| // encode | |
| // We manage this ourselves through headers and encoding | |
| // if(function_exists('gzuncompress')){ | |
| // curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate'); | |
| // } | |
| // persistent connection | |
| if ($this->persistentConnection) { | |
| // The way we send data, we cannot use persistent connections, since | |
| // there will be some "junk" at the end of our request. | |
| //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 | |
| 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 | |
| // CA cert bundle, so disable peer/host checking. | |
| //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); | |
| curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0); | |
| curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0); | |
| // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) | |
| if ($this->authtype == 'certificate') { | |
| //added by Onti | |
| $this->debug('authtype == certificate'); | |
| if (isset($this->certRequest['cainfofile'])) { | |
| curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']); | |
| } | |
| if (isset($this->certRequest['verifypeer'])) { | |
| curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); | |
| } else { | |
| curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1); | |
| } | |
| if (isset($this->certRequest['verifyhost'])) { | |
| curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); | |
| } else { | |
| curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1); | |
| } | |
| if (isset($this->certRequest['sslcertfile'])) { | |
| curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); | |
| } | |
| if (isset($this->certRequest['sslkeyfile'])) { | |
| curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); | |
| } | |
| if (isset($this->certRequest['passphrase'])) { | |
| curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']); | |
| } | |
| curl_setopt($this->ch, CURLOPT_VERBOSE , 1 ); | |
| //$handle = fopen('/home/xfer/curl.log', "ab+"); | |
| //fwrite ($handle, date('Y-m-d H:i:s')."\n\n"); | |
| //curl_setopt($this->ch, CURLOPT_STDERR, $handle ); | |
| } | |
| $this->debug('cURL connection set up'); | |
| return true; | |
| } else { | |
| $this->setError('Unknown scheme ' . $this->scheme); | |
| $this->debug('Unknown scheme ' . $this->scheme); | |
| return false; | |
| } | |
| } | |
| /** | |
| * send the SOAP message via HTTP | |
| * | |
| * @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->debug('end of send()'); | |
| return $respdata; | |
| } | |
| /** | |
| * send the SOAP message via HTTPS 1.0 using CURL | |
| * | |
| * @param string $msg 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 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) | |
| * @param array $digestRequest (keys must be nonce, nc, realm, qop) | |
| * @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', $digestRequest = array(), $certRequest = array()) { | |
| $this->debug("Set credentials for authtype $authtype"); | |
| // cf. RFC 2617 | |
| if ($authtype == 'basic') { | |
| $this->outgoing_headers['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 = $this->encryptOld($A1); | |
| // A2 = Method ":" digest-uri-value | |
| $A2 = 'POST:' . $this->digest_uri; | |
| // H(A2) | |
| $HA2 = $this->encryptOld($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 = $this->encryptOld($unhashedDigest); | |
| $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'; | |
| } | |
| } elseif ($authtype == 'certificate') { | |
| $this->certRequest = $certRequest; | |
| } | |
| $this->username = $username; | |
| $this->password = $password; | |
| $this->authtype = $authtype; | |
| $this->digestRequest = $digestRequest; | |
| if (isset($this->outgoing_headers['Authorization'])) { | |
| $this->debug('set Authorization: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...'); | |
| } else { | |
| $this->debug('Authorization header not set'); | |
| } | |
| } | |
| /** | |
| * set the soapaction value | |
| * | |
| * @param string $soapaction | |
| * @access public | |
| */ | |
| function setSOAPAction($soapaction) { | |
| $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"'; | |
| $this->debug('set SOAPAction: ' . $this->outgoing_headers['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->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 | |
| $this->encoding = $enc; | |
| } | |
| } | |
| /** | |
| * set proxy info here | |
| * | |
| * @param string $proxyhost | |
| * @param string $proxyport | |
| * @param string $proxyusername | |
| * @param string $proxypassword | |
| * @access public | |
| */ | |
| function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { | |
| $this->uri = $this->url; | |
| $this->host = $proxyhost; | |
| $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']); | |
| } | |
| } | |
| /** | |
| * 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 payload, including HTTP headers, to $this->outgoing_payload. | |
| */ | |
| 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"); | |
| $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; | |
| } | |
| 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->scheme == 'http' || $this->scheme == 'ssl') { | |
| // 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->scheme == 'https') { | |
| // set payload | |
| // TODO: 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 | |
| //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); | |
| foreach($this->outgoing_headers as $k => $v){ | |
| $curl_headers[] = "$k: $v"; | |
| } | |
| if ($cookie_str != '') { | |
| $curl_headers[] = 'Cookie: ' . $cookie_str; | |
| } | |
| curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers); | |
| if ($this->request_method == "POST") { | |
| curl_setopt($this->ch, CURLOPT_POST, 1); | |
| curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data); | |
| } else { | |
| } | |
| $this->debug('set cURL payload'); | |
| return true; | |
| } | |
| } | |
| function getResponse(){ | |
| $this->incoming_payload = ''; | |
| if ($this->scheme == 'http' || $this->scheme == 'ssl') { | |
| // 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 header | |
| if(isset($lb) && ereg('^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->scheme == 'https') { | |
| // 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); | |
| // 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") ) { | |
| $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; | |
| } | |
| } | |
| } | |
| $arr = explode(' ', $header_array[0], 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) { | |
| $this->debug("Got 301 $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; | |
| } | |
| 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(){ | |
| if (isset($this->outgoing_headers['Accept-Encoding'])) { | |
| return false; | |
| } | |
| $this->protocol_version = '1.1'; | |
| $this->persistentConnection = true; | |
| $this->outgoing_headers['Connection'] = 'Keep-Alive'; | |
| $this->debug('set Connection: ' . $this->outgoing_headers['Connection']); | |
| 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 = explode(';', $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; | |
| } | |
| public function encryptOld($string) | |
| { | |
| if (!class_exists('G')) { | |
| $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
| $docuroot = explode( '/', $realdocuroot ); | |
| array_pop( $docuroot ); | |
| $pathhome = implode( '/', $docuroot ) . '/'; | |
| array_pop( $docuroot ); | |
| $pathTrunk = implode( '/', $docuroot ) . '/'; | |
| require_once($pathTrunk.'gulliver/system/class.g.php'); | |
| } | |
| return G::encryptOld($string); | |
| } | |
| } | |
| /** | |
| * | |
| * soap_server allows the user to create a SOAP server | |
| * that is capable of receiving messages and returning responses | |
| * | |
| * NOTE: WSDL functionality is experimental | |
| * | |
| * @author Dietrich Ayala <dietrich@ganx4.com> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ | |
| * @access public | |
| */ | |
| class soap_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 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) | |
| * @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'; | |
| /** | |
| * 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 soap_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 soap_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 soap_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 soap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); | |
| $this->debug_flag = substr($v, 6); | |
| } | |
| } | |
| } | |
| // 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; | |
| $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()){ | |
| if (!class_exists('G')) { | |
| $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
| $docuroot = explode( '/', $realdocuroot ); | |
| array_pop( $docuroot ); | |
| $pathhome = implode( '/', $docuroot ) . '/'; | |
| array_pop( $docuroot ); | |
| $pathTrunk = implode( '/', $docuroot ) . '/'; | |
| require_once($pathTrunk.'gulliver/system/class.g.php'); | |
| } | |
| $filter = new InputFilter(); | |
| $err = $filter->xssFilterHard($err); | |
| 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['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, query string=$qs"); | |
| 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); | |
| } else { // assume file | |
| header("Content-Type: text/xml\r\n"); | |
| $fp = fopen($this->externalWSDLURL, 'r'); | |
| fpassthru($fp); | |
| } | |
| } 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) { | |
| $this->debug("In service, there is no data, so return Web description"); | |
| if (!class_exists('G')) { | |
| $realdocuroot = str_replace( '\\', '/', $_SERVER['DOCUMENT_ROOT'] ); | |
| $docuroot = explode( '/', $realdocuroot ); | |
| array_pop( $docuroot ); | |
| $pathhome = implode( '/', $docuroot ) . '/'; | |
| array_pop( $docuroot ); | |
| $pathTrunk = implode( '/', $docuroot ) . '/'; | |
| require_once($pathTrunk.'gulliver/system/class.g.php'); | |
| } | |
| $filter = new InputFilter(); | |
| $webDescription = $filter->xssFilterHard($this->wsdl->webDescription()); | |
| print $webDescription; | |
| } else { | |
| $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(); | |
| } | |
| } | |
| /** | |
| * 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)/',$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)))); $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)/', $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)/', $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('Client', 'Errors occurred when trying to decode the data'); | |
| return; | |
| } | |
| } else { | |
| $this->fault('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 ($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('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 | |
| $class = ''; | |
| $method = ''; | |
| if (strpos($this->methodname, '..') > 0) { | |
| $delim = '..'; | |
| } else if (strpos($this->methodname, '.') > 0) { | |
| $delim = '.'; | |
| } else { | |
| $delim = ''; | |
| } | |
| if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && | |
| 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("in invoke_method, class=$class method=$method delim=$delim"); | |
| } | |
| // 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('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("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"); | |
| 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('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)) { | |
| $this->fault('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); | |
| } | |
| $this->methodreturn = call_user_func_array($call_arg, $this->methodparams); | |
| } | |
| $this->debug('in invoke_method, methodreturn:'); | |
| $this->appendDebug($this->varDump($this->methodreturn)); | |
| $this->debug("in invoke_method, called method $this->methodname, received $this->methodreturn 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) && (get_class($this->methodreturn) == 'soap_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){ | |
| // weak attempt at supporting multiple output params | |
| if(sizeof($this->opData['output']['parts']) > 1){ | |
| $opParams = $this->methodreturn; | |
| } else { | |
| // TODO: is this really necessary? | |
| $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('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') { | |
| $payload = '<'.$this->methodname.'Response xmlns="'.$this->methodURI.'">'.$return_val.'</'.$this->methodname."Response>"; | |
| } else { | |
| $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$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($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'],$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"; | |
| ereg('\$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) . ' 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(preg_match('/(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('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 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']; | |
| } 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) { | |
| $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 soap_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 = $_SERVER['HTTPS']; | |
| } 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 = $HTTP_SERVER_VARS['HTTPS']; | |
| } else { | |
| $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); | |
| } | |
| 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 xmlschema('', '', $this->wsdl->namespaces); | |
| $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/'); | |
| } | |
| } | |
| /** | |
| * parses a WSDL file, allows access to it's data, other utility methods | |
| * | |
| * @author Dietrich Ayala <dietrich@ganx4.com> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 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; | |
| /** | |
| * 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 | |
| * @access public | |
| */ | |
| function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){ | |
| parent::nusoap_base(); | |
| $this->wsdl = $wsdl; | |
| $this->proxyhost = $proxyhost; | |
| $this->proxyport = $proxyport; | |
| $this->proxyusername = $proxyusername; | |
| $this->proxypassword = $proxypassword; | |
| $this->timeout = $timeout; | |
| $this->response_timeout = $response_timeout; | |
| // parse wsdl file | |
| if ($wsdl != "") { | |
| $this->debug('initial wsdl URL: ' . $wsdl); | |
| $this->parseWSDL($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'] ]; | |
| } | |
| if (isset($bindingData['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 = '') | |
| { | |
| 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); | |
| $tr->request_method = 'GET'; | |
| $tr->useSOAPAction = false; | |
| if($this->proxyhost && $this->proxyport){ | |
| $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); | |
| } | |
| $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 = '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 (ereg('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 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 (ereg("^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 (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': | |
| if ($name == 'part') { | |
| if (isset($attrs['type'])) { | |
| $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs)); | |
| $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; | |
| } | |
| if (isset($attrs['element'])) { | |
| $this->debug("msg " . $this->currentMessage . ": found part $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 (/*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'); | |
| } | |
| 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; | |
| } | |
| } | |
| function getBindingData($binding) | |
| { | |
| if (is_array($this->bindings[$binding])) { | |
| return $this->bindings[$binding]; | |
| } | |
| } | |
| /** | |
| * returns an assoc array of operation names => operation data | |
| * | |
| * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported) | |
| * @return array | |
| * @access public | |
| */ | |
| function getOperations($bindingType = 'soap') | |
| { | |
| $ops = array(); | |
| 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) { | |
| //$this->debug("getOperations for port $port"); | |
| //$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']); | |
| } | |
| } | |
| } | |
| 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 | |
| * @return array | |
| * @access public | |
| */ | |
| function getOperationData($operation, $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) { | |
| // 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 | |
| * @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 | |
| * | |
| * typeDef = array( | |
| * 'elements' => array(), // refs to elements array | |
| * 'restrictionBase' => '', | |
| * 'phpType' => '', | |
| * 'order' => '(sequence|all)', | |
| * 'attrs' => array() // refs to attributes array | |
| * ) | |
| * | |
| * @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("in getTypeDef: type namespace forced to $ns"); | |
| } | |
| 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) { | |
| 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']; | |
| } | |
| } | |
| } | |
| return $t; | |
| } | |
| } | |
| } 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: 105%; margin-left: 0px; | |
| padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} | |
| .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>"; | |
| 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); | |
| $typeDef = $this->getTypeDef($this->getLocalPart($partType), $ns); | |
| if ($typeDef['typeClass'] == 'element') { | |
| $elementortype = 'element'; | |
| } else { | |
| $elementortype = 'type'; | |
| } | |
| $xml .= '<part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />'; | |
| } | |
| } | |
| $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 .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; | |
| $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; | |
| foreach($attrs['operations'] as $opName => $opParts) { | |
| $binding_xml .= '<operation name="' . $opName . '">'; | |
| $binding_xml .= '<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 .= '<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 .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; | |
| $binding_xml .= '</operation>'; | |
| $portType_xml .= '<operation name="' . $opParts['name'] . '"'; | |
| if (isset($opParts['parameterOrder'])) { | |
| $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; | |
| } | |
| $portType_xml .= '>'; | |
| if(isset($opParts['documentation']) && $opParts['documentation'] != '') { | |
| $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; | |
| } | |
| $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>'; | |
| $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>'; | |
| $portType_xml .= '</operation>'; | |
| } | |
| $portType_xml .= '</portType>'; | |
| $binding_xml .= '</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 .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; | |
| $xml .= '<soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; | |
| $xml .= '</port>'; | |
| } | |
| } | |
| $xml .= '</service>'; | |
| return $xml . "\n</definitions>"; | |
| } | |
| /** | |
| * serialize PHP values 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 | |
| */ | |
| function serializeRPCParameters($operation, $direction, $parameters) | |
| { | |
| $this->debug("in serializeRPCParameters: 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('have ' . count($opData[$direction]['parts']) . ' part(s) to serialize'); | |
| if (is_array($parameters)) { | |
| $parametersArrayType = $this->isArraySimpleOrStruct($parameters); | |
| $this->debug('have ' . count($parameters) . ' parameter(s) provided as ' . $parametersArrayType . ' to serialize'); | |
| 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("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 $ type name | |
| * @param mixed $ param value | |
| * @return mixed new param or false if initial value didn't validate | |
| * @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 == '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)); | |
| } | |
| $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 | |
| $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>"; | |
| } | |
| $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) { | |
| $xml = ''; | |
| 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"); | |
| } | |
| if (isset($typeDef['extensionBase'])) { | |
| $ns = $this->getPrefix($typeDef['extensionBase']); | |
| $uqType = $this->getLocalPart($typeDef['extensionBase']); | |
| if ($this->getNamespaceFromPrefix($ns)) { | |
| $ns = $this->getNamespaceFromPrefix($ns); | |
| } | |
| if ($typeDef = $this->getTypeDef($uqType, $ns)) { | |
| $this->debug("serialize attributes for extension base $ns:$uqType"); | |
| $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); | |
| } else { | |
| $this->debug("extension base $ns:$uqType is not a supported type"); | |
| } | |
| } | |
| 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) { | |
| $xml = ''; | |
| 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 (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"); | |
| } | |
| if (isset($typeDef['extensionBase'])) { | |
| $ns = $this->getPrefix($typeDef['extensionBase']); | |
| $uqType = $this->getLocalPart($typeDef['extensionBase']); | |
| if ($this->getNamespaceFromPrefix($ns)) { | |
| $ns = $this->getNamespaceFromPrefix($ns); | |
| } | |
| if ($typeDef = $this->getTypeDef($uqType, $ns)) { | |
| $this->debug("serialize elements for extension base $ns:$uqType"); | |
| $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); | |
| } else { | |
| $this->debug("extension base $ns:$uqType is not a supported type"); | |
| } | |
| } | |
| 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 = array ( name => array(name=>'',type=>'') ) | |
| * @param array attrs = array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) | |
| * @param string arrayType: namespace:name (xsd:string) | |
| * @see xmlschema | |
| * @access public | |
| */ | |
| function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { | |
| if (count($elements) > 0) { | |
| foreach($elements as $n => $e){ | |
| // expand each element | |
| 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 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 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); | |
| } | |
| $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); | |
| } | |
| $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); | |
| $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType')); | |
| $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; | |
| } | |
| } | |
| /** | |
| * | |
| * soap_parser class parses SOAP XML messages into native PHP values | |
| * | |
| * @author Dietrich Ayala <dietrich@ganx4.com> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ | |
| * @access public | |
| */ | |
| class soap_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; | |
| 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 soap_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 soap_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('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: no, because this is documented as XML string | |
| // if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ | |
| // $this->responseHeaders = $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 = 'envelope'; | |
| } elseif($name == 'Header'){ | |
| $this->root_header = $pos; | |
| $this->status = 'header'; | |
| } elseif($name == 'Body'){ | |
| $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(ereg('^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'){ | |
| $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(ereg($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($name == 'Body'){ | |
| $this->status = 'envelope'; | |
| } elseif($name == 'Header'){ | |
| $this->status = 'envelope'; | |
| } elseif($name == 'Envelope'){ | |
| // | |
| } | |
| // 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 | |
| * | |
| * @return mixed | |
| * @access public | |
| */ | |
| function get_response(){ | |
| return $this->soapresponse; | |
| } | |
| /** | |
| * get the parsed headers | |
| * | |
| * @return string XML or empty if no headers | |
| * @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 '.$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']; | |
| } | |
| } | |
| } | |
| return is_array($params) ? $params : array(); | |
| } 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'])) { | |
| return $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); | |
| } | |
| $parent = $this->message[$pos]['parent']; | |
| if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { | |
| return $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); | |
| } | |
| return $this->message[$pos]['cdata']; | |
| } | |
| } | |
| } | |
| /** | |
| * | |
| * soapclient higher level class for easy usage. | |
| * | |
| * usage: | |
| * | |
| * // instantiate client with server info | |
| * $soapclient = new soapclient( string path [ ,boolean wsdl] ); | |
| * | |
| * // call method, get results | |
| * echo $soapclient->call( string methodname [ ,array parameters] ); | |
| * | |
| * // bye bye client | |
| * unset($soapclient); | |
| * | |
| * @author Dietrich Ayala <dietrich@ganx4.com> | |
| * @version $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $ | |
| * @access public | |
| */ | |
| class soapclient extends nusoap_base { | |
| var $username = ''; | |
| var $password = ''; | |
| var $authtype = ''; | |
| var $certRequest = array(); | |
| var $requestHeaders = false; // SOAP headers in request (text) | |
| var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) | |
| 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 $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 | |
| /* | |
| * 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 bool $wsdl optional, set to true if using WSDL | |
| * @param int $portName optional portName in WSDL document | |
| * @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 | |
| * @access public | |
| */ | |
| function soapclient($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ | |
| 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; | |
| // 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); | |
| } else { | |
| $this->wsdlFile = $this->endpoint; | |
| // instantiate wsdl object and parse wsdl file | |
| $this->debug('instantiating wsdl class with doc: '.$endpoint); | |
| $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout); | |
| } | |
| $this->appendDebug($this->wsdl->getDebug()); | |
| $this->wsdl->clearDebug(); | |
| // catch errors | |
| if($errstr = $this->wsdl->getError()){ | |
| $this->debug('got wsdl error: '.$errstr); | |
| $this->setError('wsdl error: '.$errstr); | |
| } elseif($this->operations = $this->wsdl->getOperations()){ | |
| $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile); | |
| $this->endpointType = 'wsdl'; | |
| } else { | |
| $this->debug( 'getOperations returned false'); | |
| $this->setError('no operations defined in the WSDL document!'); | |
| } | |
| } else { | |
| $this->debug("instantiate SOAP with endpoint at $endpoint"); | |
| $this->endpointType = 'soap'; | |
| } | |
| } | |
| /** | |
| * calls method, returns PHP native type | |
| * | |
| * @param string $method 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 | |
| * @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 | |
| * @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; | |
| } | |
| // 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); | |
| } 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.'); | |
| $this->debug("operation '$operation' not present."); | |
| 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) { | |
| $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$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 ""; | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * 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(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 ereg('^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); | |
| 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(ereg('^http:',$this->endpoint)){ | |
| //if(strpos($this->endpoint,'http:')){ | |
| $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); | |
| } elseif(ereg('^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) . ' and type ' . $headers['content-type']); | |
| if (!strstr($headers['content-type'], 'text/xml')) { | |
| $this->setError('Response 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)/',$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'); | |
| $parser = new soap_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 decoded message | |
| $return = $parser->get_response(); | |
| // add document for doclit support | |
| $this->document = $parser->document; | |
| // destroy the parser object | |
| unset($parser); | |
| // return decode message | |
| return $return; | |
| } | |
| } | |
| /** | |
| * sets the SOAP endpoint, which can override WSDL | |
| * | |
| * @param $endpoint string The endpoint URL to use, or empty string or false to prevent override | |
| * @access public | |
| */ | |
| function setEndpoint($endpoint) { | |
| $this->forceEndpoint = $endpoint; | |
| } | |
| /** | |
| * set the SOAP headers | |
| * | |
| * @param $headers mixed String of XML with SOAP header content, or array of soapval objects for SOAP headers | |
| * @access public | |
| */ | |
| function setHeaders($headers){ | |
| $this->requestHeaders = $headers; | |
| } | |
| /** | |
| * get the SOAP response headers (namespace resolution incomplete) | |
| * | |
| * @return string | |
| * @access public | |
| */ | |
| function getHeaders(){ | |
| return $this->responseHeaders; | |
| } | |
| /** | |
| * 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) | |
| * @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->username = $username; | |
| $this->password = $password; | |
| $this->authtype = $authtype; | |
| $this->certRequest = $certRequest; | |
| } | |
| /** | |
| * use HTTP encoding | |
| * | |
| * @param string $enc | |
| * @access public | |
| */ | |
| function setHTTPEncoding($enc='gzip, deflate'){ | |
| $this->http_encoding = $enc; | |
| } | |
| /** | |
| * use HTTP persistent connections if possible | |
| * | |
| * @access public | |
| */ | |
| function 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"; | |
| // eval the class | |
| eval($evalStr); | |
| // instantiate proxy object | |
| eval("\$proxy = new soap_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->username = $this->username; | |
| $proxy->password = $this->password; | |
| $proxy->authtype = $this->authtype; | |
| $proxy->proxyhost = $this->proxyhost; | |
| $proxy->proxyport = $this->proxyport; | |
| $proxy->proxyusername = $this->proxyusername; | |
| $proxy->proxypassword = $this->proxypassword; | |
| $proxy->timeout = $this->timeout; | |
| $proxy->response_timeout = $this->response_timeout; | |
| $proxy->http_encoding = $this->http_encoding; | |
| $proxy->persistentConnection = $this->persistentConnection; | |
| $proxy->requestHeaders = $this->requestHeaders; | |
| $proxy->soap_defencoding = $this->soap_defencoding; | |
| $proxy->endpoint = $this->endpoint; | |
| $proxy->forceEndpoint = $this->forceEndpoint; | |
| return $proxy; | |
| } | |
| /** | |
| * dynamically creates proxy class code | |
| * | |
| * @return string PHP/NuSOAP code for the proxy class | |
| * @access private | |
| */ | |
| function _getProxyClassCode($r) { | |
| if ($this->endpointType != 'wsdl') { | |
| $evalStr = 'A proxy can only be created for a WSDL client'; | |
| $this->setError($evalStr); | |
| return $evalStr; | |
| } | |
| $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 = ''; | |
| $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 soap_proxy_'.$r.' extends soapclient { | |
| '.$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 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 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 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; | |
| } | |
| } | |