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