shop.balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

class.nusoap_base.php (29229B)


      1 <?php
      2 
      3 /*
      4 $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $
      5 
      6 NuSOAP - Web Services Toolkit for PHP
      7 
      8 Copyright (c) 2002 NuSphere Corporation
      9 
     10 This library is free software; you can redistribute it and/or
     11 modify it under the terms of the GNU Lesser General Public
     12 License as published by the Free Software Foundation; either
     13 version 2.1 of the License, or (at your option) any later version.
     14 
     15 This library is distributed in the hope that it will be useful,
     16 but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18 Lesser General Public License for more details.
     19 
     20 You should have received a copy of the GNU Lesser General Public
     21 License along with this library; if not, write to the Free Software
     22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     23 
     24 The NuSOAP project home is:
     25 http://sourceforge.net/projects/nusoap/
     26 
     27 The primary support for NuSOAP is the Help forum on the project home page.
     28 
     29 If you have any questions or comments, please email:
     30 
     31 Dietrich Ayala
     32 dietrich@ganx4.com
     33 http://dietrich.ganx4.com/nusoap
     34 
     35 NuSphere Corporation
     36 http://www.nusphere.com
     37 
     38 */
     39 
     40 /*
     41  *	Some of the standards implmented in whole or part by NuSOAP:
     42  *
     43  *	SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
     44  *	WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
     45  *	SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
     46  *	XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
     47  *	Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
     48  *	XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
     49  *	RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
     50  *	RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
     51  *	RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
     52  */
     53 
     54 /* load classes
     55 
     56 // necessary classes
     57 require_once('class.soapclient.php');
     58 require_once('class.soap_val.php');
     59 require_once('class.soap_parser.php');
     60 require_once('class.soap_fault.php');
     61 
     62 // transport classes
     63 require_once('class.soap_transport_http.php');
     64 
     65 // optional add-on classes
     66 require_once('class.xmlschema.php');
     67 require_once('class.wsdl.php');
     68 
     69 // server class
     70 require_once('class.soap_server.php');*/
     71 
     72 // class variable emulation
     73 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
     74 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
     75 
     76 /**
     77 *
     78 * nusoap_base
     79 *
     80 * @author   Dietrich Ayala <dietrich@ganx4.com>
     81 * @author   Scott Nichol <snichol@users.sourceforge.net>
     82 * @version  $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $
     83 * @access   public
     84 */
     85 class nusoap_base {
     86 	/**
     87 	 * Identification for HTTP headers.
     88 	 *
     89 	 * @var string
     90 	 * @access private
     91 	 */
     92 	var $title = 'NuSOAP';
     93 	/**
     94 	 * Version for HTTP headers.
     95 	 *
     96 	 * @var string
     97 	 * @access private
     98 	 */
     99 	var $version = '0.9.5';
    100 	/**
    101 	 * CVS revision for HTTP headers.
    102 	 *
    103 	 * @var string
    104 	 * @access private
    105 	 */
    106 	var $revision = '$Revision: 1.56 $';
    107     /**
    108      * Current error string (manipulated by getError/setError)
    109 	 *
    110 	 * @var string
    111 	 * @access private
    112 	 */
    113 	var $error_str = '';
    114     /**
    115      * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
    116 	 *
    117 	 * @var string
    118 	 * @access private
    119 	 */
    120     var $debug_str = '';
    121     /**
    122 	 * toggles automatic encoding of special characters as entities
    123 	 * (should always be true, I think)
    124 	 *
    125 	 * @var boolean
    126 	 * @access private
    127 	 */
    128 	var $charencoding = true;
    129 	/**
    130 	 * the debug level for this instance
    131 	 *
    132 	 * @var	integer
    133 	 * @access private
    134 	 */
    135 	var $debugLevel;
    136 
    137     /**
    138 	* set schema version
    139 	*
    140 	* @var      string
    141 	* @access   public
    142 	*/
    143 	var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
    144 	
    145     /**
    146 	* charset encoding for outgoing messages
    147 	*
    148 	* @var      string
    149 	* @access   public
    150 	*/
    151     var $soap_defencoding = 'ISO-8859-1';
    152 	//var $soap_defencoding = 'UTF-8';
    153 
    154 	/**
    155 	* namespaces in an array of prefix => uri
    156 	*
    157 	* this is "seeded" by a set of constants, but it may be altered by code
    158 	*
    159 	* @var      array
    160 	* @access   public
    161 	*/
    162 	var $namespaces = array(
    163 		'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
    164 		'xsd' => 'http://www.w3.org/2001/XMLSchema',
    165 		'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
    166 		'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
    167 		);
    168 
    169 	/**
    170 	* namespaces used in the current context, e.g. during serialization
    171 	*
    172 	* @var      array
    173 	* @access   private
    174 	*/
    175 	var $usedNamespaces = array();
    176 
    177 	/**
    178 	* XML Schema types in an array of uri => (array of xml type => php type)
    179 	* is this legacy yet?
    180 	* no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
    181 	* @var      array
    182 	* @access   public
    183 	*/
    184 	var $typemap = array(
    185 	'http://www.w3.org/2001/XMLSchema' => array(
    186 		'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
    187 		'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
    188 		'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
    189 		// abstract "any" types
    190 		'anyType'=>'string','anySimpleType'=>'string',
    191 		// derived datatypes
    192 		'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
    193 		'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
    194 		'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
    195 		'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
    196 	'http://www.w3.org/2000/10/XMLSchema' => array(
    197 		'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
    198 		'float'=>'double','dateTime'=>'string',
    199 		'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
    200 	'http://www.w3.org/1999/XMLSchema' => array(
    201 		'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
    202 		'float'=>'double','dateTime'=>'string',
    203 		'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
    204 	'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
    205 	'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
    206     'http://xml.apache.org/xml-soap' => array('Map')
    207 	);
    208 
    209 	/**
    210 	* XML entities to convert
    211 	*
    212 	* @var      array
    213 	* @access   public
    214 	* @deprecated
    215 	* @see	expandEntities
    216 	*/
    217 	var $xmlEntities = array('quot' => '"','amp' => '&',
    218 		'lt' => '<','gt' => '>','apos' => "'");
    219 
    220 	/**
    221 	* constructor
    222 	*
    223 	* @access	public
    224 	*/
    225 	function nusoap_base() {
    226 		$this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
    227 	}
    228 
    229 	/**
    230 	* gets the global debug level, which applies to future instances
    231 	*
    232 	* @return	integer	Debug level 0-9, where 0 turns off
    233 	* @access	public
    234 	*/
    235 	function getGlobalDebugLevel() {
    236 		return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
    237 	}
    238 
    239 	/**
    240 	* sets the global debug level, which applies to future instances
    241 	*
    242 	* @param	int	$level	Debug level 0-9, where 0 turns off
    243 	* @access	public
    244 	*/
    245 	function setGlobalDebugLevel($level) {
    246 		$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
    247 	}
    248 
    249 	/**
    250 	* gets the debug level for this instance
    251 	*
    252 	* @return	int	Debug level 0-9, where 0 turns off
    253 	* @access	public
    254 	*/
    255 	function getDebugLevel() {
    256 		return $this->debugLevel;
    257 	}
    258 
    259 	/**
    260 	* sets the debug level for this instance
    261 	*
    262 	* @param	int	$level	Debug level 0-9, where 0 turns off
    263 	* @access	public
    264 	*/
    265 	function setDebugLevel($level) {
    266 		$this->debugLevel = $level;
    267 	}
    268 
    269 	/**
    270 	* adds debug data to the instance debug string with formatting
    271 	*
    272 	* @param    string $string debug data
    273 	* @access   private
    274 	*/
    275 	function debug($string){
    276 		if ($this->debugLevel > 0) {
    277 			$this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
    278 		}
    279 	}
    280 
    281 	/**
    282 	* adds debug data to the instance debug string without formatting
    283 	*
    284 	* @param    string $string debug data
    285 	* @access   public
    286 	*/
    287 	function appendDebug($string){
    288 		if ($this->debugLevel > 0) {
    289 			// it would be nice to use a memory stream here to use
    290 			// memory more efficiently
    291 			$this->debug_str .= $string;
    292 		}
    293 	}
    294 
    295 	/**
    296 	* clears the current debug data for this instance
    297 	*
    298 	* @access   public
    299 	*/
    300 	function clearDebug() {
    301 		// it would be nice to use a memory stream here to use
    302 		// memory more efficiently
    303 		$this->debug_str = '';
    304 	}
    305 
    306 	/**
    307 	* gets the current debug data for this instance
    308 	*
    309 	* @return   debug data
    310 	* @access   public
    311 	*/
    312 	function &getDebug() {
    313 		// it would be nice to use a memory stream here to use
    314 		// memory more efficiently
    315 		return $this->debug_str;
    316 	}
    317 
    318 	/**
    319 	* gets the current debug data for this instance as an XML comment
    320 	* this may change the contents of the debug data
    321 	*
    322 	* @return   debug data as an XML comment
    323 	* @access   public
    324 	*/
    325 	function &getDebugAsXMLComment() {
    326 		// it would be nice to use a memory stream here to use
    327 		// memory more efficiently
    328 		while (strpos($this->debug_str, '--')) {
    329 			$this->debug_str = str_replace('--', '- -', $this->debug_str);
    330 		}
    331 		$ret = "<!--\n" . $this->debug_str . "\n-->";
    332     	return $ret;
    333 	}
    334 
    335 	/**
    336 	* expands entities, e.g. changes '<' to '&lt;'.
    337 	*
    338 	* @param	string	$val	The string in which to expand entities.
    339 	* @access	private
    340 	*/
    341 	function expandEntities($val) {
    342 		if ($this->charencoding) {
    343 	    	$val = str_replace('&', '&amp;', $val);
    344 	    	$val = str_replace("'", '&apos;', $val);
    345 	    	$val = str_replace('"', '&quot;', $val);
    346 	    	$val = str_replace('<', '&lt;', $val);
    347 	    	$val = str_replace('>', '&gt;', $val);
    348 	    }
    349 	    return $val;
    350 	}
    351 
    352 	/**
    353 	* returns error string if present
    354 	*
    355 	* @return   mixed error string or false
    356 	* @access   public
    357 	*/
    358 	function getError(){
    359 		if($this->error_str != ''){
    360 			return $this->error_str;
    361 		}
    362 		return false;
    363 	}
    364 
    365 	/**
    366 	* sets error string
    367 	*
    368 	* @return   boolean $string error string
    369 	* @access   private
    370 	*/
    371 	function setError($str){
    372 		$this->error_str = $str;
    373 	}
    374 
    375 	/**
    376 	* detect if array is a simple array or a struct (associative array)
    377 	*
    378 	* @param	mixed	$val	The PHP array
    379 	* @return	string	(arraySimple|arrayStruct)
    380 	* @access	private
    381 	*/
    382 	function isArraySimpleOrStruct($val) {
    383         $keyList = array_keys($val);
    384 		foreach ($keyList as $keyListValue) {
    385 			if (!is_int($keyListValue)) {
    386 				return 'arrayStruct';
    387 			}
    388 		}
    389 		return 'arraySimple';
    390 	}
    391 
    392 	/**
    393 	* serializes PHP values in accordance w/ section 5. Type information is
    394 	* not serialized if $use == 'literal'.
    395 	*
    396 	* @param	mixed	$val	The value to serialize
    397 	* @param	string	$name	The name (local part) of the XML element
    398 	* @param	string	$type	The XML schema type (local part) for the element
    399 	* @param	string	$name_ns	The namespace for the name of the XML element
    400 	* @param	string	$type_ns	The namespace for the type of the element
    401 	* @param	array	$attributes	The attributes to serialize as name=>value pairs
    402 	* @param	string	$use	The WSDL "use" (encoded|literal)
    403 	* @param	boolean	$soapval	Whether this is called from soapval.
    404 	* @return	string	The serialized element, possibly with child elements
    405     * @access	public
    406 	*/
    407 	function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
    408 		$this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
    409 		$this->appendDebug('value=' . $this->varDump($val));
    410 		$this->appendDebug('attributes=' . $this->varDump($attributes));
    411 		
    412     	if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
    413     		$this->debug("serialize_val: serialize soapval");
    414         	$xml = $val->serialize($use);
    415 			$this->appendDebug($val->getDebug());
    416 			$val->clearDebug();
    417 			$this->debug("serialize_val of soapval returning $xml");
    418 			return $xml;
    419         }
    420 		// force valid name if necessary
    421 		if (is_numeric($name)) {
    422 			$name = '__numeric_' . $name;
    423 		} elseif (! $name) {
    424 			$name = 'noname';
    425 		}
    426 		// if name has ns, add ns prefix to name
    427 		$xmlns = '';
    428         if($name_ns){
    429 			$prefix = 'nu'.rand(1000,9999);
    430 			$name = $prefix.':'.$name;
    431 			$xmlns .= " xmlns:$prefix=\"$name_ns\"";
    432 		}
    433 		// if type is prefixed, create type prefix
    434 		if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
    435 			// need to fix this. shouldn't default to xsd if no ns specified
    436 		    // w/o checking against typemap
    437 			$type_prefix = 'xsd';
    438 		} elseif($type_ns){
    439 			$type_prefix = 'ns'.rand(1000,9999);
    440 			$xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
    441 		}
    442 		// serialize attributes if present
    443 		$atts = '';
    444 		if($attributes){
    445 			foreach($attributes as $k => $v){
    446 				$atts .= " $k=\"".$this->expandEntities($v).'"';
    447 			}
    448 		}
    449 		// serialize null value
    450 		if (is_null($val)) {
    451     		$this->debug("serialize_val: serialize null");
    452 			if ($use == 'literal') {
    453 				// TODO: depends on minOccurs
    454 				$xml = "<$name$xmlns$atts/>";
    455 				$this->debug("serialize_val returning $xml");
    456 	        	return $xml;
    457         	} else {
    458 				if (isset($type) && isset($type_prefix)) {
    459 					$type_str = " xsi:type=\"$type_prefix:$type\"";
    460 				} else {
    461 					$type_str = '';
    462 				}
    463 				$xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
    464 				$this->debug("serialize_val returning $xml");
    465 	        	return $xml;
    466         	}
    467 		}
    468         // serialize if an xsd built-in primitive type
    469         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
    470     		$this->debug("serialize_val: serialize xsd built-in primitive type");
    471         	if (is_bool($val)) {
    472         		if ($type == 'boolean') {
    473 	        		$val = $val ? 'true' : 'false';
    474 	        	} elseif (! $val) {
    475 	        		$val = 0;
    476 	        	}
    477 			} else if (is_string($val)) {
    478 				$val = $this->expandEntities($val);
    479 			}
    480 			if ($use == 'literal') {
    481 				$xml = "<$name$xmlns$atts>$val</$name>";
    482 				$this->debug("serialize_val returning $xml");
    483 	        	return $xml;
    484         	} else {
    485 				$xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
    486 				$this->debug("serialize_val returning $xml");
    487 	        	return $xml;
    488         	}
    489         }
    490 		// detect type and serialize
    491 		$xml = '';
    492 		switch(true) {
    493 			case (is_bool($val) || $type == 'boolean'):
    494 		   		$this->debug("serialize_val: serialize boolean");
    495         		if ($type == 'boolean') {
    496 	        		$val = $val ? 'true' : 'false';
    497 	        	} elseif (! $val) {
    498 	        		$val = 0;
    499 	        	}
    500 				if ($use == 'literal') {
    501 					$xml .= "<$name$xmlns$atts>$val</$name>";
    502 				} else {
    503 					$xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
    504 				}
    505 				break;
    506 			case (is_int($val) || is_long($val) || $type == 'int'):
    507 		   		$this->debug("serialize_val: serialize int");
    508 				if ($use == 'literal') {
    509 					$xml .= "<$name$xmlns$atts>$val</$name>";
    510 				} else {
    511 					$xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
    512 				}
    513 				break;
    514 			case (is_float($val)|| is_double($val) || $type == 'float'):
    515 		   		$this->debug("serialize_val: serialize float");
    516 				if ($use == 'literal') {
    517 					$xml .= "<$name$xmlns$atts>$val</$name>";
    518 				} else {
    519 					$xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
    520 				}
    521 				break;
    522 			case (is_string($val) || $type == 'string'):
    523 		   		$this->debug("serialize_val: serialize string");
    524 				$val = $this->expandEntities($val);
    525 				if ($use == 'literal') {
    526 					$xml .= "<$name$xmlns$atts>$val</$name>";
    527 				} else {
    528 					$xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
    529 				}
    530 				break;
    531 			case is_object($val):
    532 		   		$this->debug("serialize_val: serialize object");
    533 		    	if (get_class($val) == 'soapval') {
    534 		    		$this->debug("serialize_val: serialize soapval object");
    535 		        	$pXml = $val->serialize($use);
    536 					$this->appendDebug($val->getDebug());
    537 					$val->clearDebug();
    538 		        } else {
    539 					if (! $name) {
    540 						$name = get_class($val);
    541 						$this->debug("In serialize_val, used class name $name as element name");
    542 					} else {
    543 						$this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
    544 					}
    545 					foreach(get_object_vars($val) as $k => $v){
    546 						$pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
    547 					}
    548 				}
    549 				if(isset($type) && isset($type_prefix)){
    550 					$type_str = " xsi:type=\"$type_prefix:$type\"";
    551 				} else {
    552 					$type_str = '';
    553 				}
    554 				if ($use == 'literal') {
    555 					$xml .= "<$name$xmlns$atts>$pXml</$name>";
    556 				} else {
    557 					$xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
    558 				}
    559 				break;
    560 			break;
    561 			case (is_array($val) || $type):
    562 				// detect if struct or array
    563 				$valueType = $this->isArraySimpleOrStruct($val);
    564                 if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){
    565 			   		$this->debug("serialize_val: serialize array");
    566 					$i = 0;
    567 					if(is_array($val) && count($val)> 0){
    568 						foreach($val as $v){
    569 	                    	if(is_object($v) && get_class($v) ==  'soapval'){
    570 								$tt_ns = $v->type_ns;
    571 								$tt = $v->type;
    572 							} elseif (is_array($v)) {
    573 								$tt = $this->isArraySimpleOrStruct($v);
    574 							} else {
    575 								$tt = gettype($v);
    576 	                        }
    577 							$array_types[$tt] = 1;
    578 							// TODO: for literal, the name should be $name
    579 							$xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
    580 							++$i;
    581 						}
    582 						if(count($array_types) > 1){
    583 							$array_typename = 'xsd:anyType';
    584 						} elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
    585 							if ($tt == 'integer') {
    586 								$tt = 'int';
    587 							}
    588 							$array_typename = 'xsd:'.$tt;
    589 						} elseif(isset($tt) && $tt == 'arraySimple'){
    590 							$array_typename = 'SOAP-ENC:Array';
    591 						} elseif(isset($tt) && $tt == 'arrayStruct'){
    592 							$array_typename = 'unnamed_struct_use_soapval';
    593 						} else {
    594 							// if type is prefixed, create type prefix
    595 							if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
    596 								 $array_typename = 'xsd:' . $tt;
    597 							} elseif ($tt_ns) {
    598 								$tt_prefix = 'ns' . rand(1000, 9999);
    599 								$array_typename = "$tt_prefix:$tt";
    600 								$xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
    601 							} else {
    602 								$array_typename = $tt;
    603 							}
    604 						}
    605 						$array_type = $i;
    606 						if ($use == 'literal') {
    607 							$type_str = '';
    608 						} else if (isset($type) && isset($type_prefix)) {
    609 							$type_str = " xsi:type=\"$type_prefix:$type\"";
    610 						} else {
    611 							$type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
    612 						}
    613 					// empty array
    614 					} else {
    615 						if ($use == 'literal') {
    616 							$type_str = '';
    617 						} else if (isset($type) && isset($type_prefix)) {
    618 							$type_str = " xsi:type=\"$type_prefix:$type\"";
    619 						} else {
    620 							$type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
    621 						}
    622 					}
    623 					// TODO: for array in literal, there is no wrapper here
    624 					$xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
    625 				} else {
    626 					// got a struct
    627 			   		$this->debug("serialize_val: serialize struct");
    628 					if(isset($type) && isset($type_prefix)){
    629 						$type_str = " xsi:type=\"$type_prefix:$type\"";
    630 					} else {
    631 						$type_str = '';
    632 					}
    633 					if ($use == 'literal') {
    634 						$xml .= "<$name$xmlns$atts>";
    635 					} else {
    636 						$xml .= "<$name$xmlns$type_str$atts>";
    637 					}
    638 					foreach($val as $k => $v){
    639 						// Apache Map
    640 						if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
    641 							$xml .= '<item>';
    642 							$xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
    643 							$xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
    644 							$xml .= '</item>';
    645 						} else {
    646 							$xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
    647 						}
    648 					}
    649 					$xml .= "</$name>";
    650 				}
    651 				break;
    652 			default:
    653 		   		$this->debug("serialize_val: serialize unknown");
    654 				$xml .= 'not detected, got '.gettype($val).' for '.$val;
    655 				break;
    656 		}
    657 		$this->debug("serialize_val returning $xml");
    658 		return $xml;
    659 	}
    660 
    661     /**
    662     * serializes a message
    663     *
    664     * @param string $body the XML of the SOAP body
    665     * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
    666     * @param array $namespaces optional the namespaces used in generating the body and headers
    667     * @param string $style optional (rpc|document)
    668     * @param string $use optional (encoded|literal)
    669     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
    670     * @return string the message
    671     * @access public
    672     */
    673     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
    674     // TODO: add an option to automatically run utf8_encode on $body and $headers
    675     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
    676     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
    677 
    678 	$this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
    679 	$this->debug("headers:");
    680 	$this->appendDebug($this->varDump($headers));
    681 	$this->debug("namespaces:");
    682 	$this->appendDebug($this->varDump($namespaces));
    683 
    684 	// serialize namespaces
    685     $ns_string = '';
    686 	foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
    687 		$ns_string .= " xmlns:$k=\"$v\"";
    688 	}
    689 	if($encodingStyle) {
    690 		$ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
    691 	}
    692 
    693 	// serialize headers
    694 	if($headers){
    695 		if (is_array($headers)) {
    696 			$xml = '';
    697 			foreach ($headers as $k => $v) {
    698 				if (is_object($v) && get_class($v) == 'soapval') {
    699 					$xml .= $this->serialize_val($v, false, false, false, false, false, $use);
    700 				} else {
    701 					$xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
    702 				}
    703 			}
    704 			$headers = $xml;
    705 			$this->debug("In serializeEnvelope, serialized array of headers to $headers");
    706 		}
    707 		$headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
    708 	}
    709 	// serialize envelope
    710 	return
    711 	'<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
    712 	'<SOAP-ENV:Envelope'.$ns_string.">".
    713 	$headers.
    714 	"<SOAP-ENV:Body>".
    715 		$body.
    716 	"</SOAP-ENV:Body>".
    717 	"</SOAP-ENV:Envelope>";
    718     }
    719 
    720 	/**
    721 	 * formats a string to be inserted into an HTML stream
    722 	 *
    723 	 * @param string $str The string to format
    724 	 * @return string The formatted string
    725 	 * @access public
    726 	 * @deprecated
    727 	 */
    728     function formatDump($str){
    729 		$str = htmlspecialchars($str);
    730 		return nl2br($str);
    731     }
    732 
    733 	/**
    734 	* contracts (changes namespace to prefix) a qualified name
    735 	*
    736 	* @param    string $qname qname
    737 	* @return	string contracted qname
    738 	* @access   private
    739 	*/
    740 	function contractQname($qname){
    741 		// get element namespace
    742 		//$this->xdebug("Contract $qname");
    743 		if (strrpos($qname, ':')) {
    744 			// get unqualified name
    745 			$name = substr($qname, strrpos($qname, ':') + 1);
    746 			// get ns
    747 			$ns = substr($qname, 0, strrpos($qname, ':'));
    748 			$p = $this->getPrefixFromNamespace($ns);
    749 			if ($p) {
    750 				return $p . ':' . $name;
    751 			}
    752 			return $qname;
    753 		} else {
    754 			return $qname;
    755 		}
    756 	}
    757 
    758 	/**
    759 	* expands (changes prefix to namespace) a qualified name
    760 	*
    761 	* @param    string $qname qname
    762 	* @return	string expanded qname
    763 	* @access   private
    764 	*/
    765 	function expandQname($qname){
    766 		// get element prefix
    767 		if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){
    768 			// get unqualified name
    769 			$name = substr(strstr($qname,':'),1);
    770 			// get ns prefix
    771 			$prefix = substr($qname,0,strpos($qname,':'));
    772 			if(isset($this->namespaces[$prefix])){
    773 				return $this->namespaces[$prefix].':'.$name;
    774 			} else {
    775 				return $qname;
    776 			}
    777 		} else {
    778 			return $qname;
    779 		}
    780 	}
    781 
    782     /**
    783     * returns the local part of a prefixed string
    784     * returns the original string, if not prefixed
    785     *
    786     * @param string $str The prefixed string
    787     * @return string The local part
    788     * @access public
    789     */
    790 	function getLocalPart($str){
    791 		if($sstr = strrchr($str,':')){
    792 			// get unqualified name
    793 			return substr( $sstr, 1 );
    794 		} else {
    795 			return $str;
    796 		}
    797 	}
    798 
    799 	/**
    800     * returns the prefix part of a prefixed string
    801     * returns false, if not prefixed
    802     *
    803     * @param string $str The prefixed string
    804     * @return mixed The prefix or false if there is no prefix
    805     * @access public
    806     */
    807 	function getPrefix($str){
    808 		if($pos = strrpos($str,':')){
    809 			// get prefix
    810 			return substr($str,0,$pos);
    811 		}
    812 		return false;
    813 	}
    814 
    815 	/**
    816     * pass it a prefix, it returns a namespace
    817     *
    818     * @param string $prefix The prefix
    819     * @return mixed The namespace, false if no namespace has the specified prefix
    820     * @access public
    821     */
    822 	function getNamespaceFromPrefix($prefix){
    823 		if (isset($this->namespaces[$prefix])) {
    824 			return $this->namespaces[$prefix];
    825 		}
    826 		//$this->setError("No namespace registered for prefix '$prefix'");
    827 		return false;
    828 	}
    829 
    830 	/**
    831     * returns the prefix for a given namespace (or prefix)
    832     * or false if no prefixes registered for the given namespace
    833     *
    834     * @param string $ns The namespace
    835     * @return mixed The prefix, false if the namespace has no prefixes
    836     * @access public
    837     */
    838 	function getPrefixFromNamespace($ns) {
    839 		foreach ($this->namespaces as $p => $n) {
    840 			if ($ns == $n || $ns == $p) {
    841 			    $this->usedNamespaces[$p] = $n;
    842 				return $p;
    843 			}
    844 		}
    845 		return false;
    846 	}
    847 
    848 	/**
    849     * returns the time in ODBC canonical form with microseconds
    850     *
    851     * @return string The time in ODBC canonical form with microseconds
    852     * @access public
    853     */
    854 	function getmicrotime() {
    855 		if (function_exists('gettimeofday')) {
    856 			$tod = gettimeofday();
    857 			$sec = $tod['sec'];
    858 			$usec = $tod['usec'];
    859 		} else {
    860 			$sec = time();
    861 			$usec = 0;
    862 		}
    863 		return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
    864 	}
    865 
    866 	/**
    867 	 * Returns a string with the output of var_dump
    868 	 *
    869 	 * @param mixed $data The variable to var_dump
    870 	 * @return string The output of var_dump
    871 	 * @access public
    872 	 */
    873     function varDump($data) {
    874 		ob_start();
    875 		var_dump($data);
    876 		$ret_val = ob_get_contents();
    877 		ob_end_clean();
    878 		return $ret_val;
    879 	}
    880 
    881 	/**
    882 	* represents the object as a string
    883 	*
    884 	* @return	string
    885 	* @access   public
    886 	*/
    887 	function __toString() {
    888 		return $this->varDump($this);
    889 	}
    890 }
    891 
    892 // XML Schema Datatype Helper Functions
    893 
    894 //xsd:dateTime helpers
    895 
    896 /**
    897 * convert unix timestamp to ISO 8601 compliant date string
    898 *
    899 * @param    int $timestamp Unix time stamp
    900 * @param	boolean $utc Whether the time stamp is UTC or local
    901 * @return	mixed ISO 8601 date string or false
    902 * @access   public
    903 */
    904 function timestamp_to_iso8601($timestamp,$utc=true){
    905 	$datestr = date('Y-m-d\TH:i:sO',$timestamp);
    906 	$pos = strrpos($datestr, "+");
    907 	if ($pos === FALSE) {
    908 		$pos = strrpos($datestr, "-");
    909 	}
    910 	if ($pos !== FALSE) {
    911 		if (strlen($datestr) == $pos + 5) {
    912 			$datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
    913 		}
    914 	}
    915 	if($utc){
    916 		$pattern = '/'.
    917 		'([0-9]{4})-'.	// centuries & years CCYY-
    918 		'([0-9]{2})-'.	// months MM-
    919 		'([0-9]{2})'.	// days DD
    920 		'T'.			// separator T
    921 		'([0-9]{2}):'.	// hours hh:
    922 		'([0-9]{2}):'.	// minutes mm:
    923 		'([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
    924 		'(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
    925 		'/';
    926 
    927 		if(preg_match($pattern,$datestr,$regs)){
    928 			return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
    929 		}
    930 		return false;
    931 	} else {
    932 		return $datestr;
    933 	}
    934 }
    935 
    936 /**
    937 * convert ISO 8601 compliant date string to unix timestamp
    938 *
    939 * @param    string $datestr ISO 8601 compliant date string
    940 * @return	mixed Unix timestamp (int) or false
    941 * @access   public
    942 */
    943 function iso8601_to_timestamp($datestr){
    944 	$pattern = '/'.
    945 	'([0-9]{4})-'.	// centuries & years CCYY-
    946 	'([0-9]{2})-'.	// months MM-
    947 	'([0-9]{2})'.	// days DD
    948 	'T'.			// separator T
    949 	'([0-9]{2}):'.	// hours hh:
    950 	'([0-9]{2}):'.	// minutes mm:
    951 	'([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
    952 	'(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
    953 	'/';
    954 	if(preg_match($pattern,$datestr,$regs)){
    955 		// not utc
    956 		if($regs[8] != 'Z'){
    957 			$op = substr($regs[8],0,1);
    958 			$h = substr($regs[8],1,2);
    959 			$m = substr($regs[8],strlen($regs[8])-2,2);
    960 			if($op == '-'){
    961 				$regs[4] = $regs[4] + $h;
    962 				$regs[5] = $regs[5] + $m;
    963 			} elseif($op == '+'){
    964 				$regs[4] = $regs[4] - $h;
    965 				$regs[5] = $regs[5] - $m;
    966 			}
    967 		}
    968 		return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
    969 //		return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
    970 	} else {
    971 		return false;
    972 	}
    973 }
    974 
    975 /**
    976 * sleeps some number of microseconds
    977 *
    978 * @param    string $usec the number of microseconds to sleep
    979 * @access   public
    980 * @deprecated
    981 */
    982 function usleepWindows($usec)
    983 {
    984 	$start = gettimeofday();
    985 	
    986 	do
    987 	{
    988 		$stop = gettimeofday();
    989 		$timePassed = 1000000 * ($stop['sec'] - $start['sec'])
    990 		+ $stop['usec'] - $start['usec'];
    991 	}
    992 	while ($timePassed < $usec);
    993 }
    994 
    995 
    996 ?>