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