Test Setup Failed
Push — master ( ec638a...cb9435 )
by Julito
51:10
created

nusoap_base   D

Complexity

Total Complexity 133

Size/Duplication

Total Lines 807
Duplicated Lines 5.08 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
dl 41
loc 807
rs 4.4444
c 0
b 0
f 0
wmc 133
lcom 2
cbo 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like nusoap_base often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use nusoap_base, and based on these observations, apply Extract Interface, too.

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
[email protected]
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 <[email protected]>
81
* @author   Scott Nichol <[email protected]>
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
	/**
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.9.5';
101
	/**
102
	 * CVS revision for HTTP headers.
103
	 *
104
	 * @var string
105
	 * @access private
106
	 */
107
	var $revision = '$Revision: 1.56 $';
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
	public function __construct()
227
    {
228
		$this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
229
	}
230
231
	/**
232
	* gets the global debug level, which applies to future instances
233
	*
234
	* @return	integer	Debug level 0-9, where 0 turns off
235
	* @access	public
236
	*/
237
	function getGlobalDebugLevel() {
238
		return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
239
	}
240
241
	/**
242
	* sets the global debug level, which applies to future instances
243
	*
244
	* @param	int	$level	Debug level 0-9, where 0 turns off
245
	* @access	public
246
	*/
247
	function setGlobalDebugLevel($level) {
248
		$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
249
	}
250
251
	/**
252
	* gets the debug level for this instance
253
	*
254
	* @return	int	Debug level 0-9, where 0 turns off
255
	* @access	public
256
	*/
257
	function getDebugLevel() {
258
		return $this->debugLevel;
259
	}
260
261
	/**
262
	* sets the debug level for this instance
263
	*
264
	* @param	int	$level	Debug level 0-9, where 0 turns off
265
	* @access	public
266
	*/
267
	function setDebugLevel($level) {
268
		$this->debugLevel = $level;
269
	}
270
271
	/**
272
	* adds debug data to the instance debug string with formatting
273
	*
274
	* @param    string $string debug data
275
	* @access   private
276
	*/
277
	function debug($string){
278
		if ($this->debugLevel > 0) {
279
			$this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
280
		}
281
	}
282
283
	/**
284
	* adds debug data to the instance debug string without formatting
285
	*
286
	* @param    string $string debug data
287
	* @access   public
288
	*/
289
	function appendDebug($string){
290
		if ($this->debugLevel > 0) {
291
			// it would be nice to use a memory stream here to use
292
			// memory more efficiently
293
			$this->debug_str .= $string;
294
		}
295
	}
296
297
	/**
298
	* clears the current debug data for this instance
299
	*
300
	* @access   public
301
	*/
302
	function clearDebug() {
303
		// it would be nice to use a memory stream here to use
304
		// memory more efficiently
305
		$this->debug_str = '';
306
	}
307
308
	/**
309
	* gets the current debug data for this instance
310
	*
311
	* @return   debug data
312
	* @access   public
313
	*/
314
	function &getDebug() {
315
		// it would be nice to use a memory stream here to use
316
		// memory more efficiently
317
		return $this->debug_str;
318
	}
319
320
	/**
321
	* gets the current debug data for this instance as an XML comment
322
	* this may change the contents of the debug data
323
	*
324
	* @return   debug data as an XML comment
325
	* @access   public
326
	*/
327
	function &getDebugAsXMLComment() {
328
		// it would be nice to use a memory stream here to use
329
		// memory more efficiently
330
		while (strpos($this->debug_str, '--')) {
331
			$this->debug_str = str_replace('--', '- -', $this->debug_str);
332
		}
333
		$ret = "<!--\n" . $this->debug_str . "\n-->";
334
    	return $ret;
335
	}
336
337
	/**
338
	* expands entities, e.g. changes '<' to '&lt;'.
339
	*
340
	* @param	string	$val	The string in which to expand entities.
341
	* @access	private
342
	*/
343
	function expandEntities($val) {
344
		if ($this->charencoding) {
345
	    	$val = str_replace('&', '&amp;', $val);
346
	    	$val = str_replace("'", '&apos;', $val);
347
	    	$val = str_replace('"', '&quot;', $val);
348
	    	$val = str_replace('<', '&lt;', $val);
349
	    	$val = str_replace('>', '&gt;', $val);
350
	    }
351
	    return $val;
352
	}
353
354
	/**
355
	* returns error string if present
356
	*
357
	* @return   mixed error string or false
358
	* @access   public
359
	*/
360
	function getError(){
361
		if($this->error_str != ''){
362
			return $this->error_str;
363
		}
364
		return false;
365
	}
366
367
	/**
368
	* sets error string
369
	*
370
	* @return   boolean $string error string
371
	* @access   private
372
	*/
373
	function setError($str){
374
		$this->error_str = $str;
375
	}
376
377
	/**
378
	* detect if array is a simple array or a struct (associative array)
379
	*
380
	* @param	mixed	$val	The PHP array
381
	* @return	string	(arraySimple|arrayStruct)
382
	* @access	private
383
	*/
384
	function isArraySimpleOrStruct($val) {
385
        $keyList = array_keys($val);
386
		foreach ($keyList as $keyListValue) {
387
			if (!is_int($keyListValue)) {
388
				return 'arrayStruct';
389
			}
390
		}
391
		return 'arraySimple';
392
	}
393
394
	/**
395
	* serializes PHP values in accordance w/ section 5. Type information is
396
	* not serialized if $use == 'literal'.
397
	*
398
	* @param	mixed	$val	The value to serialize
399
	* @param	string	$name	The name (local part) of the XML element
400
	* @param	string	$type	The XML schema type (local part) for the element
401
	* @param	string	$name_ns	The namespace for the name of the XML element
402
	* @param	string	$type_ns	The namespace for the type of the element
403
	* @param	array	$attributes	The attributes to serialize as name=>value pairs
404
	* @param	string	$use	The WSDL "use" (encoded|literal)
405
	* @param	boolean	$soapval	Whether this is called from soapval.
406
	* @return	string	The serialized element, possibly with child elements
407
    * @access	public
408
	*/
409
	function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
410
		$this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
411
		$this->appendDebug('value=' . $this->varDump($val));
412
		$this->appendDebug('attributes=' . $this->varDump($attributes));
413
414
    	if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
415
    		$this->debug("serialize_val: serialize soapval");
416
        	$xml = $val->serialize($use);
417
			$this->appendDebug($val->getDebug());
418
			$val->clearDebug();
419
			$this->debug("serialize_val of soapval returning $xml");
420
			return $xml;
421
        }
422
		// force valid name if necessary
423
		if (is_numeric($name)) {
424
			$name = '__numeric_' . $name;
425
		} elseif (! $name) {
426
			$name = 'noname';
427
		}
428
		// if name has ns, add ns prefix to name
429
		$xmlns = '';
430
        if($name_ns){
431
			$prefix = 'nu'.rand(1000,9999);
432
			$name = $prefix.':'.$name;
433
			$xmlns .= " xmlns:$prefix=\"$name_ns\"";
434
		}
435
		// if type is prefixed, create type prefix
436
		if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
437
			// need to fix this. shouldn't default to xsd if no ns specified
438
		    // w/o checking against typemap
439
			$type_prefix = 'xsd';
440
		} elseif($type_ns){
441
			$type_prefix = 'ns'.rand(1000,9999);
442
			$xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
443
		}
444
		// serialize attributes if present
445
		$atts = '';
446
		if($attributes){
447
			foreach($attributes as $k => $v){
448
				$atts .= " $k=\"".$this->expandEntities($v).'"';
449
			}
450
		}
451
		// serialize null value
452
		if (is_null($val)) {
453
    		$this->debug("serialize_val: serialize null");
454
			if ($use == 'literal') {
455
				// TODO: depends on minOccurs
456
				$xml = "<$name$xmlns$atts/>";
457
				$this->debug("serialize_val returning $xml");
458
	        	return $xml;
459
        	} else {
460
				if (isset($type) && isset($type_prefix)) {
461
					$type_str = " xsi:type=\"$type_prefix:$type\"";
462
				} else {
463
					$type_str = '';
464
				}
465
				$xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
466
				$this->debug("serialize_val returning $xml");
467
	        	return $xml;
468
        	}
469
		}
470
        // serialize if an xsd built-in primitive type
471
        if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
472
    		$this->debug("serialize_val: serialize xsd built-in primitive type");
473
        	if (is_bool($val)) {
474
        		if ($type == 'boolean') {
475
	        		$val = $val ? 'true' : 'false';
476
	        	} elseif (! $val) {
477
	        		$val = 0;
478
	        	}
479
			} else if (is_string($val)) {
480
				$val = $this->expandEntities($val);
481
			}
482
			if ($use == 'literal') {
483
				$xml = "<$name$xmlns$atts>$val</$name>";
484
				$this->debug("serialize_val returning $xml");
485
	        	return $xml;
486
        	} else {
487
				$xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
488
				$this->debug("serialize_val returning $xml");
489
	        	return $xml;
490
        	}
491
        }
492
		// detect type and serialize
493
		$xml = '';
494
		switch(true) {
495
			case (is_bool($val) || $type == 'boolean'):
496
		   		$this->debug("serialize_val: serialize boolean");
497
        		if ($type == 'boolean') {
498
	        		$val = $val ? 'true' : 'false';
499
	        	} elseif (! $val) {
500
	        		$val = 0;
501
	        	}
502
				if ($use == 'literal') {
503
					$xml .= "<$name$xmlns$atts>$val</$name>";
504
				} else {
505
					$xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
506
				}
507
				break;
508
			case (is_int($val) || is_long($val) || $type == 'int'):
509
		   		$this->debug("serialize_val: serialize int");
510
				if ($use == 'literal') {
511
					$xml .= "<$name$xmlns$atts>$val</$name>";
512
				} else {
513
					$xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
514
				}
515
				break;
516
			case (is_float($val)|| is_double($val) || $type == 'float'):
517
		   		$this->debug("serialize_val: serialize float");
518
				if ($use == 'literal') {
519
					$xml .= "<$name$xmlns$atts>$val</$name>";
520
				} else {
521
					$xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
522
				}
523
				break;
524
			case (is_string($val) || $type == 'string'):
525
		   		$this->debug("serialize_val: serialize string");
526
				$val = $this->expandEntities($val);
527
				if ($use == 'literal') {
528
					$xml .= "<$name$xmlns$atts>$val</$name>";
529
				} else {
530
					$xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
531
				}
532
				break;
533
			case is_object($val):
534
		   		$this->debug("serialize_val: serialize object");
535
		    	if (get_class($val) == 'soapval') {
536
		    		$this->debug("serialize_val: serialize soapval object");
537
		        	$pXml = $val->serialize($use);
538
					$this->appendDebug($val->getDebug());
539
					$val->clearDebug();
540
		        } else {
541
					if (! $name) {
542
						$name = get_class($val);
543
						$this->debug("In serialize_val, used class name $name as element name");
544
					} else {
545
						$this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
546
					}
547
					foreach(get_object_vars($val) as $k => $v){
548
						$pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
549
					}
550
				}
551
				if(isset($type) && isset($type_prefix)){
552
					$type_str = " xsi:type=\"$type_prefix:$type\"";
553
				} else {
554
					$type_str = '';
555
				}
556
				if ($use == 'literal') {
557
					$xml .= "<$name$xmlns$atts>$pXml</$name>";
558
				} else {
559
					$xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
560
				}
561
				break;
562
			case (is_array($val) || $type):
563
				// detect if struct or array
564
				$valueType = $this->isArraySimpleOrStruct($val);
565
                if($valueType=='arraySimple' || preg_match('/^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,':') && !preg_match('/^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    int $timestamp Unix time stamp
901
* @param	boolean $utc Whether the time stamp is UTC or local
902
* @return	mixed ISO 8601 date string or false
903
* @access   public
904
*/
905
function timestamp_to_iso8601($timestamp,$utc=true){
906
	$datestr = date('Y-m-d\TH:i:sO',$timestamp);
907
	$pos = strrpos($datestr, "+");
908
	if ($pos === FALSE) {
909
		$pos = strrpos($datestr, "-");
910
	}
911
	if ($pos !== FALSE) {
912
		if (strlen($datestr) == $pos + 5) {
913
			$datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
914
		}
915
	}
916
	if($utc){
917
		$pattern = '/'.
918
		'([0-9]{4})-'.	// centuries & years CCYY-
919
		'([0-9]{2})-'.	// months MM-
920
		'([0-9]{2})'.	// days DD
921
		'T'.			// separator T
922
		'([0-9]{2}):'.	// hours hh:
923
		'([0-9]{2}):'.	// minutes mm:
924
		'([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
925
		'(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
926
		'/';
927
928
		if(preg_match($pattern,$datestr,$regs)){
929
			return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
930
		}
931
		return false;
932
	} else {
933
		return $datestr;
934
	}
935
}
936
937
/**
938
* convert ISO 8601 compliant date string to unix timestamp
939
*
940
* @param    string $datestr ISO 8601 compliant date string
941
* @return	mixed Unix timestamp (int) or false
942
* @access   public
943
*/
944
function iso8601_to_timestamp($datestr){
945
	$pattern = '/'.
946
	'([0-9]{4})-'.	// centuries & years CCYY-
947
	'([0-9]{2})-'.	// months MM-
948
	'([0-9]{2})'.	// days DD
949
	'T'.			// separator T
950
	'([0-9]{2}):'.	// hours hh:
951
	'([0-9]{2}):'.	// minutes mm:
952
	'([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
953
	'(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
954
	'/';
955
	if(preg_match($pattern,$datestr,$regs)){
956
		// not utc
957
		if($regs[8] != 'Z'){
958
			$op = substr($regs[8],0,1);
959
			$h = substr($regs[8],1,2);
960
			$m = substr($regs[8],strlen($regs[8])-2,2);
961
			if($op == '-'){
962
				$regs[4] = $regs[4] + $h;
963
				$regs[5] = $regs[5] + $m;
964
			} elseif($op == '+'){
965
				$regs[4] = $regs[4] - $h;
966
				$regs[5] = $regs[5] - $m;
967
			}
968
		}
969
		return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
970
//		return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
971
	} else {
972
		return false;
973
	}
974
}
975
976
/**
977
* sleeps some number of microseconds
978
*
979
* @param    string $usec the number of microseconds to sleep
980
* @access   public
981
* @deprecated
982
*/
983
function usleepWindows($usec)
984
{
985
	$start = gettimeofday();
986
987
	do
988
	{
989
		$stop = gettimeofday();
990
		$timePassed = 1000000 * ($stop['sec'] - $start['sec'])
991
		+ $stop['usec'] - $start['usec'];
992
	}
993
	while ($timePassed < $usec);
994
}
995