changed git call from https to git readonly
[atutor.git] / mods / openmeetings / lib / nusoap.php
1 <?php\r
2 \r
3 /*\r
4 $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
5 \r
6 NuSOAP - Web Services Toolkit for PHP\r
7 \r
8 Copyright (c) 2002 NuSphere Corporation\r
9 \r
10 This library is free software; you can redistribute it and/or\r
11 modify it under the terms of the GNU Lesser General Public\r
12 License as published by the Free Software Foundation; either\r
13 version 2.1 of the License, or (at your option) any later version.\r
14 \r
15 This library is distributed in the hope that it will be useful,\r
16 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
18 Lesser General Public License for more details.\r
19 \r
20 You should have received a copy of the GNU Lesser General Public\r
21 License along with this library; if not, write to the Free Software\r
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
23 \r
24 The NuSOAP project home is:\r
25 http://sourceforge.net/projects/nusoap/\r
26 \r
27 The primary support for NuSOAP is the mailing list:\r
28 nusoap-general@lists.sourceforge.net\r
29 \r
30 If you have any questions or comments, please email:\r
31 \r
32 Dietrich Ayala\r
33 dietrich@ganx4.com\r
34 http://dietrich.ganx4.com/nusoap\r
35 \r
36 NuSphere Corporation\r
37 http://www.nusphere.com\r
38 \r
39 */\r
40 \r
41 /*\r
42  *      Some of the standards implmented in whole or part by NuSOAP:\r
43  *\r
44  *      SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)\r
45  *      WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)\r
46  *      SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)\r
47  *      XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)\r
48  *      Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)\r
49  *      XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)\r
50  *      RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies\r
51  *      RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1\r
52  *      RFC 2617 HTTP Authentication: Basic and Digest Access Authentication\r
53  */\r
54  \r
55 /*\r
56  * \r
57  * This is a modified version of nusoap for usage of Axis2\r
58  * for some reason it does not marshall the SOAP Body correct for Axis2 on Linux Platforms\r
59  * \r
60  */\r
61 \r
62 /* load classes\r
63 \r
64 // necessary classes\r
65 require_once('class.soapclient.php');\r
66 require_once('class.soap_val.php');\r
67 require_once('class.soap_parser.php');\r
68 require_once('class.soap_fault.php');\r
69 \r
70 // transport classes\r
71 require_once('class.soap_transport_http.php');\r
72 \r
73 // optional add-on classes\r
74 require_once('class.xmlschema.php');\r
75 require_once('class.wsdl.php');\r
76 \r
77 // server class\r
78 require_once('class.soap_server.php');*/\r
79 \r
80 // class variable emulation\r
81 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html\r
82 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;\r
83 \r
84 /**\r
85 *\r
86 * nusoap_base\r
87 *\r
88 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
89 * @author   Scott Nichol <snichol@users.sourceforge.net>\r
90 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
91 * @access   public\r
92 */\r
93 class nusoap_base {\r
94         /**\r
95          * Identification for HTTP headers.\r
96          *\r
97          * @var string\r
98          * @access private\r
99          */\r
100         var $title = 'NuSOAP';\r
101         /**\r
102          * Version for HTTP headers.\r
103          *\r
104          * @var string\r
105          * @access private\r
106          */\r
107         var $version = '0.7.3';\r
108         /**\r
109          * CVS revision for HTTP headers.\r
110          *\r
111          * @var string\r
112          * @access private\r
113          */\r
114         var $revision = '$Revision: 1.114 $';\r
115     /**\r
116      * Current error string (manipulated by getError/setError)\r
117          *\r
118          * @var string\r
119          * @access private\r
120          */\r
121         var $error_str = '';\r
122     /**\r
123      * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)\r
124          *\r
125          * @var string\r
126          * @access private\r
127          */\r
128     var $debug_str = '';\r
129     /**\r
130          * toggles automatic encoding of special characters as entities\r
131          * (should always be true, I think)\r
132          *\r
133          * @var boolean\r
134          * @access private\r
135          */\r
136         var $charencoding = true;\r
137         /**\r
138          * the debug level for this instance\r
139          *\r
140          * @var integer\r
141          * @access private\r
142          */\r
143         var $debugLevel;\r
144 \r
145     /**\r
146         * set schema version\r
147         *\r
148         * @var      string\r
149         * @access   public\r
150         */\r
151         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';\r
152         \r
153     /**\r
154         * charset encoding for outgoing messages\r
155         *\r
156         * @var      string\r
157         * @access   public\r
158         */\r
159     var $soap_defencoding = 'ISO-8859-1';\r
160         //var $soap_defencoding = 'UTF-8';\r
161 \r
162         /**\r
163         * namespaces in an array of prefix => uri\r
164         *\r
165         * this is "seeded" by a set of constants, but it may be altered by code\r
166         *\r
167         * @var      array\r
168         * @access   public\r
169         */\r
170         var $namespaces = array(\r
171                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',\r
172                 'xsd' => 'http://www.w3.org/2001/XMLSchema',\r
173                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',\r
174                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'\r
175                 );\r
176 \r
177         /**\r
178         * namespaces used in the current context, e.g. during serialization\r
179         *\r
180         * @var      array\r
181         * @access   private\r
182         */\r
183         var $usedNamespaces = array();\r
184 \r
185         /**\r
186         * XML Schema types in an array of uri => (array of xml type => php type)\r
187         * is this legacy yet?\r
188         * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.\r
189         * @var      array\r
190         * @access   public\r
191         */\r
192         var $typemap = array(\r
193         'http://www.w3.org/2001/XMLSchema' => array(\r
194                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',\r
195                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',\r
196                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',\r
197                 // abstract "any" types\r
198                 'anyType'=>'string','anySimpleType'=>'string',\r
199                 // derived datatypes\r
200                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',\r
201                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',\r
202                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',\r
203                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),\r
204         'http://www.w3.org/2000/10/XMLSchema' => array(\r
205                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',\r
206                 'float'=>'double','dateTime'=>'string',\r
207                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),\r
208         'http://www.w3.org/1999/XMLSchema' => array(\r
209                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',\r
210                 'float'=>'double','dateTime'=>'string',\r
211                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),\r
212         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),\r
213         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),\r
214     'http://xml.apache.org/xml-soap' => array('Map')\r
215         );\r
216 \r
217         /**\r
218         * XML entities to convert\r
219         *\r
220         * @var      array\r
221         * @access   public\r
222         * @deprecated\r
223         * @see  expandEntities\r
224         */\r
225         var $xmlEntities = array('quot' => '"','amp' => '&',\r
226                 'lt' => '<','gt' => '>','apos' => "'");\r
227 \r
228         /**\r
229         * constructor\r
230         *\r
231         * @access       public\r
232         */\r
233         function nusoap_base() {\r
234                 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;\r
235         }\r
236 \r
237         /**\r
238         * gets the global debug level, which applies to future instances\r
239         *\r
240         * @return       integer Debug level 0-9, where 0 turns off\r
241         * @access       public\r
242         */\r
243         function getGlobalDebugLevel() {\r
244                 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;\r
245         }\r
246 \r
247         /**\r
248         * sets the global debug level, which applies to future instances\r
249         *\r
250         * @param        int     $level  Debug level 0-9, where 0 turns off\r
251         * @access       public\r
252         */\r
253         function setGlobalDebugLevel($level) {\r
254                 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;\r
255         }\r
256 \r
257         /**\r
258         * gets the debug level for this instance\r
259         *\r
260         * @return       int     Debug level 0-9, where 0 turns off\r
261         * @access       public\r
262         */\r
263         function getDebugLevel() {\r
264                 return $this->debugLevel;\r
265         }\r
266 \r
267         /**\r
268         * sets the debug level for this instance\r
269         *\r
270         * @param        int     $level  Debug level 0-9, where 0 turns off\r
271         * @access       public\r
272         */\r
273         function setDebugLevel($level) {\r
274                 $this->debugLevel = $level;\r
275         }\r
276 \r
277         /**\r
278         * adds debug data to the instance debug string with formatting\r
279         *\r
280         * @param    string $string debug data\r
281         * @access   private\r
282         */\r
283         function debug($string){\r
284                 if ($this->debugLevel > 0) {\r
285                         $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");\r
286                 }\r
287         }\r
288 \r
289         /**\r
290         * adds debug data to the instance debug string without formatting\r
291         *\r
292         * @param    string $string debug data\r
293         * @access   public\r
294         */\r
295         function appendDebug($string){\r
296                 //echo "## appendDebug: ".$string."<br/>";\r
297                 if ($this->debugLevel > 0) {\r
298                         // it would be nice to use a memory stream here to use\r
299                         // memory more efficiently\r
300                         $this->debug_str .= $string;\r
301                 }\r
302         }\r
303 \r
304         /**\r
305         * clears the current debug data for this instance\r
306         *\r
307         * @access   public\r
308         */\r
309         function clearDebug() {\r
310                 // it would be nice to use a memory stream here to use\r
311                 // memory more efficiently\r
312                 $this->debug_str = '';\r
313         }\r
314 \r
315         /**\r
316         * gets the current debug data for this instance\r
317         *\r
318         * @return   debug data\r
319         * @access   public\r
320         */\r
321         function &getDebug() {\r
322                 // it would be nice to use a memory stream here to use\r
323                 // memory more efficiently\r
324                 return $this->debug_str;\r
325         }\r
326 \r
327         /**\r
328         * gets the current debug data for this instance as an XML comment\r
329         * this may change the contents of the debug data\r
330         *\r
331         * @return   debug data as an XML comment\r
332         * @access   public\r
333         */\r
334         function &getDebugAsXMLComment() {\r
335                 // it would be nice to use a memory stream here to use\r
336                 // memory more efficiently\r
337                 while (strpos($this->debug_str, '--')) {\r
338                         $this->debug_str = str_replace('--', '- -', $this->debug_str);\r
339                 }\r
340                 $ret = "<!--\n" . $this->debug_str . "\n-->";\r
341         return $ret;\r
342         }\r
343 \r
344         /**\r
345         * expands entities, e.g. changes '<' to '&lt;'.\r
346         *\r
347         * @param        string  $val    The string in which to expand entities.\r
348         * @access       private\r
349         */\r
350         function expandEntities($val) {\r
351                 if ($this->charencoding) {\r
352                 $val = str_replace('&', '&amp;', $val);\r
353                 $val = str_replace("'", '&apos;', $val);\r
354                 $val = str_replace('"', '&quot;', $val);\r
355                 $val = str_replace('<', '&lt;', $val);\r
356                 $val = str_replace('>', '&gt;', $val);\r
357             }\r
358             return $val;\r
359         }\r
360 \r
361         /**\r
362         * returns error string if present\r
363         *\r
364         * @return   mixed error string or false\r
365         * @access   public\r
366         */\r
367         function getError(){\r
368                 if($this->error_str != ''){\r
369                         return $this->error_str;\r
370                 }\r
371                 return false;\r
372         }\r
373 \r
374         /**\r
375         * sets error string\r
376         *\r
377         * @return   boolean $string error string\r
378         * @access   private\r
379         */\r
380         function setError($str){\r
381                 $this->error_str = $str;\r
382         }\r
383 \r
384         /**\r
385         * detect if array is a simple array or a struct (associative array)\r
386         *\r
387         * @param        mixed   $val    The PHP array\r
388         * @return       string  (arraySimple|arrayStruct)\r
389         * @access       private\r
390         */\r
391         function isArraySimpleOrStruct($val) {\r
392         $keyList = array_keys($val);\r
393                 foreach ($keyList as $keyListValue) {\r
394                         if (!is_int($keyListValue)) {\r
395                                 return 'arrayStruct';\r
396                         }\r
397                 }\r
398                 return 'arraySimple';\r
399         }\r
400 \r
401         /**\r
402         * serializes PHP values in accordance w/ section 5. Type information is\r
403         * not serialized if $use == 'literal'.\r
404         *\r
405         * @param        mixed   $val    The value to serialize\r
406         * @param        string  $name   The name (local part) of the XML element\r
407         * @param        string  $type   The XML schema type (local part) for the element\r
408         * @param        string  $name_ns        The namespace for the name of the XML element\r
409         * @param        string  $type_ns        The namespace for the type of the element\r
410         * @param        array   $attributes     The attributes to serialize as name=>value pairs\r
411         * @param        string  $use    The WSDL "use" (encoded|literal)\r
412         * @param        boolean $soapval        Whether this is called from soapval.\r
413         * @return       string  The serialized element, possibly with child elements\r
414     * @access   public\r
415         */\r
416         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {\r
417                 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");\r
418                 $this->appendDebug('value=' . $this->varDump($val));\r
419                 $this->appendDebug('attributes=' . $this->varDump($attributes));\r
420                 \r
421         if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {\r
422                 $this->debug("serialize_val: serialize soapval");\r
423                 $xml = $val->serialize($use);\r
424                         $this->appendDebug($val->getDebug());\r
425                         $val->clearDebug();\r
426                         $this->debug("serialize_val of soapval returning $xml");\r
427                         return $xml;\r
428         }\r
429                 // force valid name if necessary\r
430                 if (is_numeric($name)) {\r
431                         $name = '__numeric_' . $name;\r
432                 } elseif (! $name) {\r
433                         $name = 'noname';\r
434                 }\r
435                 // if name has ns, add ns prefix to name\r
436                 $xmlns = '';\r
437         if($name_ns){\r
438                         $prefix = 'nu'.rand(1000,9999);\r
439                         $name = $prefix.':'.$name;\r
440                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";\r
441                 }\r
442                 // if type is prefixed, create type prefix\r
443                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){\r
444                         // need to fix this. shouldn't default to xsd if no ns specified\r
445                     // w/o checking against typemap\r
446                         $type_prefix = 'xsd';\r
447                 } elseif($type_ns){\r
448                         $type_prefix = 'ns'.rand(1000,9999);\r
449                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";\r
450                 }\r
451                 // serialize attributes if present\r
452                 $atts = '';\r
453                 if($attributes){\r
454                         foreach($attributes as $k => $v){\r
455                                 $atts .= " $k=\"".$this->expandEntities($v).'"';\r
456                         }\r
457                 }\r
458                 // serialize null value\r
459                 if (is_null($val)) {\r
460                 $this->debug("serialize_val: serialize null");\r
461                         if ($use == 'literal') {\r
462                                 // TODO: depends on minOccurs\r
463                                 $xml = "<$name$xmlns$atts/>";\r
464                                 $this->debug("serialize_val returning $xml");\r
465                         return $xml;\r
466                 } else {\r
467                                 if (isset($type) && isset($type_prefix)) {\r
468                                         $type_str = " xsi:type=\"$type_prefix:$type\"";\r
469                                 } else {\r
470                                         $type_str = '';\r
471                                 }\r
472                                 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";\r
473                                 $this->debug("serialize_val returning $xml");\r
474                         return $xml;\r
475                 }\r
476                 }\r
477         // serialize if an xsd built-in primitive type\r
478         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){\r
479                 $this->debug("serialize_val: serialize xsd built-in primitive type");\r
480                 if (is_bool($val)) {\r
481                         if ($type == 'boolean') {\r
482                                 $val = $val ? 'true' : 'false';\r
483                         } elseif (! $val) {\r
484                                 $val = 0;\r
485                         }\r
486                         } else if (is_string($val)) {\r
487                                 $val = $this->expandEntities($val);\r
488                         }\r
489                         if ($use == 'literal') {\r
490                                 $xml = "<$name$xmlns$atts>$val</$name>";\r
491                                 $this->debug("serialize_val returning $xml");\r
492                         return $xml;\r
493                 } else {\r
494                                 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";\r
495                                 $this->debug("serialize_val returning $xml");\r
496                         return $xml;\r
497                 }\r
498         }\r
499                 // detect type and serialize\r
500                 $xml = '';\r
501                 switch(true) {\r
502                         case (is_bool($val) || $type == 'boolean'):\r
503                                 $this->debug("serialize_val: serialize boolean");\r
504                         if ($type == 'boolean') {\r
505                                 $val = $val ? 'true' : 'false';\r
506                         } elseif (! $val) {\r
507                                 $val = 0;\r
508                         }\r
509                                 if ($use == 'literal') {\r
510                                         $xml .= "<$name$xmlns$atts>$val</$name>";\r
511                                 } else {\r
512                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";\r
513                                 }\r
514                                 break;\r
515                         case (is_int($val) || is_long($val) || $type == 'int'):\r
516                                 $this->debug("serialize_val: serialize int");\r
517                                 if ($use == 'literal') {\r
518                                         $xml .= "<$name$xmlns$atts>$val</$name>";\r
519                                 } else {\r
520                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";\r
521                                 }\r
522                                 break;\r
523                         case (is_float($val)|| is_double($val) || $type == 'float'):\r
524                                 $this->debug("serialize_val: serialize float");\r
525                                 if ($use == 'literal') {\r
526                                         $xml .= "<$name$xmlns$atts>$val</$name>";\r
527                                 } else {\r
528                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";\r
529                                 }\r
530                                 break;\r
531                         case (is_string($val) || $type == 'string'):\r
532                                 $this->debug("serialize_val: serialize string");\r
533                                 $val = $this->expandEntities($val);\r
534                                 if ($use == 'literal') {\r
535                                         $xml .= "<$name$xmlns$atts>$val</$name>";\r
536                                 } else {\r
537                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";\r
538                                 }\r
539                                 break;\r
540                         case is_object($val):\r
541                                 $this->debug("serialize_val: serialize object");\r
542                         if (get_class($val) == 'soapval') {\r
543                                 $this->debug("serialize_val: serialize soapval object");\r
544                                 $pXml = $val->serialize($use);\r
545                                         $this->appendDebug($val->getDebug());\r
546                                         $val->clearDebug();\r
547                         } else {\r
548                                         if (! $name) {\r
549                                                 $name = get_class($val);\r
550                                                 $this->debug("In serialize_val, used class name $name as element name");\r
551                                         } else {\r
552                                                 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));\r
553                                         }\r
554                                         foreach(get_object_vars($val) as $k => $v){\r
555                                                 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);\r
556                                         }\r
557                                 }\r
558                                 if(isset($type) && isset($type_prefix)){\r
559                                         $type_str = " xsi:type=\"$type_prefix:$type\"";\r
560                                 } else {\r
561                                         $type_str = '';\r
562                                 }\r
563                                 if ($use == 'literal') {\r
564                                         $xml .= "<$name$xmlns$atts>$pXml</$name>";\r
565                                 } else {\r
566                                         $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";\r
567                                 }\r
568                                 break;\r
569                         break;\r
570                         case (is_array($val) || $type):\r
571                                 // detect if struct or array\r
572                                 $valueType = $this->isArraySimpleOrStruct($val);\r
573                 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){\r
574                                         $this->debug("serialize_val: serialize array");\r
575                                         $i = 0;\r
576                                         if(is_array($val) && count($val)> 0){\r
577                                                 foreach($val as $v){\r
578                                 if(is_object($v) && get_class($v) ==  'soapval'){\r
579                                                                 $tt_ns = $v->type_ns;\r
580                                                                 $tt = $v->type;\r
581                                                         } elseif (is_array($v)) {\r
582                                                                 $tt = $this->isArraySimpleOrStruct($v);\r
583                                                         } else {\r
584                                                                 $tt = gettype($v);\r
585                                 }\r
586                                                         $array_types[$tt] = 1;\r
587                                                         // TODO: for literal, the name should be $name\r
588                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);\r
589                                                         ++$i;\r
590                                                 }\r
591                                                 if(count($array_types) > 1){\r
592                                                         $array_typename = 'xsd:anyType';\r
593                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {\r
594                                                         if ($tt == 'integer') {\r
595                                                                 $tt = 'int';\r
596                                                         }\r
597                                                         $array_typename = 'xsd:'.$tt;\r
598                                                 } elseif(isset($tt) && $tt == 'arraySimple'){\r
599                                                         $array_typename = 'SOAP-ENC:Array';\r
600                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){\r
601                                                         $array_typename = 'unnamed_struct_use_soapval';\r
602                                                 } else {\r
603                                                         // if type is prefixed, create type prefix\r
604                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){\r
605                                                                  $array_typename = 'xsd:' . $tt;\r
606                                                         } elseif ($tt_ns) {\r
607                                                                 $tt_prefix = 'ns' . rand(1000, 9999);\r
608                                                                 $array_typename = "$tt_prefix:$tt";\r
609                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";\r
610                                                         } else {\r
611                                                                 $array_typename = $tt;\r
612                                                         }\r
613                                                 }\r
614                                                 $array_type = $i;\r
615                                                 if ($use == 'literal') {\r
616                                                         $type_str = '';\r
617                                                 } else if (isset($type) && isset($type_prefix)) {\r
618                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";\r
619                                                 } else {\r
620                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";\r
621                                                 }\r
622                                         // empty array\r
623                                         } else {\r
624                                                 if ($use == 'literal') {\r
625                                                         $type_str = '';\r
626                                                 } else if (isset($type) && isset($type_prefix)) {\r
627                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";\r
628                                                 } else {\r
629                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";\r
630                                                 }\r
631                                         }\r
632                                         // TODO: for array in literal, there is no wrapper here\r
633                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";\r
634                                 } else {\r
635                                         // got a struct\r
636                                         $this->debug("serialize_val: serialize struct");\r
637                                         if(isset($type) && isset($type_prefix)){\r
638                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";\r
639                                         } else {\r
640                                                 $type_str = '';\r
641                                         }\r
642                                         if ($use == 'literal') {\r
643                                                 $xml .= "<$name$xmlns$atts>";\r
644                                         } else {\r
645                                                 $xml .= "<$name$xmlns$type_str$atts>";\r
646                                         }\r
647                                         foreach($val as $k => $v){\r
648                                                 // Apache Map\r
649                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {\r
650                                                         $xml .= '<item>';\r
651                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);\r
652                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);\r
653                                                         $xml .= '</item>';\r
654                                                 } else {\r
655                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);\r
656                                                 }\r
657                                         }\r
658                                         $xml .= "</$name>";\r
659                                 }\r
660                                 break;\r
661                         default:\r
662                                 $this->debug("serialize_val: serialize unknown");\r
663                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;\r
664                                 break;\r
665                 }\r
666                 $this->debug("serialize_val returning $xml");\r
667                 return $xml;\r
668         }\r
669 \r
670     /**\r
671     * serializes a message\r
672     *\r
673     * @param string $body the XML of the SOAP body\r
674     * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array\r
675     * @param array $namespaces optional the namespaces used in generating the body and headers\r
676     * @param string $style optional (rpc|document)\r
677     * @param string $use optional (encoded|literal)\r
678     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)\r
679     * @return string the message\r
680     * @access public\r
681     */\r
682     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){\r
683     // TODO: add an option to automatically run utf8_encode on $body and $headers\r
684     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows\r
685     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1\r
686 \r
687         $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");\r
688         $this->debug("headers:");\r
689         $this->appendDebug($this->varDump($headers));\r
690         $this->debug("namespaces:");\r
691         $this->appendDebug($this->varDump($namespaces));\r
692 \r
693         // serialize namespaces\r
694     $ns_string = '';\r
695         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){\r
696                 $ns_string .= " xmlns:$k=\"$v\"";\r
697         }\r
698         if($encodingStyle) {\r
699                 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";\r
700         }\r
701 \r
702         // serialize headers\r
703         if($headers){\r
704                 if (is_array($headers)) {\r
705                         $xml = '';\r
706                         foreach ($headers as $k => $v) {\r
707                                 if (is_object($v) && get_class($v) == 'soapval') {\r
708                                         $xml .= $this->serialize_val($v, false, false, false, false, false, $use);\r
709                                 } else {\r
710                                         $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);\r
711                                 }\r
712                         }\r
713                         $headers = $xml;\r
714                         $this->debug("In serializeEnvelope, serialized array of headers to $headers");\r
715                 }\r
716                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";\r
717         }\r
718         //echo "####<br/>";\r
719         //echo $body;\r
720         //echo  "<br/>####<br/>";\r
721         // serialize envelope\r
722         return\r
723         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".\r
724         '<SOAP-ENV:Envelope'.$ns_string.">".\r
725         $headers.\r
726         "<SOAP-ENV:Body>".\r
727                 $body.\r
728         "</SOAP-ENV:Body>".\r
729         "</SOAP-ENV:Envelope>";\r
730     }\r
731 \r
732         /**\r
733          * formats a string to be inserted into an HTML stream\r
734          *\r
735          * @param string $str The string to format\r
736          * @return string The formatted string\r
737          * @access public\r
738          * @deprecated\r
739          */\r
740     function formatDump($str){\r
741                 $str = htmlspecialchars($str);\r
742                 return nl2br($str);\r
743     }\r
744 \r
745         /**\r
746         * contracts (changes namespace to prefix) a qualified name\r
747         *\r
748         * @param    string $qname qname\r
749         * @return       string contracted qname\r
750         * @access   private\r
751         */\r
752         function contractQname($qname){\r
753                 // get element namespace\r
754                 //$this->xdebug("Contract $qname");\r
755                 if (strrpos($qname, ':')) {\r
756                         // get unqualified name\r
757                         $name = substr($qname, strrpos($qname, ':') + 1);\r
758                         // get ns\r
759                         $ns = substr($qname, 0, strrpos($qname, ':'));\r
760                         $p = $this->getPrefixFromNamespace($ns);\r
761                         if ($p) {\r
762                                 return $p . ':' . $name;\r
763                         }\r
764                         return $qname;\r
765                 } else {\r
766                         return $qname;\r
767                 }\r
768         }\r
769 \r
770         /**\r
771         * expands (changes prefix to namespace) a qualified name\r
772         *\r
773         * @param    string $qname qname\r
774         * @return       string expanded qname\r
775         * @access   private\r
776         */\r
777         function expandQname($qname){\r
778                 // get element prefix\r
779                 if(strpos($qname,':') && !ereg('^http://',$qname)){\r
780                         // get unqualified name\r
781                         $name = substr(strstr($qname,':'),1);\r
782                         // get ns prefix\r
783                         $prefix = substr($qname,0,strpos($qname,':'));\r
784                         if(isset($this->namespaces[$prefix])){\r
785                                 return $this->namespaces[$prefix].':'.$name;\r
786                         } else {\r
787                                 return $qname;\r
788                         }\r
789                 } else {\r
790                         return $qname;\r
791                 }\r
792         }\r
793 \r
794     /**\r
795     * returns the local part of a prefixed string\r
796     * returns the original string, if not prefixed\r
797     *\r
798     * @param string $str The prefixed string\r
799     * @return string The local part\r
800     * @access public\r
801     */\r
802         function getLocalPart($str){\r
803                 if($sstr = strrchr($str,':')){\r
804                         // get unqualified name\r
805                         return substr( $sstr, 1 );\r
806                 } else {\r
807                         return $str;\r
808                 }\r
809         }\r
810 \r
811         /**\r
812     * returns the prefix part of a prefixed string\r
813     * returns false, if not prefixed\r
814     *\r
815     * @param string $str The prefixed string\r
816     * @return mixed The prefix or false if there is no prefix\r
817     * @access public\r
818     */\r
819         function getPrefix($str){\r
820                 if($pos = strrpos($str,':')){\r
821                         // get prefix\r
822                         return substr($str,0,$pos);\r
823                 }\r
824                 return false;\r
825         }\r
826 \r
827         /**\r
828     * pass it a prefix, it returns a namespace\r
829     *\r
830     * @param string $prefix The prefix\r
831     * @return mixed The namespace, false if no namespace has the specified prefix\r
832     * @access public\r
833     */\r
834         function getNamespaceFromPrefix($prefix){\r
835                 if (isset($this->namespaces[$prefix])) {\r
836                         return $this->namespaces[$prefix];\r
837                 }\r
838                 //$this->setError("No namespace registered for prefix '$prefix'");\r
839                 return false;\r
840         }\r
841 \r
842         /**\r
843     * returns the prefix for a given namespace (or prefix)\r
844     * or false if no prefixes registered for the given namespace\r
845     *\r
846     * @param string $ns The namespace\r
847     * @return mixed The prefix, false if the namespace has no prefixes\r
848     * @access public\r
849     */\r
850         function getPrefixFromNamespace($ns) {\r
851                 foreach ($this->namespaces as $p => $n) {\r
852                         if ($ns == $n || $ns == $p) {\r
853                             $this->usedNamespaces[$p] = $n;\r
854                                 return $p;\r
855                         }\r
856                 }\r
857                 return false;\r
858         }\r
859 \r
860         /**\r
861     * returns the time in ODBC canonical form with microseconds\r
862     *\r
863     * @return string The time in ODBC canonical form with microseconds\r
864     * @access public\r
865     */\r
866         function getmicrotime() {\r
867                 if (function_exists('gettimeofday')) {\r
868                         $tod = gettimeofday();\r
869                         $sec = $tod['sec'];\r
870                         $usec = $tod['usec'];\r
871                 } else {\r
872                         $sec = time();\r
873                         $usec = 0;\r
874                 }\r
875                 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);\r
876         }\r
877 \r
878         /**\r
879          * Returns a string with the output of var_dump\r
880          *\r
881          * @param mixed $data The variable to var_dump\r
882          * @return string The output of var_dump\r
883          * @access public\r
884          */\r
885     function varDump($data) {\r
886                 ob_start();\r
887                 var_dump($data);\r
888                 $ret_val = ob_get_contents();\r
889                 ob_end_clean();\r
890                 return $ret_val;\r
891         }\r
892 \r
893         /**\r
894         * represents the object as a string\r
895         *\r
896         * @return       string\r
897         * @access   public\r
898         */\r
899         function __toString() {\r
900                 return $this->varDump($this);\r
901         }\r
902 }\r
903 \r
904 // XML Schema Datatype Helper Functions\r
905 \r
906 //xsd:dateTime helpers\r
907 \r
908 /**\r
909 * convert unix timestamp to ISO 8601 compliant date string\r
910 *\r
911 * @param    string $timestamp Unix time stamp\r
912 * @param        boolean $utc Whether the time stamp is UTC or local\r
913 * @access   public\r
914 */\r
915 function timestamp_to_iso8601($timestamp,$utc=true){\r
916         $datestr = date('Y-m-d\TH:i:sO',$timestamp);\r
917         if($utc){\r
918                 $eregStr =\r
919                 '([0-9]{4})-'.  // centuries & years CCYY-\r
920                 '([0-9]{2})-'.  // months MM-\r
921                 '([0-9]{2})'.   // days DD\r
922                 'T'.                    // separator T\r
923                 '([0-9]{2}):'.  // hours hh:\r
924                 '([0-9]{2}):'.  // minutes mm:\r
925                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...\r
926                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's\r
927 \r
928                 if(ereg($eregStr,$datestr,$regs)){\r
929                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);\r
930                 }\r
931                 return false;\r
932         } else {\r
933                 return $datestr;\r
934         }\r
935 }\r
936 \r
937 /**\r
938 * convert ISO 8601 compliant date string to unix timestamp\r
939 *\r
940 * @param    string $datestr ISO 8601 compliant date string\r
941 * @access   public\r
942 */\r
943 function iso8601_to_timestamp($datestr){\r
944         $eregStr =\r
945         '([0-9]{4})-'.  // centuries & years CCYY-\r
946         '([0-9]{2})-'.  // months MM-\r
947         '([0-9]{2})'.   // days DD\r
948         'T'.                    // separator T\r
949         '([0-9]{2}):'.  // hours hh:\r
950         '([0-9]{2}):'.  // minutes mm:\r
951         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...\r
952         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's\r
953         if(ereg($eregStr,$datestr,$regs)){\r
954                 // not utc\r
955                 if($regs[8] != 'Z'){\r
956                         $op = substr($regs[8],0,1);\r
957                         $h = substr($regs[8],1,2);\r
958                         $m = substr($regs[8],strlen($regs[8])-2,2);\r
959                         if($op == '-'){\r
960                                 $regs[4] = $regs[4] + $h;\r
961                                 $regs[5] = $regs[5] + $m;\r
962                         } elseif($op == '+'){\r
963                                 $regs[4] = $regs[4] - $h;\r
964                                 $regs[5] = $regs[5] - $m;\r
965                         }\r
966                 }\r
967                 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);\r
968 //              return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");\r
969         } else {\r
970                 return false;\r
971         }\r
972 }\r
973 \r
974 /**\r
975 * sleeps some number of microseconds\r
976 *\r
977 * @param    string $usec the number of microseconds to sleep\r
978 * @access   public\r
979 * @deprecated\r
980 */\r
981 function usleepWindows($usec)\r
982 {\r
983         $start = gettimeofday();\r
984         \r
985         do\r
986         {\r
987                 $stop = gettimeofday();\r
988                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])\r
989                 + $stop['usec'] - $start['usec'];\r
990         }\r
991         while ($timePassed < $usec);\r
992 }\r
993 \r
994 ?><?php\r
995 \r
996 \r
997 \r
998 /**\r
999 * Contains information for a SOAP fault.\r
1000 * Mainly used for returning faults from deployed functions\r
1001 * in a server instance.\r
1002 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
1003 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
1004 * @access public\r
1005 */\r
1006 class nusoap_fault extends nusoap_base {\r
1007         /**\r
1008          * The fault code (client|server)\r
1009          * @var string\r
1010          * @access private\r
1011          */\r
1012         var $faultcode;\r
1013         /**\r
1014          * The fault actor\r
1015          * @var string\r
1016          * @access private\r
1017          */\r
1018         var $faultactor;\r
1019         /**\r
1020          * The fault string, a description of the fault\r
1021          * @var string\r
1022          * @access private\r
1023          */\r
1024         var $faultstring;\r
1025         /**\r
1026          * The fault detail, typically a string or array of string\r
1027          * @var mixed\r
1028          * @access private\r
1029          */\r
1030         var $faultdetail;\r
1031 \r
1032         /**\r
1033         * constructor\r
1034     *\r
1035     * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)\r
1036     * @param string $faultactor only used when msg routed between multiple actors\r
1037     * @param string $faultstring human readable error message\r
1038     * @param mixed $faultdetail detail, typically a string or array of string\r
1039         */\r
1040         function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){\r
1041                 parent::nusoap_base();\r
1042                 $this->faultcode = $faultcode;\r
1043                 $this->faultactor = $faultactor;\r
1044                 $this->faultstring = $faultstring;\r
1045                 $this->faultdetail = $faultdetail;\r
1046         }\r
1047 \r
1048         /**\r
1049         * serialize a fault\r
1050         *\r
1051         * @return       string  The serialization of the fault instance.\r
1052         * @access   public\r
1053         */\r
1054         function serialize(){\r
1055                 $ns_string = '';\r
1056                 foreach($this->namespaces as $k => $v){\r
1057                         $ns_string .= "\n  xmlns:$k=\"$v\"";\r
1058                 }\r
1059                 $return_msg =\r
1060                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.\r
1061                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".\r
1062                                 '<SOAP-ENV:Body>'.\r
1063                                 '<SOAP-ENV:Fault>'.\r
1064                                         $this->serialize_val($this->faultcode, 'faultcode').\r
1065                                         $this->serialize_val($this->faultactor, 'faultactor').\r
1066                                         $this->serialize_val($this->faultstring, 'faultstring').\r
1067                                         $this->serialize_val($this->faultdetail, 'detail').\r
1068                                 '</SOAP-ENV:Fault>'.\r
1069                                 '</SOAP-ENV:Body>'.\r
1070                         '</SOAP-ENV:Envelope>';\r
1071                 return $return_msg;\r
1072         }\r
1073 }\r
1074 \r
1075 /**\r
1076  * Backward compatibility\r
1077  */\r
1078 class soap_fault extends nusoap_fault {\r
1079 }\r
1080 \r
1081 ?><?php\r
1082 \r
1083 \r
1084 \r
1085 /**\r
1086 * parses an XML Schema, allows access to it's data, other utility methods.\r
1087 * imperfect, no validation... yet, but quite functional.\r
1088 *\r
1089 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
1090 * @author   Scott Nichol <snichol@users.sourceforge.net>\r
1091 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
1092 * @access   public\r
1093 */\r
1094 class nusoap_xmlschema extends nusoap_base  {\r
1095         \r
1096         // files\r
1097         var $schema = '';\r
1098         var $xml = '';\r
1099         // namespaces\r
1100         var $enclosingNamespaces;\r
1101         // schema info\r
1102         var $schemaInfo = array();\r
1103         var $schemaTargetNamespace = '';\r
1104         // types, elements, attributes defined by the schema\r
1105         var $attributes = array();\r
1106         var $complexTypes = array();\r
1107         var $complexTypeStack = array();\r
1108         var $currentComplexType = null;\r
1109         var $elements = array();\r
1110         var $elementStack = array();\r
1111         var $currentElement = null;\r
1112         var $simpleTypes = array();\r
1113         var $simpleTypeStack = array();\r
1114         var $currentSimpleType = null;\r
1115         // imports\r
1116         var $imports = array();\r
1117         // parser vars\r
1118         var $parser;\r
1119         var $position = 0;\r
1120         var $depth = 0;\r
1121         var $depth_array = array();\r
1122         var $message = array();\r
1123         var $defaultNamespace = array();\r
1124     \r
1125         /**\r
1126         * constructor\r
1127         *\r
1128         * @param    string $schema schema document URI\r
1129         * @param    string $xml xml document URI\r
1130         * @param        string $namespaces namespaces defined in enclosing XML\r
1131         * @access   public\r
1132         */\r
1133         function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){\r
1134                 parent::nusoap_base();\r
1135                 $this->debug('nusoap_xmlschema class instantiated, inside constructor');\r
1136                 // files\r
1137                 $this->schema = $schema;\r
1138                 $this->xml = $xml;\r
1139 \r
1140                 // namespaces\r
1141                 $this->enclosingNamespaces = $namespaces;\r
1142                 $this->namespaces = array_merge($this->namespaces, $namespaces);\r
1143 \r
1144                 // parse schema file\r
1145                 if($schema != ''){\r
1146                         $this->debug('initial schema file: '.$schema);\r
1147                         $this->parseFile($schema, 'schema');\r
1148                 }\r
1149 \r
1150                 // parse xml file\r
1151                 if($xml != ''){\r
1152                         $this->debug('initial xml file: '.$xml);\r
1153                         $this->parseFile($xml, 'xml');\r
1154                 }\r
1155 \r
1156         }\r
1157 \r
1158     /**\r
1159     * parse an XML file\r
1160     *\r
1161     * @param string $xml path/URL to XML file\r
1162     * @param string $type (schema | xml)\r
1163         * @return boolean\r
1164     * @access public\r
1165     */\r
1166         function parseFile($xml,$type){\r
1167                 // parse xml file\r
1168                 if($xml != ""){\r
1169                         $xmlStr = @join("",@file($xml));\r
1170                         if($xmlStr == ""){\r
1171                                 $msg = 'Error reading XML from '.$xml;\r
1172                                 $this->setError($msg);\r
1173                                 $this->debug($msg);\r
1174                         return false;\r
1175                         } else {\r
1176                                 $this->debug("parsing $xml");\r
1177                                 $this->parseString($xmlStr,$type);\r
1178                                 $this->debug("done parsing $xml");\r
1179                         return true;\r
1180                         }\r
1181                 }\r
1182                 return false;\r
1183         }\r
1184 \r
1185         /**\r
1186         * parse an XML string\r
1187         *\r
1188         * @param    string $xml path or URL\r
1189     * @param    string $type (schema|xml)\r
1190         * @access   private\r
1191         */\r
1192         function parseString($xml,$type){\r
1193                 // parse xml string\r
1194                 if($xml != ""){\r
1195 \r
1196                 // Create an XML parser.\r
1197                 $this->parser = xml_parser_create();\r
1198                 // Set the options for parsing the XML data.\r
1199                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);\r
1200 \r
1201                 // Set the object for the parser.\r
1202                 xml_set_object($this->parser, $this);\r
1203 \r
1204                 // Set the element handlers for the parser.\r
1205                         if($type == "schema"){\r
1206                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');\r
1207                         xml_set_character_data_handler($this->parser,'schemaCharacterData');\r
1208                         } elseif($type == "xml"){\r
1209                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');\r
1210                         xml_set_character_data_handler($this->parser,'xmlCharacterData');\r
1211                         }\r
1212 \r
1213                     // Parse the XML file.\r
1214                     if(!xml_parse($this->parser,$xml,true)){\r
1215                         // Display an error message.\r
1216                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',\r
1217                                 xml_get_current_line_number($this->parser),\r
1218                                 xml_error_string(xml_get_error_code($this->parser))\r
1219                                 );\r
1220                                 $this->debug($errstr);\r
1221                                 $this->debug("XML payload:\n" . $xml);\r
1222                                 $this->setError($errstr);\r
1223                 }\r
1224             \r
1225                         xml_parser_free($this->parser);\r
1226                 } else{\r
1227                         $this->debug('no xml passed to parseString()!!');\r
1228                         $this->setError('no xml passed to parseString()!!');\r
1229                 }\r
1230         }\r
1231 \r
1232         /**\r
1233          * gets a type name for an unnamed type\r
1234          *\r
1235          * @param       string  Element name\r
1236          * @return      string  A type name for an unnamed type\r
1237          * @access      private\r
1238          */\r
1239         function CreateTypeName($ename) {\r
1240                 $scope = '';\r
1241                 for ($i = 0; $i < count($this->complexTypeStack); $i++) {\r
1242                         $scope .= $this->complexTypeStack[$i] . '_';\r
1243                 }\r
1244                 return $scope . $ename . '_ContainedType';\r
1245         }\r
1246         \r
1247         /**\r
1248         * start-element handler\r
1249         *\r
1250         * @param    string $parser XML parser object\r
1251         * @param    string $name element name\r
1252         * @param    string $attrs associative array of attributes\r
1253         * @access   private\r
1254         */\r
1255         function schemaStartElement($parser, $name, $attrs) {\r
1256                 \r
1257                 // position in the total number of elements, starting from 0\r
1258                 $pos = $this->position++;\r
1259                 $depth = $this->depth++;\r
1260                 // set self as current value for this depth\r
1261                 $this->depth_array[$depth] = $pos;\r
1262                 $this->message[$pos] = array('cdata' => ''); \r
1263                 if ($depth > 0) {\r
1264                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];\r
1265                 } else {\r
1266                         $this->defaultNamespace[$pos] = false;\r
1267                 }\r
1268 \r
1269                 // get element prefix\r
1270                 if($prefix = $this->getPrefix($name)){\r
1271                         // get unqualified name\r
1272                         $name = $this->getLocalPart($name);\r
1273                 } else {\r
1274                 $prefix = '';\r
1275         }\r
1276                 \r
1277         // loop thru attributes, expanding, and registering namespace declarations\r
1278         if(count($attrs) > 0){\r
1279                 foreach($attrs as $k => $v){\r
1280                 // if ns declarations, add to class level array of valid namespaces\r
1281                                 if(ereg("^xmlns",$k)){\r
1282                         //$this->xdebug("$k: $v");\r
1283                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));\r
1284                         if($ns_prefix = substr(strrchr($k,':'),1)){\r
1285                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");\r
1286                                                 $this->namespaces[$ns_prefix] = $v;\r
1287                                         } else {\r
1288                                                 $this->defaultNamespace[$pos] = $v;\r
1289                                                 if (! $this->getPrefixFromNamespace($v)) {\r
1290                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;\r
1291                                                 }\r
1292                                         }\r
1293                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){\r
1294                                                 $this->XMLSchemaVersion = $v;\r
1295                                                 $this->namespaces['xsi'] = $v.'-instance';\r
1296                                         }\r
1297                                 }\r
1298                 }\r
1299                 foreach($attrs as $k => $v){\r
1300                 // expand each attribute\r
1301                 $k = strpos($k,':') ? $this->expandQname($k) : $k;\r
1302                 $v = strpos($v,':') ? $this->expandQname($v) : $v;\r
1303                         $eAttrs[$k] = $v;\r
1304                 }\r
1305                 $attrs = $eAttrs;\r
1306         } else {\r
1307                 $attrs = array();\r
1308         }\r
1309                 // find status, register data\r
1310                 switch($name){\r
1311                         case 'all':                     // (optional) compositor content for a complexType\r
1312                         case 'choice':\r
1313                         case 'group':\r
1314                         case 'sequence':\r
1315                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");\r
1316                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;\r
1317                                 //if($name == 'all' || $name == 'sequence'){\r
1318                                 //      $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';\r
1319                                 //}\r
1320                         break;\r
1321                         case 'attribute':       // complexType attribute\r
1322                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);\r
1323                 $this->xdebug("parsing attribute:");\r
1324                 $this->appendDebug($this->varDump($attrs));\r
1325                                 if (!isset($attrs['form'])) {\r
1326                                         $attrs['form'] = $this->schemaInfo['attributeFormDefault'];\r
1327                                 }\r
1328                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {\r
1329                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];\r
1330                                         if (!strpos($v, ':')) {\r
1331                                                 // no namespace in arrayType attribute value...\r
1332                                                 if ($this->defaultNamespace[$pos]) {\r
1333                                                         // ...so use the default\r
1334                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];\r
1335                                                 }\r
1336                                         }\r
1337                 }\r
1338                 if(isset($attrs['name'])){\r
1339                                         $this->attributes[$attrs['name']] = $attrs;\r
1340                                         $aname = $attrs['name'];\r
1341                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){\r
1342                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {\r
1343                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];\r
1344                         } else {\r
1345                                 $aname = '';\r
1346                         }\r
1347                                 } elseif(isset($attrs['ref'])){\r
1348                                         $aname = $attrs['ref'];\r
1349                     $this->attributes[$attrs['ref']] = $attrs;\r
1350                                 }\r
1351                 \r
1352                                 if($this->currentComplexType){  // This should *always* be\r
1353                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;\r
1354                                 }\r
1355                                 // arrayType attribute\r
1356                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){\r
1357                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';\r
1358                         $prefix = $this->getPrefix($aname);\r
1359                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){\r
1360                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];\r
1361                                         } else {\r
1362                                                 $v = '';\r
1363                                         }\r
1364                     if(strpos($v,'[,]')){\r
1365                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;\r
1366                     }\r
1367                     $v = substr($v,0,strpos($v,'[')); // clip the []\r
1368                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){\r
1369                         $v = $this->XMLSchemaVersion.':'.$v;\r
1370                     }\r
1371                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;\r
1372                                 }\r
1373                         break;\r
1374                         case 'complexContent':  // (optional) content for a complexType\r
1375                         break;\r
1376                         case 'complexType':\r
1377                                 array_push($this->complexTypeStack, $this->currentComplexType);\r
1378                                 if(isset($attrs['name'])){\r
1379                                         // TODO: what is the scope of named complexTypes that appear\r
1380                                         //       nested within other c complexTypes?\r
1381                                         $this->xdebug('processing named complexType '.$attrs['name']);\r
1382                                         //$this->currentElement = false;\r
1383                                         $this->currentComplexType = $attrs['name'];\r
1384                                         $this->complexTypes[$this->currentComplexType] = $attrs;\r
1385                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';\r
1386                                         // This is for constructs like\r
1387                                         //           <complexType name="ListOfString" base="soap:Array">\r
1388                                         //                <sequence>\r
1389                                         //                    <element name="string" type="xsd:string"\r
1390                                         //                        minOccurs="0" maxOccurs="unbounded" />\r
1391                                         //                </sequence>\r
1392                                         //            </complexType>\r
1393                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){\r
1394                                                 $this->xdebug('complexType is unusual array');\r
1395                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';\r
1396                                         } else {\r
1397                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';\r
1398                                         }\r
1399                                 } else {\r
1400                                         $name = $this->CreateTypeName($this->currentElement);\r
1401                                         $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);\r
1402                                         $this->currentComplexType = $name;\r
1403                                         //$this->currentElement = false;\r
1404                                         $this->complexTypes[$this->currentComplexType] = $attrs;\r
1405                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';\r
1406                                         // This is for constructs like\r
1407                                         //           <complexType name="ListOfString" base="soap:Array">\r
1408                                         //                <sequence>\r
1409                                         //                    <element name="string" type="xsd:string"\r
1410                                         //                        minOccurs="0" maxOccurs="unbounded" />\r
1411                                         //                </sequence>\r
1412                                         //            </complexType>\r
1413                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){\r
1414                                                 $this->xdebug('complexType is unusual array');\r
1415                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';\r
1416                                         } else {\r
1417                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';\r
1418                                         }\r
1419                                 }\r
1420                         break;\r
1421                         case 'element':\r
1422                                 array_push($this->elementStack, $this->currentElement);\r
1423                                 if (!isset($attrs['form'])) {\r
1424                                         $attrs['form'] = $this->schemaInfo['elementFormDefault'];\r
1425                                 }\r
1426                                 if(isset($attrs['type'])){\r
1427                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);\r
1428                                         if (! $this->getPrefix($attrs['type'])) {\r
1429                                                 if ($this->defaultNamespace[$pos]) {\r
1430                                                         $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];\r
1431                                                         $this->xdebug('used default namespace to make type ' . $attrs['type']);\r
1432                                                 }\r
1433                                         }\r
1434                                         // This is for constructs like\r
1435                                         //           <complexType name="ListOfString" base="soap:Array">\r
1436                                         //                <sequence>\r
1437                                         //                    <element name="string" type="xsd:string"\r
1438                                         //                        minOccurs="0" maxOccurs="unbounded" />\r
1439                                         //                </sequence>\r
1440                                         //            </complexType>\r
1441                                         if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {\r
1442                                                 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);\r
1443                                                 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];\r
1444                                         }\r
1445                                         $this->currentElement = $attrs['name'];\r
1446                                         $ename = $attrs['name'];\r
1447                                 } elseif(isset($attrs['ref'])){\r
1448                                         $this->xdebug("processing element as ref to ".$attrs['ref']);\r
1449                                         $this->currentElement = "ref to ".$attrs['ref'];\r
1450                                         $ename = $this->getLocalPart($attrs['ref']);\r
1451                                 } else {\r
1452                                         $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);\r
1453                                         $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);\r
1454                                         $this->currentElement = $attrs['name'];\r
1455                                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;\r
1456                                         $ename = $attrs['name'];\r
1457                                 }\r
1458                                 if (isset($ename) && $this->currentComplexType) {\r
1459                                         $this->xdebug("add element $ename to complexType $this->currentComplexType");\r
1460                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;\r
1461                                 } elseif (!isset($attrs['ref'])) {\r
1462                                         $this->xdebug("add element $ename to elements array");\r
1463                                         $this->elements[ $attrs['name'] ] = $attrs;\r
1464                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';\r
1465                                 }\r
1466                         break;\r
1467                         case 'enumeration':     //      restriction value list member\r
1468                                 $this->xdebug('enumeration ' . $attrs['value']);\r
1469                                 if ($this->currentSimpleType) {\r
1470                                         $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];\r
1471                                 } elseif ($this->currentComplexType) {\r
1472                                         $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];\r
1473                                 }\r
1474                         break;\r
1475                         case 'extension':       // simpleContent or complexContent type extension\r
1476                                 $this->xdebug('extension ' . $attrs['base']);\r
1477                                 if ($this->currentComplexType) {\r
1478                                         $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];\r
1479                                 }\r
1480                         break;\r
1481                         case 'import':\r
1482                             if (isset($attrs['schemaLocation'])) {\r
1483                                         //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);\r
1484                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);\r
1485                                 } else {\r
1486                                         //$this->xdebug('import namespace ' . $attrs['namespace']);\r
1487                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);\r
1488                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {\r
1489                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];\r
1490                                         }\r
1491                                 }\r
1492                         break;\r
1493                         case 'list':    // simpleType value list\r
1494                         break;\r
1495                         case 'restriction':     // simpleType, simpleContent or complexContent value restriction\r
1496                                 $this->xdebug('restriction ' . $attrs['base']);\r
1497                                 if($this->currentSimpleType){\r
1498                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];\r
1499                                 } elseif($this->currentComplexType){\r
1500                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];\r
1501                                         if(strstr($attrs['base'],':') == ':Array'){\r
1502                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';\r
1503                                         }\r
1504                                 }\r
1505                         break;\r
1506                         case 'schema':\r
1507                                 $this->schemaInfo = $attrs;\r
1508                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);\r
1509                                 if (isset($attrs['targetNamespace'])) {\r
1510                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];\r
1511                                 }\r
1512                                 if (!isset($attrs['elementFormDefault'])) {\r
1513                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';\r
1514                                 }\r
1515                                 if (!isset($attrs['attributeFormDefault'])) {\r
1516                                         $this->schemaInfo['attributeFormDefault'] = 'unqualified';\r
1517                                 }\r
1518                         break;\r
1519                         case 'simpleContent':   // (optional) content for a complexType\r
1520                         break;\r
1521                         case 'simpleType':\r
1522                                 array_push($this->simpleTypeStack, $this->currentSimpleType);\r
1523                                 if(isset($attrs['name'])){\r
1524                                         $this->xdebug("processing simpleType for name " . $attrs['name']);\r
1525                                         $this->currentSimpleType = $attrs['name'];\r
1526                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;\r
1527                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';\r
1528                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';\r
1529                                 } else {\r
1530                                         $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);\r
1531                                         $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);\r
1532                                         $this->currentSimpleType = $name;\r
1533                                         //$this->currentElement = false;\r
1534                                         $this->simpleTypes[$this->currentSimpleType] = $attrs;\r
1535                                         $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';\r
1536                                 }\r
1537                         break;\r
1538                         case 'union':   // simpleType type list\r
1539                         break;\r
1540                         default:\r
1541                                 //$this->xdebug("do not have anything to do for element $name");\r
1542                 }\r
1543         }\r
1544 \r
1545         /**\r
1546         * end-element handler\r
1547         *\r
1548         * @param    string $parser XML parser object\r
1549         * @param    string $name element name\r
1550         * @access   private\r
1551         */\r
1552         function schemaEndElement($parser, $name) {\r
1553                 // bring depth down a notch\r
1554                 $this->depth--;\r
1555                 // position of current element is equal to the last value left in depth_array for my depth\r
1556                 if(isset($this->depth_array[$this->depth])){\r
1557                 $pos = $this->depth_array[$this->depth];\r
1558         }\r
1559                 // get element prefix\r
1560                 if ($prefix = $this->getPrefix($name)){\r
1561                         // get unqualified name\r
1562                         $name = $this->getLocalPart($name);\r
1563                 } else {\r
1564                 $prefix = '';\r
1565         }\r
1566                 // move on...\r
1567                 if($name == 'complexType'){\r
1568                         $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));\r
1569                         $this->currentComplexType = array_pop($this->complexTypeStack);\r
1570                         //$this->currentElement = false;\r
1571                 }\r
1572                 if($name == 'element'){\r
1573                         $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));\r
1574                         $this->currentElement = array_pop($this->elementStack);\r
1575                 }\r
1576                 if($name == 'simpleType'){\r
1577                         $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));\r
1578                         $this->currentSimpleType = array_pop($this->simpleTypeStack);\r
1579                 }\r
1580         }\r
1581 \r
1582         /**\r
1583         * element content handler\r
1584         *\r
1585         * @param    string $parser XML parser object\r
1586         * @param    string $data element content\r
1587         * @access   private\r
1588         */\r
1589         function schemaCharacterData($parser, $data){\r
1590                 $pos = $this->depth_array[$this->depth - 1];\r
1591                 $this->message[$pos]['cdata'] .= $data;\r
1592         }\r
1593 \r
1594         /**\r
1595         * serialize the schema\r
1596         *\r
1597         * @access   public\r
1598         */\r
1599         function serializeSchema(){\r
1600 \r
1601                 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);\r
1602                 $xml = '';\r
1603                 // imports\r
1604                 if (sizeof($this->imports) > 0) {\r
1605                         foreach($this->imports as $ns => $list) {\r
1606                                 foreach ($list as $ii) {\r
1607                                         if ($ii['location'] != '') {\r
1608                                                 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";\r
1609                                         } else {\r
1610                                                 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";\r
1611                                         }\r
1612                                 }\r
1613                         } \r
1614                 } \r
1615                 // complex types\r
1616                 foreach($this->complexTypes as $typeName => $attrs){\r
1617                         $contentStr = '';\r
1618                         // serialize child elements\r
1619                         if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){\r
1620                                 foreach($attrs['elements'] as $element => $eParts){\r
1621                                         if(isset($eParts['ref'])){\r
1622                                                 $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";\r
1623                                         } else {\r
1624                                                 $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";\r
1625                                                 foreach ($eParts as $aName => $aValue) {\r
1626                                                         // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable\r
1627                                                         if ($aName != 'name' && $aName != 'type') {\r
1628                                                                 $contentStr .= " $aName=\"$aValue\"";\r
1629                                                         }\r
1630                                                 }\r
1631                                                 $contentStr .= "/>\n";\r
1632                                         }\r
1633                                 }\r
1634                                 // compositor wraps elements\r
1635                                 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {\r
1636                                         $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";\r
1637                                 }\r
1638                         }\r
1639                         // attributes\r
1640                         if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){\r
1641                                 foreach($attrs['attrs'] as $attr => $aParts){\r
1642                                         $contentStr .= "    <$schemaPrefix:attribute";\r
1643                                         foreach ($aParts as $a => $v) {\r
1644                                                 if ($a == 'ref' || $a == 'type') {\r
1645                                                         $contentStr .= " $a=\"".$this->contractQName($v).'"';\r
1646                                                 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {\r
1647                                                         $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];\r
1648                                                         $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';\r
1649                                                 } else {\r
1650                                                         $contentStr .= " $a=\"$v\"";\r
1651                                                 }\r
1652                                         }\r
1653                                         $contentStr .= "/>\n";\r
1654                                 }\r
1655                         }\r
1656                         // if restriction\r
1657                         if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){\r
1658                                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";\r
1659                                 // complex or simple content\r
1660                                 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){\r
1661                                         $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";\r
1662                                 }\r
1663                         }\r
1664                         // finalize complex type\r
1665                         if($contentStr != ''){\r
1666                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";\r
1667                         } else {\r
1668                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";\r
1669                         }\r
1670                         $xml .= $contentStr;\r
1671                 }\r
1672                 // simple types\r
1673                 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){\r
1674                         foreach($this->simpleTypes as $typeName => $eParts){\r
1675                                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";\r
1676                                 if (isset($eParts['enumeration'])) {\r
1677                                         foreach ($eParts['enumeration'] as $e) {\r
1678                                                 $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";\r
1679                                         }\r
1680                                 }\r
1681                                 $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";\r
1682                         }\r
1683                 }\r
1684                 // elements\r
1685                 if(isset($this->elements) && count($this->elements) > 0){\r
1686                         foreach($this->elements as $element => $eParts){\r
1687                                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";\r
1688                         }\r
1689                 }\r
1690                 // attributes\r
1691                 if(isset($this->attributes) && count($this->attributes) > 0){\r
1692                         foreach($this->attributes as $attr => $aParts){\r
1693                                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";\r
1694                         }\r
1695                 }\r
1696                 // finish 'er up\r
1697                 $attr = '';\r
1698                 foreach ($this->schemaInfo as $k => $v) {\r
1699                         if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {\r
1700                                 $attr .= " $k=\"$v\"";\r
1701                         }\r
1702                 }\r
1703                 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";\r
1704                 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {\r
1705                         $el .= " xmlns:$nsp=\"$ns\"";\r
1706                 }\r
1707                 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";\r
1708                 return $xml;\r
1709         }\r
1710 \r
1711         /**\r
1712         * adds debug data to the clas level debug string\r
1713         *\r
1714         * @param    string $string debug data\r
1715         * @access   private\r
1716         */\r
1717         function xdebug($string){\r
1718                 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);\r
1719         }\r
1720 \r
1721     /**\r
1722     * get the PHP type of a user defined type in the schema\r
1723     * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays\r
1724     * returns false if no type exists, or not w/ the given namespace\r
1725     * else returns a string that is either a native php type, or 'struct'\r
1726     *\r
1727     * @param string $type name of defined type\r
1728     * @param string $ns namespace of type\r
1729     * @return mixed\r
1730     * @access public\r
1731     * @deprecated\r
1732     */\r
1733         function getPHPType($type,$ns){\r
1734                 if(isset($this->typemap[$ns][$type])){\r
1735                         //print "found type '$type' and ns $ns in typemap<br>";\r
1736                         return $this->typemap[$ns][$type];\r
1737                 } elseif(isset($this->complexTypes[$type])){\r
1738                         //print "getting type '$type' and ns $ns from complexTypes array<br>";\r
1739                         return $this->complexTypes[$type]['phpType'];\r
1740                 }\r
1741                 return false;\r
1742         }\r
1743 \r
1744         /**\r
1745     * returns an associative array of information about a given type\r
1746     * returns false if no type exists by the given name\r
1747     *\r
1748         *       For a complexType typeDef = array(\r
1749         *       'restrictionBase' => '',\r
1750         *       'phpType' => '',\r
1751         *       'compositor' => '(sequence|all)',\r
1752         *       'elements' => array(), // refs to elements array\r
1753         *       'attrs' => array() // refs to attributes array\r
1754         *       ... and so on (see addComplexType)\r
1755         *       )\r
1756         *\r
1757         *   For simpleType or element, the array has different keys.\r
1758     *\r
1759     * @param string $type\r
1760     * @return mixed\r
1761     * @access public\r
1762     * @see addComplexType\r
1763     * @see addSimpleType\r
1764     * @see addElement\r
1765     */\r
1766         function getTypeDef($type){\r
1767                 //$this->debug("in getTypeDef for type $type");\r
1768                 if (substr($type, -1) == '^') {\r
1769                         $is_element = 1;\r
1770                         $type = substr($type, 0, -1);\r
1771                 } else {\r
1772                         $is_element = 0;\r
1773                 }\r
1774 \r
1775                 if((! $is_element) && isset($this->complexTypes[$type])){\r
1776                         $this->xdebug("in getTypeDef, found complexType $type");\r
1777                         return $this->complexTypes[$type];\r
1778                 } elseif((! $is_element) && isset($this->simpleTypes[$type])){\r
1779                         $this->xdebug("in getTypeDef, found simpleType $type");\r
1780                         if (!isset($this->simpleTypes[$type]['phpType'])) {\r
1781                                 // get info for type to tack onto the simple type\r
1782                                 // TODO: can this ever really apply (i.e. what is a simpleType really?)\r
1783                                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);\r
1784                                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));\r
1785                                 $etype = $this->getTypeDef($uqType);\r
1786                                 if ($etype) {\r
1787                                         $this->xdebug("in getTypeDef, found type for simpleType $type:");\r
1788                                         $this->xdebug($this->varDump($etype));\r
1789                                         if (isset($etype['phpType'])) {\r
1790                                                 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];\r
1791                                         }\r
1792                                         if (isset($etype['elements'])) {\r
1793                                                 $this->simpleTypes[$type]['elements'] = $etype['elements'];\r
1794                                         }\r
1795                                 }\r
1796                         }\r
1797                         return $this->simpleTypes[$type];\r
1798                 } elseif(isset($this->elements[$type])){\r
1799                         $this->xdebug("in getTypeDef, found element $type");\r
1800                         if (!isset($this->elements[$type]['phpType'])) {\r
1801                                 // get info for type to tack onto the element\r
1802                                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);\r
1803                                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));\r
1804                                 $etype = $this->getTypeDef($uqType);\r
1805                                 if ($etype) {\r
1806                                         $this->xdebug("in getTypeDef, found type for element $type:");\r
1807                                         $this->xdebug($this->varDump($etype));\r
1808                                         if (isset($etype['phpType'])) {\r
1809                                                 $this->elements[$type]['phpType'] = $etype['phpType'];\r
1810                                         }\r
1811                                         if (isset($etype['elements'])) {\r
1812                                                 $this->elements[$type]['elements'] = $etype['elements'];\r
1813                                         }\r
1814                                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {\r
1815                                         $this->xdebug("in getTypeDef, element $type is an XSD type");\r
1816                                         $this->elements[$type]['phpType'] = 'scalar';\r
1817                                 }\r
1818                         }\r
1819                         return $this->elements[$type];\r
1820                 } elseif(isset($this->attributes[$type])){\r
1821                         $this->xdebug("in getTypeDef, found attribute $type");\r
1822                         return $this->attributes[$type];\r
1823                 } elseif (ereg('_ContainedType$', $type)) {\r
1824                         $this->xdebug("in getTypeDef, have an untyped element $type");\r
1825                         $typeDef['typeClass'] = 'simpleType';\r
1826                         $typeDef['phpType'] = 'scalar';\r
1827                         $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';\r
1828                         return $typeDef;\r
1829                 }\r
1830                 $this->xdebug("in getTypeDef, did not find $type");\r
1831                 return false;\r
1832         }\r
1833 \r
1834         /**\r
1835     * returns a sample serialization of a given type, or false if no type by the given name\r
1836     *\r
1837     * @param string $type name of type\r
1838     * @return mixed\r
1839     * @access public\r
1840     * @deprecated\r
1841     */\r
1842     function serializeTypeDef($type){\r
1843         //print "in sTD() for type $type<br>";\r
1844         if($typeDef = $this->getTypeDef($type)){\r
1845                 $str .= '<'.$type;\r
1846             if(is_array($typeDef['attrs'])){\r
1847                 foreach($typeDef['attrs'] as $attName => $data){\r
1848                     $str .= " $attName=\"{type = ".$data['type']."}\"";\r
1849                 }\r
1850             }\r
1851             $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";\r
1852             if(count($typeDef['elements']) > 0){\r
1853                 $str .= ">";\r
1854                 foreach($typeDef['elements'] as $element => $eData){\r
1855                     $str .= $this->serializeTypeDef($element);\r
1856                 }\r
1857                 $str .= "</$type>";\r
1858             } elseif($typeDef['typeClass'] == 'element') {\r
1859                 $str .= "></$type>";\r
1860             } else {\r
1861                 $str .= "/>";\r
1862             }\r
1863                         return $str;\r
1864         }\r
1865         return false;\r
1866     }\r
1867 \r
1868     /**\r
1869     * returns HTML form elements that allow a user\r
1870     * to enter values for creating an instance of the given type.\r
1871     *\r
1872     * @param string $name name for type instance\r
1873     * @param string $type name of type\r
1874     * @return string\r
1875     * @access public\r
1876     * @deprecated\r
1877         */\r
1878         function typeToForm($name,$type){\r
1879                 // get typedef\r
1880                 if($typeDef = $this->getTypeDef($type)){\r
1881                         // if struct\r
1882                         if($typeDef['phpType'] == 'struct'){\r
1883                                 $buffer .= '<table>';\r
1884                                 foreach($typeDef['elements'] as $child => $childDef){\r
1885                                         $buffer .= "\r
1886                                         <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>\r
1887                                         <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";\r
1888                                 }\r
1889                                 $buffer .= '</table>';\r
1890                         // if array\r
1891                         } elseif($typeDef['phpType'] == 'array'){\r
1892                                 $buffer .= '<table>';\r
1893                                 for($i=0;$i < 3; $i++){\r
1894                                         $buffer .= "\r
1895                                         <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>\r
1896                                         <td><input type='text' name='parameters[".$name."][]'></td></tr>";\r
1897                                 }\r
1898                                 $buffer .= '</table>';\r
1899                         // if scalar\r
1900                         } else {\r
1901                                 $buffer .= "<input type='text' name='parameters[$name]'>";\r
1902                         }\r
1903                 } else {\r
1904                         $buffer .= "<input type='text' name='parameters[$name]'>";\r
1905                 }\r
1906                 return $buffer;\r
1907         }\r
1908         \r
1909         /**\r
1910         * adds a complex type to the schema\r
1911         * \r
1912         * example: array\r
1913         * \r
1914         * addType(\r
1915         *       'ArrayOfstring',\r
1916         *       'complexType',\r
1917         *       'array',\r
1918         *       '',\r
1919         *       'SOAP-ENC:Array',\r
1920         *       array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),\r
1921         *       'xsd:string'\r
1922         * );\r
1923         * \r
1924         * example: PHP associative array ( SOAP Struct )\r
1925         * \r
1926         * addType(\r
1927         *       'SOAPStruct',\r
1928         *       'complexType',\r
1929         *       'struct',\r
1930         *       'all',\r
1931         *       array('myVar'=> array('name'=>'myVar','type'=>'string')\r
1932         * );\r
1933         * \r
1934         * @param name\r
1935         * @param typeClass (complexType|simpleType|attribute)\r
1936         * @param phpType: currently supported are array and struct (php assoc array)\r
1937         * @param compositor (all|sequence|choice)\r
1938         * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)\r
1939         * @param elements = array ( name = array(name=>'',type=>'') )\r
1940         * @param attrs = array(\r
1941         *       array(\r
1942         *               'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",\r
1943         *               "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"\r
1944         *       )\r
1945         * )\r
1946         * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)\r
1947         * @access public\r
1948         * @see getTypeDef\r
1949         */\r
1950         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){\r
1951                 $this->complexTypes[$name] = array(\r
1952             'name'              => $name,\r
1953             'typeClass' => $typeClass,\r
1954             'phpType'   => $phpType,\r
1955                 'compositor'=> $compositor,\r
1956             'restrictionBase' => $restrictionBase,\r
1957                 'elements'      => $elements,\r
1958             'attrs'             => $attrs,\r
1959             'arrayType' => $arrayType\r
1960                 );\r
1961                 \r
1962                 $this->xdebug("addComplexType $name:");\r
1963                 $this->appendDebug($this->varDump($this->complexTypes[$name]));\r
1964         }\r
1965         \r
1966         /**\r
1967         * adds a simple type to the schema\r
1968         *\r
1969         * @param string $name\r
1970         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)\r
1971         * @param string $typeClass (should always be simpleType)\r
1972         * @param string $phpType (should always be scalar)\r
1973         * @param array $enumeration array of values\r
1974         * @access public\r
1975         * @see nusoap_xmlschema\r
1976         * @see getTypeDef\r
1977         */\r
1978         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {\r
1979                 $this->simpleTypes[$name] = array(\r
1980             'name'                      => $name,\r
1981             'typeClass'         => $typeClass,\r
1982             'phpType'           => $phpType,\r
1983             'type'                      => $restrictionBase,\r
1984             'enumeration'       => $enumeration\r
1985                 );\r
1986                 \r
1987                 $this->xdebug("addSimpleType $name:");\r
1988                 $this->appendDebug($this->varDump($this->simpleTypes[$name]));\r
1989         }\r
1990 \r
1991         /**\r
1992         * adds an element to the schema\r
1993         *\r
1994         * @param array $attrs attributes that must include name and type\r
1995         * @see nusoap_xmlschema\r
1996         * @access public\r
1997         */\r
1998         function addElement($attrs) {\r
1999                 if (! $this->getPrefix($attrs['type'])) {\r
2000                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];\r
2001                 }\r
2002                 $this->elements[ $attrs['name'] ] = $attrs;\r
2003                 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';\r
2004                 \r
2005                 $this->xdebug("addElement " . $attrs['name']);\r
2006                 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));\r
2007         }\r
2008 }\r
2009 \r
2010 /**\r
2011  * Backward compatibility\r
2012  */\r
2013 class XMLSchema extends nusoap_xmlschema {\r
2014 }\r
2015 \r
2016 ?><?php\r
2017 \r
2018 \r
2019 \r
2020 /**\r
2021 * For creating serializable abstractions of native PHP types.  This class\r
2022 * allows element name/namespace, XSD type, and XML attributes to be\r
2023 * associated with a value.  This is extremely useful when WSDL is not\r
2024 * used, but is also useful when WSDL is used with polymorphic types, including\r
2025 * xsd:anyType and user-defined types.\r
2026 *\r
2027 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
2028 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
2029 * @access   public\r
2030 */\r
2031 class soapval extends nusoap_base {\r
2032         /**\r
2033          * The XML element name\r
2034          *\r
2035          * @var string\r
2036          * @access private\r
2037          */\r
2038         var $name;\r
2039         /**\r
2040          * The XML type name (string or false)\r
2041          *\r
2042          * @var mixed\r
2043          * @access private\r
2044          */\r
2045         var $type;\r
2046         /**\r
2047          * The PHP value\r
2048          *\r
2049          * @var mixed\r
2050          * @access private\r
2051          */\r
2052         var $value;\r
2053         /**\r
2054          * The XML element namespace (string or false)\r
2055          *\r
2056          * @var mixed\r
2057          * @access private\r
2058          */\r
2059         var $element_ns;\r
2060         /**\r
2061          * The XML type namespace (string or false)\r
2062          *\r
2063          * @var mixed\r
2064          * @access private\r
2065          */\r
2066         var $type_ns;\r
2067         /**\r
2068          * The XML element attributes (array or false)\r
2069          *\r
2070          * @var mixed\r
2071          * @access private\r
2072          */\r
2073         var $attributes;\r
2074 \r
2075         /**\r
2076         * constructor\r
2077         *\r
2078         * @param    string $name optional name\r
2079         * @param    mixed $type optional type name\r
2080         * @param        mixed $value optional value\r
2081         * @param        mixed $element_ns optional namespace of value\r
2082         * @param        mixed $type_ns optional namespace of type\r
2083         * @param        mixed $attributes associative array of attributes to add to element serialization\r
2084         * @access   public\r
2085         */\r
2086         function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {\r
2087                 parent::nusoap_base();\r
2088                 $this->name = $name;\r
2089                 $this->type = $type;\r
2090                 $this->value = $value;\r
2091                 $this->element_ns = $element_ns;\r
2092                 $this->type_ns = $type_ns;\r
2093                 $this->attributes = $attributes;\r
2094     }\r
2095 \r
2096         /**\r
2097         * return serialized value\r
2098         *\r
2099         * @param        string $use The WSDL use value (encoded|literal)\r
2100         * @return       string XML data\r
2101         * @access   public\r
2102         */\r
2103         function serialize($use='encoded') {\r
2104                 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);\r
2105     }\r
2106 \r
2107         /**\r
2108         * decodes a soapval object into a PHP native type\r
2109         *\r
2110         * @return       mixed\r
2111         * @access   public\r
2112         */\r
2113         function decode(){\r
2114                 return $this->value;\r
2115         }\r
2116 }\r
2117 \r
2118 \r
2119 \r
2120 ?><?php\r
2121 \r
2122 \r
2123 \r
2124 /**\r
2125 * transport class for sending/receiving data via HTTP and HTTPS\r
2126 * NOTE: PHP must be compiled with the CURL extension for HTTPS support\r
2127 *\r
2128 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
2129 * @author   Scott Nichol <snichol@users.sourceforge.net>\r
2130 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
2131 * @access public\r
2132 */\r
2133 class soap_transport_http extends nusoap_base {\r
2134 \r
2135         var $url = '';\r
2136         var $uri = '';\r
2137         var $digest_uri = '';\r
2138         var $scheme = '';\r
2139         var $host = '';\r
2140         var $port = '';\r
2141         var $path = '';\r
2142         var $request_method = 'POST';\r
2143         var $protocol_version = '1.0';\r
2144         var $encoding = '';\r
2145         var $outgoing_headers = array();\r
2146         var $incoming_headers = array();\r
2147         var $incoming_cookies = array();\r
2148         var $outgoing_payload = '';\r
2149         var $incoming_payload = '';\r
2150         var $response_status_line;      // HTTP response status line\r
2151         var $useSOAPAction = true;\r
2152         var $persistentConnection = false;\r
2153         var $ch = false;        // cURL handle\r
2154         var $ch_options = array();      // cURL custom options\r
2155         var $use_curl = false;          // force cURL use\r
2156         var $proxy = null;                      // proxy information (associative array)\r
2157         var $username = '';\r
2158         var $password = '';\r
2159         var $authtype = '';\r
2160         var $digestRequest = array();\r
2161         var $certRequest = array();     // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)\r
2162                                                                 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'\r
2163                                                                 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'\r
2164                                                                 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'\r
2165                                                                 // passphrase: SSL key password/passphrase\r
2166                                                                 // certpassword: SSL certificate password\r
2167                                                                 // verifypeer: default is 1\r
2168                                                                 // verifyhost: default is 1\r
2169 \r
2170         /**\r
2171         * constructor\r
2172         *\r
2173         * @param string $url The URL to which to connect\r
2174         * @param array $curl_options User-specified cURL options\r
2175         * @param boolean $use_curl Whether to try to force cURL use\r
2176         * @access public\r
2177         */\r
2178         function soap_transport_http($url, $curl_options = NULL, $use_curl = false){\r
2179                 parent::nusoap_base();\r
2180                 $this->debug("ctor url=$url use_curl=$use_curl curl_options:");\r
2181                 $this->appendDebug($this->varDump($curl_options));\r
2182                 $this->setURL($url);\r
2183                 if (is_array($curl_options)) {\r
2184                         $this->ch_options = $curl_options;\r
2185                 }\r
2186                 $this->use_curl = $use_curl;\r
2187                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);\r
2188                 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');\r
2189         }\r
2190 \r
2191         /**\r
2192         * sets a cURL option\r
2193         *\r
2194         * @param        mixed $option The cURL option (always integer?)\r
2195         * @param        mixed $value The cURL option value\r
2196         * @access   private\r
2197         */\r
2198         function setCurlOption($option, $value) {\r
2199                 $this->debug("setCurlOption option=$option, value=");\r
2200                 $this->appendDebug($this->varDump($value));\r
2201                 curl_setopt($this->ch, $option, $value);\r
2202         }\r
2203 \r
2204         /**\r
2205         * sets an HTTP header\r
2206         *\r
2207         * @param string $name The name of the header\r
2208         * @param string $value The value of the header\r
2209         * @access private\r
2210         */\r
2211         function setHeader($name, $value) {\r
2212                 $this->outgoing_headers[$name] = $value;\r
2213                 $this->debug("set header $name: $value");\r
2214         }\r
2215 \r
2216         /**\r
2217         * unsets an HTTP header\r
2218         *\r
2219         * @param string $name The name of the header\r
2220         * @access private\r
2221         */\r
2222         function unsetHeader($name) {\r
2223                 if (isset($this->outgoing_headers[$name])) {\r
2224                         $this->debug("unset header $name");\r
2225                         unset($this->outgoing_headers[$name]);\r
2226                 }\r
2227         }\r
2228 \r
2229         /**\r
2230         * sets the URL to which to connect\r
2231         *\r
2232         * @param string $url The URL to which to connect\r
2233         * @access private\r
2234         */\r
2235         function setURL($url) {\r
2236                 $this->url = $url;\r
2237 \r
2238                 $u = parse_url($url);\r
2239                 foreach($u as $k => $v){\r
2240                         $this->debug("parsed URL $k = $v");\r
2241                         $this->$k = $v;\r
2242                 }\r
2243                 \r
2244                 // add any GET params to path\r
2245                 if(isset($u['query']) && $u['query'] != ''){\r
2246             $this->path .= '?' . $u['query'];\r
2247                 }\r
2248                 \r
2249                 // set default port\r
2250                 if(!isset($u['port'])){\r
2251                         if($u['scheme'] == 'https'){\r
2252                                 $this->port = 443;\r
2253                         } else {\r
2254                                 $this->port = 80;\r
2255                         }\r
2256                 }\r
2257                 \r
2258                 $this->uri = $this->path;\r
2259                 $this->digest_uri = $this->uri;\r
2260                 \r
2261                 // build headers\r
2262                 if (!isset($u['port'])) {\r
2263                         $this->setHeader('Host', $this->host);\r
2264                 } else {\r
2265                         $this->setHeader('Host', $this->host.':'.$this->port);\r
2266                 }\r
2267 \r
2268                 if (isset($u['user']) && $u['user'] != '') {\r
2269                         $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');\r
2270                 }\r
2271         }\r
2272 \r
2273         /**\r
2274         * gets the I/O method to use\r
2275         *\r
2276         * @return       string  I/O method to use (socket|curl|unknown)\r
2277         * @access       private\r
2278         */\r
2279         function io_method() {\r
2280                 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))\r
2281                         return 'curl';\r
2282                 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))\r
2283                         return 'socket';\r
2284                 return 'unknown';\r
2285         }\r
2286 \r
2287         /**\r
2288         * establish an HTTP connection\r
2289         *\r
2290         * @param    integer $timeout set connection timeout in seconds\r
2291         * @param        integer $response_timeout set response timeout in seconds\r
2292         * @return       boolean true if connected, false if not\r
2293         * @access   private\r
2294         */\r
2295         function connect($connection_timeout=0,$response_timeout=30){\r
2296                 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like\r
2297                 // "regular" socket.\r
2298                 // TODO: disabled for now because OpenSSL must be *compiled* in (not just\r
2299                 //       loaded), and until PHP5 stream_get_wrappers is not available.\r
2300 //              if ($this->scheme == 'https') {\r
2301 //                      if (version_compare(phpversion(), '4.3.0') >= 0) {\r
2302 //                              if (extension_loaded('openssl')) {\r
2303 //                                      $this->scheme = 'ssl';\r
2304 //                                      $this->debug('Using SSL over OpenSSL');\r
2305 //                              }\r
2306 //                      }\r
2307 //              }\r
2308                 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");\r
2309           if ($this->io_method() == 'socket') {\r
2310                 if (!is_array($this->proxy)) {\r
2311                         $host = $this->host;\r
2312                         $port = $this->port;\r
2313                 } else {\r
2314                         $host = $this->proxy['host'];\r
2315                         $port = $this->proxy['port'];\r
2316                 }\r
2317 \r
2318                 // use persistent connection\r
2319                 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){\r
2320                         if (!feof($this->fp)) {\r
2321                                 $this->debug('Re-use persistent connection');\r
2322                                 return true;\r
2323                         }\r
2324                         fclose($this->fp);\r
2325                         $this->debug('Closed persistent connection at EOF');\r
2326                 }\r
2327 \r
2328                 // munge host if using OpenSSL\r
2329                 if ($this->scheme == 'ssl') {\r
2330                         $host = 'ssl://' . $host;\r
2331                 }\r
2332                 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);\r
2333 \r
2334                 // open socket\r
2335                 if($connection_timeout > 0){\r
2336                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);\r
2337                 } else {\r
2338                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);\r
2339                 }\r
2340                 \r
2341                 // test pointer\r
2342                 if(!$this->fp) {\r
2343                         $msg = 'Couldn\'t open socket connection to server ' . $this->url;\r
2344                         if ($this->errno) {\r
2345                                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;\r
2346                         } else {\r
2347                                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';\r
2348                         }\r
2349                         $this->debug($msg);\r
2350                         $this->setError($msg);\r
2351                         return false;\r
2352                 }\r
2353                 \r
2354                 // set response timeout\r
2355                 $this->debug('set response timeout to ' . $response_timeout);\r
2356                 socket_set_timeout( $this->fp, $response_timeout);\r
2357 \r
2358                 $this->debug('socket connected');\r
2359                 return true;\r
2360           } else if ($this->io_method() == 'curl') {\r
2361                 if (!extension_loaded('curl')) {\r
2362 //                      $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');\r
2363                         $this->setError('The PHP cURL Extension is required for HTTPS or NLTM.  You will need to re-build or update your PHP to included cURL.');\r
2364                         return false;\r
2365                 }\r
2366                 // Avoid warnings when PHP does not have these options\r
2367                 if (defined('CURLOPT_CONNECTIONTIMEOUT'))\r
2368                         $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;\r
2369                 else\r
2370                         $CURLOPT_CONNECTIONTIMEOUT = 78;\r
2371                 if (defined('CURLOPT_HTTPAUTH'))\r
2372                         $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;\r
2373                 else\r
2374                         $CURLOPT_HTTPAUTH = 107;\r
2375                 if (defined('CURLOPT_PROXYAUTH'))\r
2376                         $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;\r
2377                 else\r
2378                         $CURLOPT_PROXYAUTH = 111;\r
2379                 if (defined('CURLAUTH_BASIC'))\r
2380                         $CURLAUTH_BASIC = CURLAUTH_BASIC;\r
2381                 else\r
2382                         $CURLAUTH_BASIC = 1;\r
2383                 if (defined('CURLAUTH_DIGEST'))\r
2384                         $CURLAUTH_DIGEST = CURLAUTH_DIGEST;\r
2385                 else\r
2386                         $CURLAUTH_DIGEST = 2;\r
2387                 if (defined('CURLAUTH_NTLM'))\r
2388                         $CURLAUTH_NTLM = CURLAUTH_NTLM;\r
2389                 else\r
2390                         $CURLAUTH_NTLM = 8;\r
2391 \r
2392                 $this->debug('connect using cURL');\r
2393                 // init CURL\r
2394                 $this->ch = curl_init();\r
2395                 // set url\r
2396                 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";\r
2397                 // add path\r
2398                 $hostURL .= $this->path;\r
2399                 $this->setCurlOption(CURLOPT_URL, $hostURL);\r
2400                 // follow location headers (re-directs)\r
2401                 if (ini_get('safe_mode') || ini_get('open_basedir')) {\r
2402                         $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');\r
2403                         $this->debug('safe_mode = ');\r
2404                         $this->appendDebug($this->varDump(ini_get('safe_mode')));\r
2405                         $this->debug('open_basedir = ');\r
2406                         $this->appendDebug($this->varDump(ini_get('open_basedir')));\r
2407                 } else {\r
2408                         $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);\r
2409                 }\r
2410                 // ask for headers in the response output\r
2411                 $this->setCurlOption(CURLOPT_HEADER, 1);\r
2412                 // ask for the response output as the return value\r
2413                 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);\r
2414                 // encode\r
2415                 // We manage this ourselves through headers and encoding\r
2416 //              if(function_exists('gzuncompress')){\r
2417 //                      $this->setCurlOption(CURLOPT_ENCODING, 'deflate');\r
2418 //              }\r
2419                 // persistent connection\r
2420                 if ($this->persistentConnection) {\r
2421                         // I believe the following comment is now bogus, having applied to\r
2422                         // the code when it used CURLOPT_CUSTOMREQUEST to send the request.\r
2423                         // The way we send data, we cannot use persistent connections, since\r
2424                         // there will be some "junk" at the end of our request.\r
2425                         //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);\r
2426                         $this->persistentConnection = false;\r
2427                         $this->setHeader('Connection', 'close');\r
2428                 }\r
2429                 // set timeouts\r
2430                 if ($connection_timeout != 0) {\r
2431                         $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);\r
2432                 }\r
2433                 if ($response_timeout != 0) {\r
2434                         $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);\r
2435                 }\r
2436 \r
2437                 if ($this->scheme == 'https') {\r
2438                         $this->debug('set cURL SSL verify options');\r
2439                         // recent versions of cURL turn on peer/host checking by default,\r
2440                         // while PHP binaries are not compiled with a default location for the\r
2441                         // CA cert bundle, so disable peer/host checking.\r
2442                         //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');             \r
2443                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);\r
2444                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);\r
2445         \r
2446                         // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)\r
2447                         if ($this->authtype == 'certificate') {\r
2448                                 $this->debug('set cURL certificate options');\r
2449                                 if (isset($this->certRequest['cainfofile'])) {\r
2450                                         $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);\r
2451                                 }\r
2452                                 if (isset($this->certRequest['verifypeer'])) {\r
2453                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);\r
2454                                 } else {\r
2455                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);\r
2456                                 }\r
2457                                 if (isset($this->certRequest['verifyhost'])) {\r
2458                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);\r
2459                                 } else {\r
2460                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);\r
2461                                 }\r
2462                                 if (isset($this->certRequest['sslcertfile'])) {\r
2463                                         $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);\r
2464                                 }\r
2465                                 if (isset($this->certRequest['sslkeyfile'])) {\r
2466                                         $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);\r
2467                                 }\r
2468                                 if (isset($this->certRequest['passphrase'])) {\r
2469                                         $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);\r
2470                                 }\r
2471                                 if (isset($this->certRequest['certpassword'])) {\r
2472                                         $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);\r
2473                                 }\r
2474                         }\r
2475                 }\r
2476                 if ($this->authtype && ($this->authtype != 'certificate')) {\r
2477                         if ($this->username) {\r
2478                                 $this->debug('set cURL username/password');\r
2479                                 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");\r
2480                         }\r
2481                         if ($this->authtype == 'basic') {\r
2482                                 $this->debug('set cURL for Basic authentication');\r
2483                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);\r
2484                         }\r
2485                         if ($this->authtype == 'digest') {\r
2486                                 $this->debug('set cURL for digest authentication');\r
2487                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);\r
2488                         }\r
2489                         if ($this->authtype == 'ntlm') {\r
2490                                 $this->debug('set cURL for NTLM authentication');\r
2491                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);\r
2492                         }\r
2493                 }\r
2494                 if (is_array($this->proxy)) {\r
2495                         $this->debug('set cURL proxy options');\r
2496                         if ($this->proxy['port'] != '') {\r
2497                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);\r
2498                         } else {\r
2499                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);\r
2500                         }\r
2501                         if ($this->proxy['username'] || $this->proxy['password']) {\r
2502                                 $this->debug('set cURL proxy authentication options');\r
2503                                 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);\r
2504                                 if ($this->proxy['authtype'] == 'basic') {\r
2505                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);\r
2506                                 }\r
2507                                 if ($this->proxy['authtype'] == 'ntlm') {\r
2508                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);\r
2509                                 }\r
2510                         }\r
2511                 }\r
2512                 $this->debug('cURL connection set up');\r
2513                 return true;\r
2514           } else {\r
2515                 $this->setError('Unknown scheme ' . $this->scheme);\r
2516                 $this->debug('Unknown scheme ' . $this->scheme);\r
2517                 return false;\r
2518           }\r
2519         }\r
2520 \r
2521         /**\r
2522         * sends the SOAP request and gets the SOAP response via HTTP[S]\r
2523         *\r
2524         * @param    string $data message data\r
2525         * @param    integer $timeout set connection timeout in seconds\r
2526         * @param        integer $response_timeout set response timeout in seconds\r
2527         * @param        array $cookies cookies to send\r
2528         * @return       string data\r
2529         * @access   public\r
2530         */\r
2531         function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {\r
2532                 \r
2533                 $this->debug('entered send() with data of length: '.strlen($data));\r
2534 \r
2535                 $this->tryagain = true;\r
2536                 $tries = 0;\r
2537                 while ($this->tryagain) {\r
2538                         $this->tryagain = false;\r
2539                         if ($tries++ < 2) {\r
2540                                 // make connnection\r
2541                                 if (!$this->connect($timeout, $response_timeout)){\r
2542                                         return false;\r
2543                                 }\r
2544                                 \r
2545                                 // send request\r
2546                                 if (!$this->sendRequest($data, $cookies)){\r
2547                                         return false;\r
2548                                 }\r
2549                                 \r
2550                                 // get response\r
2551                                 $respdata = $this->getResponse();\r
2552                         } else {\r
2553                                 $this->setError("Too many tries to get an OK response ($this->response_status_line)");\r
2554                         }\r
2555                 }               \r
2556                 $this->debug('end of send()');\r
2557                 return $respdata;\r
2558         }\r
2559 \r
2560 \r
2561         /**\r
2562         * sends the SOAP request and gets the SOAP response via HTTPS using CURL\r
2563         *\r
2564         * @param    string $data message data\r
2565         * @param    integer $timeout set connection timeout in seconds\r
2566         * @param        integer $response_timeout set response timeout in seconds\r
2567         * @param        array $cookies cookies to send\r
2568         * @return       string data\r
2569         * @access   public\r
2570         * @deprecated\r
2571         */\r
2572         function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {\r
2573                 return $this->send($data, $timeout, $response_timeout, $cookies);\r
2574         }\r
2575         \r
2576         /**\r
2577         * if authenticating, set user credentials here\r
2578         *\r
2579         * @param    string $username\r
2580         * @param    string $password\r
2581         * @param        string $authtype (basic|digest|certificate|ntlm)\r
2582         * @param        array $digestRequest (keys must be nonce, nc, realm, qop)\r
2583         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)\r
2584         * @access   public\r
2585         */\r
2586         function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {\r
2587                 $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");\r
2588                 $this->appendDebug($this->varDump($digestRequest));\r
2589                 $this->debug("certRequest=");\r
2590                 $this->appendDebug($this->varDump($certRequest));\r
2591                 // cf. RFC 2617\r
2592                 if ($authtype == 'basic') {\r
2593                         $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));\r
2594                 } elseif ($authtype == 'digest') {\r
2595                         if (isset($digestRequest['nonce'])) {\r
2596                                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;\r
2597                                 \r
2598                                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)\r
2599         \r
2600                                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd\r
2601                                 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;\r
2602         \r
2603                                 // H(A1) = MD5(A1)\r
2604                                 $HA1 = md5($A1);\r
2605         \r
2606                                 // A2 = Method ":" digest-uri-value\r
2607                                 $A2 = $this->request_method . ':' . $this->digest_uri;\r
2608         \r
2609                                 // H(A2)\r
2610                                 $HA2 =  md5($A2);\r
2611         \r
2612                                 // KD(secret, data) = H(concat(secret, ":", data))\r
2613                                 // if qop == auth:\r
2614                                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)\r
2615                                 //                              ":" nc-value\r
2616                                 //                              ":" unq(cnonce-value)\r
2617                                 //                              ":" unq(qop-value)\r
2618                                 //                              ":" H(A2)\r
2619                                 //                            ) <">\r
2620                                 // if qop is missing,\r
2621                                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">\r
2622         \r
2623                                 $unhashedDigest = '';\r
2624                                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';\r
2625                                 $cnonce = $nonce;\r
2626                                 if ($digestRequest['qop'] != '') {\r
2627                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;\r
2628                                 } else {\r
2629                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;\r
2630                                 }\r
2631         \r
2632                                 $hashedDigest = md5($unhashedDigest);\r
2633         \r
2634                                 $opaque = '';   \r
2635                                 if (isset($digestRequest['opaque'])) {\r
2636                                         $opaque = ', opaque="' . $digestRequest['opaque'] . '"';\r
2637                                 }\r
2638 \r
2639                                 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');\r
2640                         }\r
2641                 } elseif ($authtype == 'certificate') {\r
2642                         $this->certRequest = $certRequest;\r
2643                         $this->debug('Authorization header not set for certificate');\r
2644                 } elseif ($authtype == 'ntlm') {\r
2645                         // do nothing\r
2646                         $this->debug('Authorization header not set for ntlm');\r
2647                 }\r
2648                 $this->username = $username;\r
2649                 $this->password = $password;\r
2650                 $this->authtype = $authtype;\r
2651                 $this->digestRequest = $digestRequest;\r
2652         }\r
2653         \r
2654         /**\r
2655         * set the soapaction value\r
2656         *\r
2657         * @param    string $soapaction\r
2658         * @access   public\r
2659         */\r
2660         function setSOAPAction($soapaction) {\r
2661                 $this->setHeader('SOAPAction', '"' . $soapaction . '"');\r
2662         }\r
2663         \r
2664         /**\r
2665         * use http encoding\r
2666         *\r
2667         * @param    string $enc encoding style. supported values: gzip, deflate, or both\r
2668         * @access   public\r
2669         */\r
2670         function setEncoding($enc='gzip, deflate') {\r
2671                 if (function_exists('gzdeflate')) {\r
2672                         $this->protocol_version = '1.1';\r
2673                         $this->setHeader('Accept-Encoding', $enc);\r
2674                         if (!isset($this->outgoing_headers['Connection'])) {\r
2675                                 $this->setHeader('Connection', 'close');\r
2676                                 $this->persistentConnection = false;\r
2677                         }\r
2678                         set_magic_quotes_runtime(0);\r
2679                         // deprecated\r
2680                         $this->encoding = $enc;\r
2681                 }\r
2682         }\r
2683         \r
2684         /**\r
2685         * set proxy info here\r
2686         *\r
2687         * @param    string $proxyhost use an empty string to remove proxy\r
2688         * @param    string $proxyport\r
2689         * @param        string $proxyusername\r
2690         * @param        string $proxypassword\r
2691         * @param        string $proxyauthtype (basic|ntlm)\r
2692         * @access   public\r
2693         */\r
2694         function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {\r
2695                 if ($proxyhost) {\r
2696                         $this->proxy = array(\r
2697                                 'host' => $proxyhost,\r
2698                                 'port' => $proxyport,\r
2699                                 'username' => $proxyusername,\r
2700                                 'password' => $proxypassword,\r
2701                                 'authtype' => $proxyauthtype\r
2702                         );\r
2703                         if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {\r
2704                                 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));\r
2705                         }\r
2706                 } else {\r
2707                         $this->debug('remove proxy');\r
2708                         $proxy = null;\r
2709                         unsetHeader('Proxy-Authorization');\r
2710                 }\r
2711         }\r
2712         \r
2713 \r
2714         /**\r
2715          * Test if the given string starts with a header that is to be skipped.\r
2716          * Skippable headers result from chunked transfer and proxy requests.\r
2717          *\r
2718          * @param       string $data The string to check.\r
2719          * @returns     boolean Whether a skippable header was found.\r
2720          * @access      private\r
2721          */\r
2722         function isSkippableCurlHeader(&$data) {\r
2723                 $skipHeaders = array(   'HTTP/1.1 100',\r
2724                                                                 'HTTP/1.0 301',\r
2725                                                                 'HTTP/1.1 301',\r
2726                                                                 'HTTP/1.0 302',\r
2727                                                                 'HTTP/1.1 302',\r
2728                                                                 'HTTP/1.0 401',\r
2729                                                                 'HTTP/1.1 401',\r
2730                                                                 'HTTP/1.0 200 Connection established');\r
2731                 foreach ($skipHeaders as $hd) {\r
2732                         $prefix = substr($data, 0, strlen($hd));\r
2733                         if ($prefix == $hd) return true;\r
2734                 }\r
2735 \r
2736                 return false;\r
2737         }\r
2738 \r
2739         /**\r
2740         * decode a string that is encoded w/ "chunked' transfer encoding\r
2741         * as defined in RFC2068 19.4.6\r
2742         *\r
2743         * @param    string $buffer\r
2744         * @param    string $lb\r
2745         * @returns      string\r
2746         * @access   public\r
2747         * @deprecated\r
2748         */\r
2749         function decodeChunked($buffer, $lb){\r
2750                 // length := 0\r
2751                 $length = 0;\r
2752                 $new = '';\r
2753                 \r
2754                 // read chunk-size, chunk-extension (if any) and CRLF\r
2755                 // get the position of the linebreak\r
2756                 $chunkend = strpos($buffer, $lb);\r
2757                 if ($chunkend == FALSE) {\r
2758                         $this->debug('no linebreak found in decodeChunked');\r
2759                         return $new;\r
2760                 }\r
2761                 $temp = substr($buffer,0,$chunkend);\r
2762                 $chunk_size = hexdec( trim($temp) );\r
2763                 $chunkstart = $chunkend + strlen($lb);\r
2764                 // while (chunk-size > 0) {\r
2765                 while ($chunk_size > 0) {\r
2766                         $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");\r
2767                         $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);\r
2768                         \r
2769                         // Just in case we got a broken connection\r
2770                         if ($chunkend == FALSE) {\r
2771                             $chunk = substr($buffer,$chunkstart);\r
2772                                 // append chunk-data to entity-body\r
2773                         $new .= $chunk;\r
2774                             $length += strlen($chunk);\r
2775                             break;\r
2776                         }\r
2777                         \r
2778                         // read chunk-data and CRLF\r
2779                         $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);\r
2780                         // append chunk-data to entity-body\r
2781                         $new .= $chunk;\r
2782                         // length := length + chunk-size\r
2783                         $length += strlen($chunk);\r
2784                         // read chunk-size and CRLF\r
2785                         $chunkstart = $chunkend + strlen($lb);\r
2786                         \r
2787                         $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);\r
2788                         if ($chunkend == FALSE) {\r
2789                                 break; //Just in case we got a broken connection\r
2790                         }\r
2791                         $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);\r
2792                         $chunk_size = hexdec( trim($temp) );\r
2793                         $chunkstart = $chunkend;\r
2794                 }\r
2795                 return $new;\r
2796         }\r
2797         \r
2798         /**\r
2799          * Writes the payload, including HTTP headers, to $this->outgoing_payload.\r
2800          *\r
2801          * @param       string $data HTTP body\r
2802          * @param       string $cookie_str data for HTTP Cookie header\r
2803          * @return      void\r
2804          * @access      private\r
2805          */\r
2806         function buildPayload($data, $cookie_str = '') {\r
2807                 // Note: for cURL connections, $this->outgoing_payload is ignored,\r
2808                 // as is the Content-Length header, but these are still created as\r
2809                 // debugging guides.\r
2810 \r
2811                 // add content-length header\r
2812                 $this->setHeader('Content-Length', strlen($data));\r
2813 \r
2814                 // start building outgoing payload:\r
2815                 if ($this->proxy) {\r
2816                         $uri = $this->url;\r
2817                 } else {\r
2818                         $uri = $this->uri;\r
2819                 }\r
2820                 $req = "$this->request_method $uri HTTP/$this->protocol_version";\r
2821                 $this->debug("HTTP request: $req");\r
2822                 $this->outgoing_payload = "$req\r\n";\r
2823 \r
2824                 // loop thru headers, serializing\r
2825                 foreach($this->outgoing_headers as $k => $v){\r
2826                         $hdr = $k.': '.$v;\r
2827                         $this->debug("HTTP header: $hdr");\r
2828                         $this->outgoing_payload .= "$hdr\r\n";\r
2829                 }\r
2830 \r
2831                 // add any cookies\r
2832                 if ($cookie_str != '') {\r
2833                         $hdr = 'Cookie: '.$cookie_str;\r
2834                         $this->debug("HTTP header: $hdr");\r
2835                         $this->outgoing_payload .= "$hdr\r\n";\r
2836                 }\r
2837 \r
2838                 // header/body separator\r
2839                 $this->outgoing_payload .= "\r\n";\r
2840                 \r
2841                 // add data\r
2842                 $this->outgoing_payload .= $data;\r
2843         }\r
2844 \r
2845         /**\r
2846         * sends the SOAP request via HTTP[S]\r
2847         *\r
2848         * @param    string $data message data\r
2849         * @param        array $cookies cookies to send\r
2850         * @return       boolean true if OK, false if problem\r
2851         * @access   private\r
2852         */\r
2853         function sendRequest($data, $cookies = NULL) {\r
2854                 // build cookie string\r
2855                 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));\r
2856 \r
2857                 // build payload\r
2858                 $this->buildPayload($data, $cookie_str);\r
2859 \r
2860           if ($this->io_method() == 'socket') {\r
2861                 // send payload\r
2862                 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {\r
2863                         $this->setError('couldn\'t write message data to socket');\r
2864                         $this->debug('couldn\'t write message data to socket');\r
2865                         return false;\r
2866                 }\r
2867                 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));\r
2868                 return true;\r
2869           } else if ($this->io_method() == 'curl') {\r
2870                 // set payload\r
2871                 // cURL does say this should only be the verb, and in fact it\r
2872                 // turns out that the URI and HTTP version are appended to this, which\r
2873                 // some servers refuse to work with (so we no longer use this method!)\r
2874                 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);\r
2875                 $curl_headers = array();\r
2876                 foreach($this->outgoing_headers as $k => $v){\r
2877                         if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {\r
2878                                 $this->debug("Skip cURL header $k: $v");\r
2879                         } else {\r
2880                                 $curl_headers[] = "$k: $v";\r
2881                         }\r
2882                 }\r
2883                 if ($cookie_str != '') {\r
2884                         $curl_headers[] = 'Cookie: ' . $cookie_str;\r
2885                 }\r
2886                 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);\r
2887                 $this->debug('set cURL HTTP headers');\r
2888                 if ($this->request_method == "POST") {\r
2889                         $this->setCurlOption(CURLOPT_POST, 1);\r
2890                         $this->setCurlOption(CURLOPT_POSTFIELDS, $data);\r
2891                         $this->debug('set cURL POST data');\r
2892                 } else {\r
2893                 }\r
2894                 // insert custom user-set cURL options\r
2895                 foreach ($this->ch_options as $key => $val) {\r
2896                         $this->setCurlOption($key, $val);\r
2897                 }\r
2898 \r
2899                 $this->debug('set cURL payload');\r
2900                 return true;\r
2901           }\r
2902         }\r
2903 \r
2904         /**\r
2905         * gets the SOAP response via HTTP[S]\r
2906         *\r
2907         * @return       string the response (also sets member variables like incoming_payload)\r
2908         * @access   private\r
2909         */\r
2910         function getResponse(){\r
2911                 $this->incoming_payload = '';\r
2912             \r
2913           if ($this->io_method() == 'socket') {\r
2914             // loop until headers have been retrieved\r
2915             $data = '';\r
2916             while (!isset($lb)){\r
2917 \r
2918                         // We might EOF during header read.\r
2919                         if(feof($this->fp)) {\r
2920                                 $this->incoming_payload = $data;\r
2921                                 $this->debug('found no headers before EOF after length ' . strlen($data));\r
2922                                 $this->debug("received before EOF:\n" . $data);\r
2923                                 $this->setError('server failed to send headers');\r
2924                                 return false;\r
2925                         }\r
2926 \r
2927                         $tmp = fgets($this->fp, 256);\r
2928                         $tmplen = strlen($tmp);\r
2929                         $this->debug("read line of $tmplen bytes: " . trim($tmp));\r
2930 \r
2931                         if ($tmplen == 0) {\r
2932                                 $this->incoming_payload = $data;\r
2933                                 $this->debug('socket read of headers timed out after length ' . strlen($data));\r
2934                                 $this->debug("read before timeout: " . $data);\r
2935                                 $this->setError('socket read of headers timed out');\r
2936                                 return false;\r
2937                         }\r
2938 \r
2939                         $data .= $tmp;\r
2940                         $pos = strpos($data,"\r\n\r\n");\r
2941                         if($pos > 1){\r
2942                                 $lb = "\r\n";\r
2943                         } else {\r
2944                                 $pos = strpos($data,"\n\n");\r
2945                                 if($pos > 1){\r
2946                                         $lb = "\n";\r
2947                                 }\r
2948                         }\r
2949                         // remove 100 headers\r
2950                         if (isset($lb) && ereg('^HTTP/1.1 100',$data)) {\r
2951                                 unset($lb);\r
2952                                 $data = '';\r
2953                         }//\r
2954                 }\r
2955                 // store header data\r
2956                 $this->incoming_payload .= $data;\r
2957                 $this->debug('found end of headers after length ' . strlen($data));\r
2958                 // process headers\r
2959                 $header_data = trim(substr($data,0,$pos));\r
2960                 $header_array = explode($lb,$header_data);\r
2961                 $this->incoming_headers = array();\r
2962                 $this->incoming_cookies = array();\r
2963                 foreach($header_array as $header_line){\r
2964                         $arr = explode(':',$header_line, 2);\r
2965                         if(count($arr) > 1){\r
2966                                 $header_name = strtolower(trim($arr[0]));\r
2967                                 $this->incoming_headers[$header_name] = trim($arr[1]);\r
2968                                 if ($header_name == 'set-cookie') {\r
2969                                         // TODO: allow multiple cookies from parseCookie\r
2970                                         $cookie = $this->parseCookie(trim($arr[1]));\r
2971                                         if ($cookie) {\r
2972                                                 $this->incoming_cookies[] = $cookie;\r
2973                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);\r
2974                                         } else {\r
2975                                                 $this->debug('did not find cookie in ' . trim($arr[1]));\r
2976                                         }\r
2977                         }\r
2978                         } else if (isset($header_name)) {\r
2979                                 // append continuation line to previous header\r
2980                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;\r
2981                         }\r
2982                 }\r
2983                 \r
2984                 // loop until msg has been received\r
2985                 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {\r
2986                         $content_length =  2147483647;  // ignore any content-length header\r
2987                         $chunked = true;\r
2988                         $this->debug("want to read chunked content");\r
2989                 } elseif (isset($this->incoming_headers['content-length'])) {\r
2990                         $content_length = $this->incoming_headers['content-length'];\r
2991                         $chunked = false;\r
2992                         $this->debug("want to read content of length $content_length");\r
2993                 } else {\r
2994                         $content_length =  2147483647;\r
2995                         $chunked = false;\r
2996                         $this->debug("want to read content to EOF");\r
2997                 }\r
2998                 $data = '';\r
2999                 do {\r
3000                         if ($chunked) {\r
3001                                 $tmp = fgets($this->fp, 256);\r
3002                                 $tmplen = strlen($tmp);\r
3003                                 $this->debug("read chunk line of $tmplen bytes");\r
3004                                 if ($tmplen == 0) {\r
3005                                         $this->incoming_payload = $data;\r
3006                                         $this->debug('socket read of chunk length timed out after length ' . strlen($data));\r
3007                                         $this->debug("read before timeout:\n" . $data);\r
3008                                         $this->setError('socket read of chunk length timed out');\r
3009                                         return false;\r
3010                                 }\r
3011                                 $content_length = hexdec(trim($tmp));\r
3012                                 $this->debug("chunk length $content_length");\r
3013                         }\r
3014                         $strlen = 0;\r
3015                     while (($strlen < $content_length) && (!feof($this->fp))) {\r
3016                         $readlen = min(8192, $content_length - $strlen);\r
3017                                 $tmp = fread($this->fp, $readlen);\r
3018                                 $tmplen = strlen($tmp);\r
3019                                 $this->debug("read buffer of $tmplen bytes");\r
3020                                 if (($tmplen == 0) && (!feof($this->fp))) {\r
3021                                         $this->incoming_payload = $data;\r
3022                                         $this->debug('socket read of body timed out after length ' . strlen($data));\r
3023                                         $this->debug("read before timeout:\n" . $data);\r
3024                                         $this->setError('socket read of body timed out');\r
3025                                         return false;\r
3026                                 }\r
3027                                 $strlen += $tmplen;\r
3028                                 $data .= $tmp;\r
3029                         }\r
3030                         if ($chunked && ($content_length > 0)) {\r
3031                                 $tmp = fgets($this->fp, 256);\r
3032                                 $tmplen = strlen($tmp);\r
3033                                 $this->debug("read chunk terminator of $tmplen bytes");\r
3034                                 if ($tmplen == 0) {\r
3035                                         $this->incoming_payload = $data;\r
3036                                         $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));\r
3037                                         $this->debug("read before timeout:\n" . $data);\r
3038                                         $this->setError('socket read of chunk terminator timed out');\r
3039                                         return false;\r
3040                                 }\r
3041                         }\r
3042                 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));\r
3043                 if (feof($this->fp)) {\r
3044                         $this->debug('read to EOF');\r
3045                 }\r
3046                 $this->debug('read body of length ' . strlen($data));\r
3047                 $this->incoming_payload .= $data;\r
3048                 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');\r
3049                 \r
3050                 // close filepointer\r
3051                 if(\r
3052                         (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || \r
3053                         (! $this->persistentConnection) || feof($this->fp)){\r
3054                         fclose($this->fp);\r
3055                         $this->fp = false;\r
3056                         $this->debug('closed socket');\r
3057                 }\r
3058                 \r
3059                 // connection was closed unexpectedly\r
3060                 if($this->incoming_payload == ''){\r
3061                         $this->setError('no response from server');\r
3062                         return false;\r
3063                 }\r
3064                 \r
3065                 // decode transfer-encoding\r
3066 //              if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){\r
3067 //                      if(!$data = $this->decodeChunked($data, $lb)){\r
3068 //                              $this->setError('Decoding of chunked data failed');\r
3069 //                              return false;\r
3070 //                      }\r
3071                         //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";\r
3072                         // set decoded payload\r
3073 //                      $this->incoming_payload = $header_data.$lb.$lb.$data;\r
3074 //              }\r
3075         \r
3076           } else if ($this->io_method() == 'curl') {\r
3077                 // send and receive\r
3078                 $this->debug('send and receive with cURL');\r
3079                 $this->incoming_payload = curl_exec($this->ch);\r
3080                 $data = $this->incoming_payload;\r
3081 \r
3082         $cErr = curl_error($this->ch);\r
3083                 if ($cErr != '') {\r
3084                 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';\r
3085                 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE\r
3086                         foreach(curl_getinfo($this->ch) as $k => $v){\r
3087                                 $err .= "$k: $v<br>";\r
3088                         }\r
3089                         $this->debug($err);\r
3090                         $this->setError($err);\r
3091                         curl_close($this->ch);\r
3092                 return false;\r
3093                 } else {\r
3094                         ////echo '<pre>';\r
3095                         //var_dump(curl_getinfo($this->ch));\r
3096                         ////echo '</pre>';\r
3097                 }\r
3098                 // close curl\r
3099                 $this->debug('No cURL error, closing cURL');\r
3100                 curl_close($this->ch);\r
3101                 \r
3102                 // try removing skippable headers\r
3103                 $savedata = $data;\r
3104                 while ($this->isSkippableCurlHeader($data)) {\r
3105                         $this->debug("Found HTTP header to skip");\r
3106                         if ($pos = strpos($data,"\r\n\r\n")) {\r
3107                                 $data = ltrim(substr($data,$pos));\r
3108                         } elseif($pos = strpos($data,"\n\n") ) {\r
3109                                 $data = ltrim(substr($data,$pos));\r
3110                         }\r
3111                 }\r
3112 \r
3113                 if ($data == '') {\r
3114                         // have nothing left; just remove 100 header(s)\r
3115                         $data = $savedata;\r
3116                         while (ereg('^HTTP/1.1 100',$data)) {\r
3117                                 if ($pos = strpos($data,"\r\n\r\n")) {\r
3118                                         $data = ltrim(substr($data,$pos));\r
3119                                 } elseif($pos = strpos($data,"\n\n") ) {\r
3120                                         $data = ltrim(substr($data,$pos));\r
3121                                 }\r
3122                         }\r
3123                 }\r
3124                 \r
3125                 // separate content from HTTP headers\r
3126                 if ($pos = strpos($data,"\r\n\r\n")) {\r
3127                         $lb = "\r\n";\r
3128                 } elseif( $pos = strpos($data,"\n\n")) {\r
3129                         $lb = "\n";\r
3130                 } else {\r
3131                         $this->debug('no proper separation of headers and document');\r
3132                         $this->setError('no proper separation of headers and document');\r
3133                         return false;\r
3134                 }\r
3135                 $header_data = trim(substr($data,0,$pos));\r
3136                 $header_array = explode($lb,$header_data);\r
3137                 $data = ltrim(substr($data,$pos));\r
3138                 $this->debug('found proper separation of headers and document');\r
3139                 $this->debug('cleaned data, stringlen: '.strlen($data));\r
3140                 // clean headers\r
3141                 foreach ($header_array as $header_line) {\r
3142                         $arr = explode(':',$header_line,2);\r
3143                         if(count($arr) > 1){\r
3144                                 $header_name = strtolower(trim($arr[0]));\r
3145                                 $this->incoming_headers[$header_name] = trim($arr[1]);\r
3146                                 if ($header_name == 'set-cookie') {\r
3147                                         // TODO: allow multiple cookies from parseCookie\r
3148                                         $cookie = $this->parseCookie(trim($arr[1]));\r
3149                                         if ($cookie) {\r
3150                                                 $this->incoming_cookies[] = $cookie;\r
3151                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);\r
3152                                         } else {\r
3153                                                 $this->debug('did not find cookie in ' . trim($arr[1]));\r
3154                                         }\r
3155                         }\r
3156                         } else if (isset($header_name)) {\r
3157                                 // append continuation line to previous header\r
3158                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;\r
3159                         }\r
3160                 }\r
3161           }\r
3162 \r
3163                 $this->response_status_line = $header_array[0];\r
3164                 $arr = explode(' ', $this->response_status_line, 3);\r
3165                 $http_version = $arr[0];\r
3166                 $http_status = intval($arr[1]);\r
3167                 $http_reason = count($arr) > 2 ? $arr[2] : '';\r
3168 \r
3169                 // see if we need to resend the request with http digest authentication\r
3170                 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {\r
3171                         $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);\r
3172                         $this->setURL($this->incoming_headers['location']);\r
3173                         $this->tryagain = true;\r
3174                         return false;\r
3175                 }\r
3176 \r
3177                 // see if we need to resend the request with http digest authentication\r
3178                 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {\r
3179                         $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);\r
3180                         if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {\r
3181                                 $this->debug('Server wants digest authentication');\r
3182                                 // remove "Digest " from our elements\r
3183                                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);\r
3184                                 \r
3185                                 // parse elements into array\r
3186                                 $digestElements = explode(',', $digestString);\r
3187                                 foreach ($digestElements as $val) {\r
3188                                         $tempElement = explode('=', trim($val), 2);\r
3189                                         $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);\r
3190                                 }\r
3191 \r
3192                                 // should have (at least) qop, realm, nonce\r
3193                                 if (isset($digestRequest['nonce'])) {\r
3194                                         $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);\r
3195                                         $this->tryagain = true;\r
3196                                         return false;\r
3197                                 }\r
3198                         }\r
3199                         $this->debug('HTTP authentication failed');\r
3200                         $this->setError('HTTP authentication failed');\r
3201                         return false;\r
3202                 }\r
3203                 \r
3204                 if (\r
3205                         ($http_status >= 300 && $http_status <= 307) ||\r
3206                         ($http_status >= 400 && $http_status <= 417) ||\r
3207                         ($http_status >= 501 && $http_status <= 505)\r
3208                    ) {\r
3209                         $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");\r
3210                         return false;\r
3211                 }\r
3212 \r
3213                 // decode content-encoding\r
3214                 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){\r
3215                         if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){\r
3216                         // if decoding works, use it. else assume data wasn't gzencoded\r
3217                         if(function_exists('gzinflate')){\r
3218                                         //$timer->setMarker('starting decoding of gzip/deflated content');\r
3219                                         // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)\r
3220                                         // this means there are no Zlib headers, although there should be\r
3221                                         $this->debug('The gzinflate function exists');\r
3222                                         $datalen = strlen($data);\r
3223                                         if ($this->incoming_headers['content-encoding'] == 'deflate') {\r
3224                                                 if ($degzdata = @gzinflate($data)) {\r
3225                                                 $data = $degzdata;\r
3226                                                 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');\r
3227                                                 if (strlen($data) < $datalen) {\r
3228                                                         // test for the case that the payload has been compressed twice\r
3229                                                         $this->debug('The inflated payload is smaller than the gzipped one; try again');\r
3230                                                                 if ($degzdata = @gzinflate($data)) {\r
3231                                                                 $data = $degzdata;\r
3232                                                                 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');\r
3233                                                                 }\r
3234                                                 }\r
3235                                         } else {\r
3236                                                 $this->debug('Error using gzinflate to inflate the payload');\r
3237                                                 $this->setError('Error using gzinflate to inflate the payload');\r
3238                                         }\r
3239                                         } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {\r
3240                                                 if ($degzdata = @gzinflate(substr($data, 10))) {        // do our best\r
3241                                                         $data = $degzdata;\r
3242                                                 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');\r
3243                                                 if (strlen($data) < $datalen) {\r
3244                                                         // test for the case that the payload has been compressed twice\r
3245                                                         $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');\r
3246                                                                 if ($degzdata = @gzinflate(substr($data, 10))) {\r
3247                                                                 $data = $degzdata;\r
3248                                                                 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');\r
3249                                                                 }\r
3250                                                 }\r
3251                                         } else {\r
3252                                                 $this->debug('Error using gzinflate to un-gzip the payload');\r
3253                                                         $this->setError('Error using gzinflate to un-gzip the payload');\r
3254                                         }\r
3255                                         }\r
3256                                         //$timer->setMarker('finished decoding of gzip/deflated content');\r
3257                                         //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";\r
3258                                         // set decoded payload\r
3259                                         $this->incoming_payload = $header_data.$lb.$lb.$data;\r
3260                         } else {\r
3261                                         $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');\r
3262                                         $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');\r
3263                                 }\r
3264                         } else {\r
3265                                 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);\r
3266                                 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);\r
3267                         }\r
3268                 } else {\r
3269                         $this->debug('No Content-Encoding header');\r
3270                 }\r
3271                 \r
3272                 if(strlen($data) == 0){\r
3273                         $this->debug('no data after headers!');\r
3274                         $this->setError('no data present after HTTP headers');\r
3275                         return false;\r
3276                 }\r
3277                 \r
3278                 return $data;\r
3279         }\r
3280 \r
3281         /**\r
3282          * sets the content-type for the SOAP message to be sent\r
3283          *\r
3284          * @param       string $type the content type, MIME style\r
3285          * @param       mixed $charset character set used for encoding (or false)\r
3286          * @access      public\r
3287          */\r
3288         function setContentType($type, $charset = false) {\r
3289                 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));\r
3290         }\r
3291 \r
3292         /**\r
3293          * specifies that an HTTP persistent connection should be used\r
3294          *\r
3295          * @return      boolean whether the request was honored by this method.\r
3296          * @access      public\r
3297          */\r
3298         function usePersistentConnection(){\r
3299                 if (isset($this->outgoing_headers['Accept-Encoding'])) {\r
3300                         return false;\r
3301                 }\r
3302                 $this->protocol_version = '1.1';\r
3303                 $this->persistentConnection = true;\r
3304                 $this->setHeader('Connection', 'Keep-Alive');\r
3305                 return true;\r
3306         }\r
3307 \r
3308         /**\r
3309          * parse an incoming Cookie into it's parts\r
3310          *\r
3311          * @param       string $cookie_str content of cookie\r
3312          * @return      array with data of that cookie\r
3313          * @access      private\r
3314          */\r
3315         /*\r
3316          * TODO: allow a Set-Cookie string to be parsed into multiple cookies\r
3317          */\r
3318         function parseCookie($cookie_str) {\r
3319                 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';\r
3320                 $data = split(';', $cookie_str);\r
3321                 $value_str = $data[0];\r
3322 \r
3323                 $cookie_param = 'domain=';\r
3324                 $start = strpos($cookie_str, $cookie_param);\r
3325                 if ($start > 0) {\r
3326                         $domain = substr($cookie_str, $start + strlen($cookie_param));\r
3327                         $domain = substr($domain, 0, strpos($domain, ';'));\r
3328                 } else {\r
3329                         $domain = '';\r
3330                 }\r
3331 \r
3332                 $cookie_param = 'expires=';\r
3333                 $start = strpos($cookie_str, $cookie_param);\r
3334                 if ($start > 0) {\r
3335                         $expires = substr($cookie_str, $start + strlen($cookie_param));\r
3336                         $expires = substr($expires, 0, strpos($expires, ';'));\r
3337                 } else {\r
3338                         $expires = '';\r
3339                 }\r
3340 \r
3341                 $cookie_param = 'path=';\r
3342                 $start = strpos($cookie_str, $cookie_param);\r
3343                 if ( $start > 0 ) {\r
3344                         $path = substr($cookie_str, $start + strlen($cookie_param));\r
3345                         $path = substr($path, 0, strpos($path, ';'));\r
3346                 } else {\r
3347                         $path = '/';\r
3348                 }\r
3349                                                 \r
3350                 $cookie_param = ';secure;';\r
3351                 if (strpos($cookie_str, $cookie_param) !== FALSE) {\r
3352                         $secure = true;\r
3353                 } else {\r
3354                         $secure = false;\r
3355                 }\r
3356 \r
3357                 $sep_pos = strpos($value_str, '=');\r
3358 \r
3359                 if ($sep_pos) {\r
3360                         $name = substr($value_str, 0, $sep_pos);\r
3361                         $value = substr($value_str, $sep_pos + 1);\r
3362                         $cookie= array( 'name' => $name,\r
3363                                         'value' => $value,\r
3364                                                         'domain' => $domain,\r
3365                                                         'path' => $path,\r
3366                                                         'expires' => $expires,\r
3367                                                         'secure' => $secure\r
3368                                                         );              \r
3369                         return $cookie;\r
3370                 }\r
3371                 return false;\r
3372         }\r
3373   \r
3374         /**\r
3375          * sort out cookies for the current request\r
3376          *\r
3377          * @param       array $cookies array with all cookies\r
3378          * @param       boolean $secure is the send-content secure or not?\r
3379          * @return      string for Cookie-HTTP-Header\r
3380          * @access      private\r
3381          */\r
3382         function getCookiesForRequest($cookies, $secure=false) {\r
3383                 $cookie_str = '';\r
3384                 if ((! is_null($cookies)) && (is_array($cookies))) {\r
3385                         foreach ($cookies as $cookie) {\r
3386                                 if (! is_array($cookie)) {\r
3387                                         continue;\r
3388                                 }\r
3389                         $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);\r
3390                                 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {\r
3391                                         if (strtotime($cookie['expires']) <= time()) {\r
3392                                                 $this->debug('cookie has expired');\r
3393                                                 continue;\r
3394                                         }\r
3395                                 }\r
3396                                 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {\r
3397                                         $domain = preg_quote($cookie['domain']);\r
3398                                         if (! preg_match("'.*$domain$'i", $this->host)) {\r
3399                                                 $this->debug('cookie has different domain');\r
3400                                                 continue;\r
3401                                         }\r
3402                                 }\r
3403                                 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {\r
3404                                         $path = preg_quote($cookie['path']);\r
3405                                         if (! preg_match("'^$path.*'i", $this->path)) {\r
3406                                                 $this->debug('cookie is for a different path');\r
3407                                                 continue;\r
3408                                         }\r
3409                                 }\r
3410                                 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {\r
3411                                         $this->debug('cookie is secure, transport is not');\r
3412                                         continue;\r
3413                                 }\r
3414                                 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';\r
3415                         $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);\r
3416                         }\r
3417                 }\r
3418                 return $cookie_str;\r
3419   }\r
3420 }\r
3421 \r
3422 ?><?php\r
3423 \r
3424 \r
3425 \r
3426 /**\r
3427 * parses a WSDL file, allows access to it's data, other utility methods.\r
3428 * also builds WSDL structures programmatically.\r
3429\r
3430 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
3431 * @author   Scott Nichol <snichol@users.sourceforge.net>\r
3432 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
3433 * @access public \r
3434 */\r
3435 class wsdl extends nusoap_base {\r
3436         // URL or filename of the root of this WSDL\r
3437     var $wsdl; \r
3438     // define internal arrays of bindings, ports, operations, messages, etc.\r
3439     var $schemas = array();\r
3440     var $currentSchema;\r
3441     var $message = array();\r
3442     var $complexTypes = array();\r
3443     var $messages = array();\r
3444     var $currentMessage;\r
3445     var $currentOperation;\r
3446     var $portTypes = array();\r
3447     var $currentPortType;\r
3448     var $bindings = array();\r
3449     var $currentBinding;\r
3450     var $ports = array();\r
3451     var $currentPort;\r
3452     var $opData = array();\r
3453     var $status = '';\r
3454     var $documentation = false;\r
3455     var $endpoint = ''; \r
3456     // array of wsdl docs to import\r
3457     var $import = array(); \r
3458     // parser vars\r
3459     var $parser;\r
3460     var $position = 0;\r
3461     var $depth = 0;\r
3462     var $depth_array = array();\r
3463         // for getting wsdl\r
3464         var $proxyhost = '';\r
3465     var $proxyport = '';\r
3466         var $proxyusername = '';\r
3467         var $proxypassword = '';\r
3468         var $timeout = 0;\r
3469         var $response_timeout = 30;\r
3470         var $curl_options = array();    // User-specified cURL options\r
3471         var $use_curl = false;                  // whether to always try to use cURL\r
3472         // for HTTP authentication\r
3473         var $username = '';                             // Username for HTTP authentication\r
3474         var $password = '';                             // Password for HTTP authentication\r
3475         var $authtype = '';                             // Type of HTTP authentication\r
3476         var $certRequest = array();             // Certificate for HTTP SSL authentication\r
3477 \r
3478     /**\r
3479      * constructor\r
3480      * \r
3481      * @param string $wsdl WSDL document URL\r
3482          * @param string $proxyhost\r
3483          * @param string $proxyport\r
3484          * @param string $proxyusername\r
3485          * @param string $proxypassword\r
3486          * @param integer $timeout set the connection timeout\r
3487          * @param integer $response_timeout set the response timeout\r
3488          * @param array $curl_options user-specified cURL options\r
3489          * @param boolean $use_curl try to use cURL\r
3490      * @access public \r
3491      */\r
3492     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){\r
3493                 parent::nusoap_base();\r
3494                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");\r
3495         $this->proxyhost = $proxyhost;\r
3496         $this->proxyport = $proxyport;\r
3497                 $this->proxyusername = $proxyusername;\r
3498                 $this->proxypassword = $proxypassword;\r
3499                 $this->timeout = $timeout;\r
3500                 $this->response_timeout = $response_timeout;\r
3501                 if (is_array($curl_options))\r
3502                         $this->curl_options = $curl_options;\r
3503                 $this->use_curl = $use_curl;\r
3504                 $this->fetchWSDL($wsdl);\r
3505     }\r
3506 \r
3507         /**\r
3508          * fetches the WSDL document and parses it\r
3509          *\r
3510          * @access public\r
3511          */\r
3512         function fetchWSDL($wsdl) {\r
3513                 $this->debug("parse and process WSDL path=$wsdl");\r
3514                 $this->wsdl = $wsdl;\r
3515         // parse wsdl file\r
3516         if ($this->wsdl != "") {\r
3517             $this->parseWSDL($this->wsdl);\r
3518         }\r
3519         // imports\r
3520         // TODO: handle imports more properly, grabbing them in-line and nesting them\r
3521         $imported_urls = array();\r
3522         $imported = 1;\r
3523         while ($imported > 0) {\r
3524                 $imported = 0;\r
3525                 // Schema imports\r
3526                 foreach ($this->schemas as $ns => $list) {\r
3527                         foreach ($list as $xs) {\r
3528                                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!\r
3529                             foreach ($xs->imports as $ns2 => $list2) {\r
3530                                 for ($ii = 0; $ii < count($list2); $ii++) {\r
3531                                         if (! $list2[$ii]['loaded']) {\r
3532                                                 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;\r
3533                                                 $url = $list2[$ii]['location'];\r
3534                                                                 if ($url != '') {\r
3535                                                                         $urlparts = parse_url($url);\r
3536                                                                         if (!isset($urlparts['host'])) {\r
3537                                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .\r
3538                                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];\r
3539                                                                         }\r
3540                                                                         if (! in_array($url, $imported_urls)) {\r
3541                                                                 $this->parseWSDL($url);\r
3542                                                                 $imported++;\r
3543                                                                 $imported_urls[] = $url;\r
3544                                                         }\r
3545                                                                 } else {\r
3546                                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");\r
3547                                                                 }\r
3548                                                         }\r
3549                                                 }\r
3550                             } \r
3551                         }\r
3552                 }\r
3553                 // WSDL imports\r
3554                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!\r
3555             foreach ($this->import as $ns => $list) {\r
3556                 for ($ii = 0; $ii < count($list); $ii++) {\r
3557                         if (! $list[$ii]['loaded']) {\r
3558                                 $this->import[$ns][$ii]['loaded'] = true;\r
3559                                 $url = $list[$ii]['location'];\r
3560                                                 if ($url != '') {\r
3561                                                         $urlparts = parse_url($url);\r
3562                                                         if (!isset($urlparts['host'])) {\r
3563                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .\r
3564                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];\r
3565                                                         }\r
3566                                                         if (! in_array($url, $imported_urls)) {\r
3567                                                 $this->parseWSDL($url);\r
3568                                                 $imported++;\r
3569                                                 $imported_urls[] = $url;\r
3570                                         }\r
3571                                                 } else {\r
3572                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");\r
3573                                                 }\r
3574                                         }\r
3575                                 }\r
3576             } \r
3577                 }\r
3578         // add new data to operation data\r
3579         foreach($this->bindings as $binding => $bindingData) {\r
3580             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {\r
3581                 foreach($bindingData['operations'] as $operation => $data) {\r
3582                     $this->debug('post-parse data gathering for ' . $operation);\r
3583                     $this->bindings[$binding]['operations'][$operation]['input'] = \r
3584                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ? \r
3585                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :\r
3586                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];\r
3587                     $this->bindings[$binding]['operations'][$operation]['output'] = \r
3588                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?\r
3589                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :\r
3590                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];\r
3591                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){\r
3592                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];\r
3593                                         }\r
3594                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){\r
3595                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];\r
3596                     }\r
3597                     // Set operation style if necessary, but do not override one already provided\r
3598                                         if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {\r
3599                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];\r
3600                     }\r
3601                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';\r
3602                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';\r
3603                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';\r
3604                 } \r
3605             } \r
3606         }\r
3607         }\r
3608 \r
3609     /**\r
3610      * parses the wsdl document\r
3611      * \r
3612      * @param string $wsdl path or URL\r
3613      * @access private \r
3614      */\r
3615     function parseWSDL($wsdl = '') {\r
3616                 $this->debug("parse WSDL at path=$wsdl");\r
3617 \r
3618         if ($wsdl == '') {\r
3619             $this->debug('no wsdl passed to parseWSDL()!!');\r
3620             $this->setError('no wsdl passed to parseWSDL()!!');\r
3621             return false;\r
3622         }\r
3623         \r
3624         // parse $wsdl for url format\r
3625         $wsdl_props = parse_url($wsdl);\r
3626 \r
3627         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {\r
3628             $this->debug('getting WSDL http(s) URL ' . $wsdl);\r
3629                 // get wsdl\r
3630                 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);\r
3631                         $tr->request_method = 'GET';\r
3632                         $tr->useSOAPAction = false;\r
3633                         if($this->proxyhost && $this->proxyport){\r
3634                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);\r
3635                         }\r
3636                         if ($this->authtype != '') {\r
3637                                 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);\r
3638                         }\r
3639                         $tr->setEncoding('gzip, deflate');\r
3640                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);\r
3641                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);\r
3642                         //$this->debug("WSDL response\n" . $tr->incoming_payload);\r
3643                         $this->appendDebug($tr->getDebug());\r
3644                         // catch errors\r
3645                         if($err = $tr->getError() ){\r
3646                                 $errstr = 'HTTP ERROR: '.$err;\r
3647                                 $this->debug($errstr);\r
3648                     $this->setError($errstr);\r
3649                                 unset($tr);\r
3650                     return false;\r
3651                         }\r
3652                         unset($tr);\r
3653                         $this->debug("got WSDL URL");\r
3654         } else {\r
3655             // $wsdl is not http(s), so treat it as a file URL or plain file path\r
3656                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {\r
3657                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];\r
3658                 } else {\r
3659                         $path = $wsdl;\r
3660                 }\r
3661             $this->debug('getting WSDL file ' . $path);\r
3662             if ($fp = @fopen($path, 'r')) {\r
3663                 $wsdl_string = '';\r
3664                 while ($data = fread($fp, 32768)) {\r
3665                     $wsdl_string .= $data;\r
3666                 } \r
3667                 fclose($fp);\r
3668             } else {\r
3669                 $errstr = "Bad path to WSDL file $path";\r
3670                 $this->debug($errstr);\r
3671                 $this->setError($errstr);\r
3672                 return false;\r
3673             } \r
3674         }\r
3675         $this->debug('Parse WSDL');\r
3676         // end new code added\r
3677         // Create an XML parser.\r
3678         $this->parser = xml_parser_create(); \r
3679         // Set the options for parsing the XML data.\r
3680         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);\r
3681         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); \r
3682         // Set the object for the parser.\r
3683         xml_set_object($this->parser, $this); \r
3684         // Set the element handlers for the parser.\r
3685         xml_set_element_handler($this->parser, 'start_element', 'end_element');\r
3686         xml_set_character_data_handler($this->parser, 'character_data');\r
3687         // Parse the XML file.\r
3688         if (!xml_parse($this->parser, $wsdl_string, true)) {\r
3689             // Display an error message.\r
3690             $errstr = sprintf(\r
3691                                 'XML error parsing WSDL from %s on line %d: %s',\r
3692                                 $wsdl,\r
3693                 xml_get_current_line_number($this->parser),\r
3694                 xml_error_string(xml_get_error_code($this->parser))\r
3695                 );\r
3696             $this->debug($errstr);\r
3697                         $this->debug("XML payload:\n" . $wsdl_string);\r
3698             $this->setError($errstr);\r
3699             return false;\r
3700         } \r
3701                 // free the parser\r
3702         xml_parser_free($this->parser);\r
3703         $this->debug('Parsing WSDL done');\r
3704                 // catch wsdl parse errors\r
3705                 if($this->getError()){\r
3706                         return false;\r
3707                 }\r
3708         return true;\r
3709     } \r
3710 \r
3711     /**\r
3712      * start-element handler\r
3713      * \r
3714      * @param string $parser XML parser object\r
3715      * @param string $name element name\r
3716      * @param string $attrs associative array of attributes\r
3717      * @access private \r
3718      */\r
3719     function start_element($parser, $name, $attrs)\r
3720     {\r
3721         if ($this->status == 'schema') {\r
3722             $this->currentSchema->schemaStartElement($parser, $name, $attrs);\r
3723             $this->appendDebug($this->currentSchema->getDebug());\r
3724             $this->currentSchema->clearDebug();\r
3725         } elseif (ereg('schema$', $name)) {\r
3726                 $this->debug('Parsing WSDL schema');\r
3727             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");\r
3728             $this->status = 'schema';\r
3729             $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);\r
3730             $this->currentSchema->schemaStartElement($parser, $name, $attrs);\r
3731             $this->appendDebug($this->currentSchema->getDebug());\r
3732             $this->currentSchema->clearDebug();\r
3733         } else {\r
3734             // position in the total number of elements, starting from 0\r
3735             $pos = $this->position++;\r
3736             $depth = $this->depth++; \r
3737             // set self as current value for this depth\r
3738             $this->depth_array[$depth] = $pos;\r
3739             $this->message[$pos] = array('cdata' => ''); \r
3740             // process attributes\r
3741             if (count($attrs) > 0) {\r
3742                                 // register namespace declarations\r
3743                 foreach($attrs as $k => $v) {\r
3744                     if (ereg("^xmlns", $k)) {\r
3745                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {\r
3746                             $this->namespaces[$ns_prefix] = $v;\r
3747                         } else {\r
3748                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;\r
3749                         } \r
3750                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {\r
3751                             $this->XMLSchemaVersion = $v;\r
3752                             $this->namespaces['xsi'] = $v . '-instance';\r
3753                         } \r
3754                     }\r
3755                 }\r
3756                 // expand each attribute prefix to its namespace\r
3757                 foreach($attrs as $k => $v) {\r
3758                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;\r
3759                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {\r
3760                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;\r
3761                     } \r
3762                     $eAttrs[$k] = $v;\r
3763                 } \r
3764                 $attrs = $eAttrs;\r
3765             } else {\r
3766                 $attrs = array();\r
3767             } \r
3768             // get element prefix, namespace and name\r
3769             if (ereg(':', $name)) {\r
3770                 // get ns prefix\r
3771                 $prefix = substr($name, 0, strpos($name, ':')); \r
3772                 // get ns\r
3773                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; \r
3774                 // get unqualified name\r
3775                 $name = substr(strstr($name, ':'), 1);\r
3776             } \r
3777                         // process attributes, expanding any prefixes to namespaces\r
3778             // find status, register data\r
3779             switch ($this->status) {\r
3780                 case 'message':\r
3781                     if ($name == 'part') {\r
3782                                     if (isset($attrs['type'])) {\r
3783                                     $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));\r
3784                                     $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];\r
3785                                 } \r
3786                                     if (isset($attrs['element'])) {\r
3787                                     $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));\r
3788                                         $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';\r
3789                                     } \r
3790                                 } \r
3791                                 break;\r
3792                             case 'portType':\r
3793                                 switch ($name) {\r
3794                                     case 'operation':\r
3795                                         $this->currentPortOperation = $attrs['name'];\r
3796                                         $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");\r
3797                                         if (isset($attrs['parameterOrder'])) {\r
3798                                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];\r
3799                                                 } \r
3800                                                 break;\r
3801                                             case 'documentation':\r
3802                                                 $this->documentation = true;\r
3803                                                 break; \r
3804                                             // merge input/output data\r
3805                                             default:\r
3806                                                 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';\r
3807                                                 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;\r
3808                                                 break;\r
3809                                         } \r
3810                                 break;\r
3811                                 case 'binding':\r
3812                                     switch ($name) {\r
3813                                         case 'binding': \r
3814                                             // get ns prefix\r
3815                                             if (isset($attrs['style'])) {\r
3816                                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;\r
3817                                                 } \r
3818                                                 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);\r
3819                                                 break;\r
3820                                                 case 'header':\r
3821                                                     $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;\r
3822                                                     break;\r
3823                                                 case 'operation':\r
3824                                                     if (isset($attrs['soapAction'])) {\r
3825                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];\r
3826                                                     } \r
3827                                                     if (isset($attrs['style'])) {\r
3828                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];\r
3829                                                     } \r
3830                                                     if (isset($attrs['name'])) {\r
3831                                                         $this->currentOperation = $attrs['name'];\r
3832                                                         $this->debug("current binding operation: $this->currentOperation");\r
3833                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];\r
3834                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;\r
3835                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';\r
3836                                                     } \r
3837                                                     break;\r
3838                                                 case 'input':\r
3839                                                     $this->opStatus = 'input';\r
3840                                                     break;\r
3841                                                 case 'output':\r
3842                                                     $this->opStatus = 'output';\r
3843                                                     break;\r
3844                                                 case 'body':\r
3845                                                     if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {\r
3846                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);\r
3847                                                     } else {\r
3848                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;\r
3849                                                     } \r
3850                                                     break;\r
3851                                         } \r
3852                                         break;\r
3853                                 case 'service':\r
3854                                         switch ($name) {\r
3855                                             case 'port':\r
3856                                                 $this->currentPort = $attrs['name'];\r
3857                                                 $this->debug('current port: ' . $this->currentPort);\r
3858                                                 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);\r
3859                                         \r
3860                                                 break;\r
3861                                             case 'address':\r
3862                                                 $this->ports[$this->currentPort]['location'] = $attrs['location'];\r
3863                                                 $this->ports[$this->currentPort]['bindingType'] = $namespace;\r
3864                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;\r
3865                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];\r
3866                                                 break;\r
3867                                         } \r
3868                                         break;\r
3869                         } \r
3870                 // set status\r
3871                 switch ($name) {\r
3872                         case 'import':\r
3873                             if (isset($attrs['location'])) {\r
3874                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);\r
3875                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');\r
3876                                 } else {\r
3877                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);\r
3878                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {\r
3879                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];\r
3880                                         }\r
3881                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');\r
3882                                 }\r
3883                                 break;\r
3884                         //wait for schema\r
3885                         //case 'types':\r
3886                         //      $this->status = 'schema';\r
3887                         //      break;\r
3888                         case 'message':\r
3889                                 $this->status = 'message';\r
3890                                 $this->messages[$attrs['name']] = array();\r
3891                                 $this->currentMessage = $attrs['name'];\r
3892                                 break;\r
3893                         case 'portType':\r
3894                                 $this->status = 'portType';\r
3895                                 $this->portTypes[$attrs['name']] = array();\r
3896                                 $this->currentPortType = $attrs['name'];\r
3897                                 break;\r
3898                         case "binding":\r
3899                                 if (isset($attrs['name'])) {\r
3900                                 // get binding name\r
3901                                         if (strpos($attrs['name'], ':')) {\r
3902                                         $this->currentBinding = $this->getLocalPart($attrs['name']);\r
3903                                         } else {\r
3904                                         $this->currentBinding = $attrs['name'];\r
3905                                         } \r
3906                                         $this->status = 'binding';\r
3907                                         $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);\r
3908                                         $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);\r
3909                                 } \r
3910                                 break;\r
3911                         case 'service':\r
3912                                 $this->serviceName = $attrs['name'];\r
3913                                 $this->status = 'service';\r
3914                                 $this->debug('current service: ' . $this->serviceName);\r
3915                                 break;\r
3916                         case 'definitions':\r
3917                                 foreach ($attrs as $name => $value) {\r
3918                                         $this->wsdl_info[$name] = $value;\r
3919                                 } \r
3920                                 break;\r
3921                         } \r
3922                 } \r
3923         } \r
3924 \r
3925         /**\r
3926         * end-element handler\r
3927         * \r
3928         * @param string $parser XML parser object\r
3929         * @param string $name element name\r
3930         * @access private \r
3931         */\r
3932         function end_element($parser, $name){ \r
3933                 // unset schema status\r
3934                 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {\r
3935                         $this->status = "";\r
3936             $this->appendDebug($this->currentSchema->getDebug());\r
3937             $this->currentSchema->clearDebug();\r
3938                         $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;\r
3939                 $this->debug('Parsing WSDL schema done');\r
3940                 } \r
3941                 if ($this->status == 'schema') {\r
3942                         $this->currentSchema->schemaEndElement($parser, $name);\r
3943                 } else {\r
3944                         // bring depth down a notch\r
3945                         $this->depth--;\r
3946                 } \r
3947                 // end documentation\r
3948                 if ($this->documentation) {\r
3949                         //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.\r
3950                         //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;\r
3951                         $this->documentation = false;\r
3952                 } \r
3953         } \r
3954 \r
3955         /**\r
3956          * element content handler\r
3957          * \r
3958          * @param string $parser XML parser object\r
3959          * @param string $data element content\r
3960          * @access private \r
3961          */\r
3962         function character_data($parser, $data)\r
3963         {\r
3964                 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;\r
3965                 if (isset($this->message[$pos]['cdata'])) {\r
3966                         $this->message[$pos]['cdata'] .= $data;\r
3967                 } \r
3968                 if ($this->documentation) {\r
3969                         $this->documentation .= $data;\r
3970                 } \r
3971         } \r
3972         \r
3973         /**\r
3974         * if authenticating, set user credentials here\r
3975         *\r
3976         * @param    string $username\r
3977         * @param    string $password\r
3978         * @param        string $authtype (basic|digest|certificate|ntlm)\r
3979         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)\r
3980         * @access   public\r
3981         */\r
3982         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {\r
3983                 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");\r
3984                 $this->appendDebug($this->varDump($certRequest));\r
3985                 $this->username = $username;\r
3986                 $this->password = $password;\r
3987                 $this->authtype = $authtype;\r
3988                 $this->certRequest = $certRequest;\r
3989         }\r
3990         \r
3991         function getBindingData($binding)\r
3992         {\r
3993                 if (is_array($this->bindings[$binding])) {\r
3994                         return $this->bindings[$binding];\r
3995                 } \r
3996         }\r
3997         \r
3998         /**\r
3999          * returns an assoc array of operation names => operation data\r
4000          * \r
4001          * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)\r
4002          * @return array \r
4003          * @access public \r
4004          */\r
4005         function getOperations($bindingType = 'soap') {\r
4006                 $ops = array();\r
4007                 if ($bindingType == 'soap') {\r
4008                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';\r
4009                 } elseif ($bindingType == 'soap12') {\r
4010                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';\r
4011                 }\r
4012                 // loop thru ports\r
4013                 foreach($this->ports as $port => $portData) {\r
4014                         // binding type of port matches parameter\r
4015                         if ($portData['bindingType'] == $bindingType) {\r
4016                                 //$this->debug("getOperations for port $port");\r
4017                                 //$this->debug("port data: " . $this->varDump($portData));\r
4018                                 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));\r
4019                                 // merge bindings\r
4020                                 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {\r
4021                                         $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);\r
4022                                 }\r
4023                         }\r
4024                 } \r
4025                 return $ops;\r
4026         } \r
4027         \r
4028         /**\r
4029          * returns an associative array of data necessary for calling an operation\r
4030          * \r
4031          * @param string $operation name of operation\r
4032          * @param string $bindingType type of binding eg: soap, soap12\r
4033          * @return array \r
4034          * @access public \r
4035          */\r
4036         function getOperationData($operation, $bindingType = 'soap')\r
4037         {\r
4038                 if ($bindingType == 'soap') {\r
4039                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';\r
4040                 } elseif ($bindingType == 'soap12') {\r
4041                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';\r
4042                 }\r
4043                 // loop thru ports\r
4044                 foreach($this->ports as $port => $portData) {\r
4045                         // binding type of port matches parameter\r
4046                         if ($portData['bindingType'] == $bindingType) {\r
4047                                 // get binding\r
4048                                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {\r
4049                                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {\r
4050                                         // note that we could/should also check the namespace here\r
4051                                         if ($operation == $bOperation) {\r
4052                                                 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];\r
4053                                             return $opData;\r
4054                                         } \r
4055                                 } \r
4056                         }\r
4057                 } \r
4058         }\r
4059         \r
4060         /**\r
4061          * returns an associative array of data necessary for calling an operation\r
4062          * \r
4063          * @param string $soapAction soapAction for operation\r
4064          * @param string $bindingType type of binding eg: soap, soap12\r
4065          * @return array \r
4066          * @access public \r
4067          */\r
4068         function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {\r
4069                 if ($bindingType == 'soap') {\r
4070                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';\r
4071                 } elseif ($bindingType == 'soap12') {\r
4072                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';\r
4073                 }\r
4074                 // loop thru ports\r
4075                 foreach($this->ports as $port => $portData) {\r
4076                         // binding type of port matches parameter\r
4077                         if ($portData['bindingType'] == $bindingType) {\r
4078                                 // loop through operations for the binding\r
4079                                 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {\r
4080                                         if ($opData['soapAction'] == $soapAction) {\r
4081                                             return $opData;\r
4082                                         } \r
4083                                 } \r
4084                         }\r
4085                 } \r
4086         }\r
4087         \r
4088         /**\r
4089     * returns an array of information about a given type\r
4090     * returns false if no type exists by the given name\r
4091     *\r
4092         *        typeDef = array(\r
4093         *        'elements' => array(), // refs to elements array\r
4094         *       'restrictionBase' => '',\r
4095         *       'phpType' => '',\r
4096         *       'order' => '(sequence|all)',\r
4097         *       'attrs' => array() // refs to attributes array\r
4098         *       )\r
4099     *\r
4100     * @param string $type the type\r
4101     * @param string $ns namespace (not prefix) of the type\r
4102     * @return mixed\r
4103     * @access public\r
4104     * @see nusoap_xmlschema\r
4105     */\r
4106         function getTypeDef($type, $ns) {\r
4107                 $this->debug("in getTypeDef: type=$type, ns=$ns");\r
4108                 if ((! $ns) && isset($this->namespaces['tns'])) {\r
4109                         $ns = $this->namespaces['tns'];\r
4110                         $this->debug("in getTypeDef: type namespace forced to $ns");\r
4111                 }\r
4112                 if (!isset($this->schemas[$ns])) {\r
4113                         foreach ($this->schemas as $ns0 => $schema0) {\r
4114                                 if (strcasecmp($ns, $ns0) == 0) {\r
4115                                         $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");\r
4116                                         $ns = $ns0;\r
4117                                         break;\r
4118                                 }\r
4119                         }\r
4120                 }\r
4121                 if (isset($this->schemas[$ns])) {\r
4122                         $this->debug("in getTypeDef: have schema for namespace $ns");\r
4123                         for ($i = 0; $i < count($this->schemas[$ns]); $i++) {\r
4124                                 $xs = &$this->schemas[$ns][$i];\r
4125                                 $t = $xs->getTypeDef($type);\r
4126                                 //$this->appendDebug($xs->getDebug());\r
4127                                 //$xs->clearDebug();\r
4128                                 if ($t) {\r
4129                                         if (!isset($t['phpType'])) {\r
4130                                                 // get info for type to tack onto the element\r
4131                                                 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);\r
4132                                                 $ns = substr($t['type'], 0, strrpos($t['type'], ':'));\r
4133                                                 $etype = $this->getTypeDef($uqType, $ns);\r
4134                                                 if ($etype) {\r
4135                                                         $this->debug("found type for [element] $type:");\r
4136                                                         $this->debug($this->varDump($etype));\r
4137                                                         if (isset($etype['phpType'])) {\r
4138                                                                 $t['phpType'] = $etype['phpType'];\r
4139                                                         }\r
4140                                                         if (isset($etype['elements'])) {\r
4141                                                                 $t['elements'] = $etype['elements'];\r
4142                                                         }\r
4143                                                         if (isset($etype['attrs'])) {\r
4144                                                                 $t['attrs'] = $etype['attrs'];\r
4145                                                         }\r
4146                                                 }\r
4147                                         }\r
4148                                         return $t;\r
4149                                 }\r
4150                         }\r
4151                 } else {\r
4152                         $this->debug("in getTypeDef: do not have schema for namespace $ns");\r
4153                 }\r
4154                 return false;\r
4155         }\r
4156 \r
4157     /**\r
4158     * prints html description of services\r
4159     *\r
4160     * @access private\r
4161     */\r
4162     function webDescription(){\r
4163         global $HTTP_SERVER_VARS;\r
4164 \r
4165                 if (isset($_SERVER)) {\r
4166                         $PHP_SELF = $_SERVER['PHP_SELF'];\r
4167                 } elseif (isset($HTTP_SERVER_VARS)) {\r
4168                         $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];\r
4169                 } else {\r
4170                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");\r
4171                 }\r
4172 \r
4173                 $b = '\r
4174                 <html><head><title>NuSOAP: '.$this->serviceName.'</title>\r
4175                 <style type="text/css">\r
4176                     body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }\r
4177                     p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }\r
4178                     pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}\r
4179                     ul      { margin-top: 10px; margin-left: 20px; }\r
4180                     li      { list-style-type: none; margin-top: 10px; color: #000000; }\r
4181                     .content{\r
4182                         margin-left: 0px; padding-bottom: 2em; }\r
4183                     .nav {\r
4184                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;\r
4185                         margin-top: 10px; margin-left: 0px; color: #000000;\r
4186                         background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }\r
4187                     .title {\r
4188                         font-family: arial; font-size: 26px; color: #ffffff;\r
4189                         background-color: #999999; width: 105%; margin-left: 0px;\r
4190                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}\r
4191                     .hidden {\r
4192                         position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;\r
4193                         font-family: arial; overflow: hidden; width: 600;\r
4194                         padding: 20px; font-size: 10px; background-color: #999999;\r
4195                         layer-background-color:#FFFFFF; }\r
4196                     a,a:active  { color: charcoal; font-weight: bold; }\r
4197                     a:visited   { color: #666666; font-weight: bold; }\r
4198                     a:hover     { color: cc3300; font-weight: bold; }\r
4199                 </style>\r
4200                 <script language="JavaScript" type="text/javascript">\r
4201                 <!--\r
4202                 // POP-UP CAPTIONS...\r
4203                 function lib_bwcheck(){ //Browsercheck (needed)\r
4204                     this.ver=navigator.appVersion\r
4205                     this.agent=navigator.userAgent\r
4206                     this.dom=document.getElementById?1:0\r
4207                     this.opera5=this.agent.indexOf("Opera 5")>-1\r
4208                     this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;\r
4209                     this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;\r
4210                     this.ie4=(document.all && !this.dom && !this.opera5)?1:0;\r
4211                     this.ie=this.ie4||this.ie5||this.ie6\r
4212                     this.mac=this.agent.indexOf("Mac")>-1\r
4213                     this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;\r
4214                     this.ns4=(document.layers && !this.dom)?1:0;\r
4215                     this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)\r
4216                     return this\r
4217                 }\r
4218                 var bw = new lib_bwcheck()\r
4219                 //Makes crossbrowser object.\r
4220                 function makeObj(obj){\r
4221                     this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;\r
4222                     if(!this.evnt) return false\r
4223                     this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;\r
4224                     this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;\r
4225                     this.writeIt=b_writeIt;\r
4226                     return this\r
4227                 }\r
4228                 // A unit of measure that will be added when setting the position of a layer.\r
4229                 //var px = bw.ns4||window.opera?"":"px";\r
4230                 function b_writeIt(text){\r
4231                     if (bw.ns4){this.wref.write(text);this.wref.close()}\r
4232                     else this.wref.innerHTML = text\r
4233                 }\r
4234                 //Shows the messages\r
4235                 var oDesc;\r
4236                 function popup(divid){\r
4237                     if(oDesc = new makeObj(divid)){\r
4238                         oDesc.css.visibility = "visible"\r
4239                     }\r
4240                 }\r
4241                 function popout(){ // Hides message\r
4242                     if(oDesc) oDesc.css.visibility = "hidden"\r
4243                 }\r
4244                 //-->\r
4245                 </script>\r
4246                 </head>\r
4247                 <body>\r
4248                 <div class=content>\r
4249                         <br><br>\r
4250                         <div class=title>'.$this->serviceName.'</div>\r
4251                         <div class=nav>\r
4252                                 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.\r
4253                                 Click on an operation name to view it&apos;s details.</p>\r
4254                                 <ul>';\r
4255                                 foreach($this->getOperations() as $op => $data){\r
4256                                     $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";\r
4257                                     // create hidden div\r
4258                                     $b .= "<div id='$op' class='hidden'>\r
4259                                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";\r
4260                                     foreach($data as $donnie => $marie){ // loop through opdata\r
4261                                                 if($donnie == 'input' || $donnie == 'output'){ // show input/output data\r
4262                                                     $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';\r
4263                                                     foreach($marie as $captain => $tenille){ // loop through data\r
4264                                                                 if($captain == 'parts'){ // loop thru parts\r
4265                                                                     $b .= "&nbsp;&nbsp;$captain:<br>";\r
4266                                                         //if(is_array($tenille)){\r
4267                                                                         foreach($tenille as $joanie => $chachi){\r
4268                                                                                         $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";\r
4269                                                                         }\r
4270                                                                 //}\r
4271                                                                 } else {\r
4272                                                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";\r
4273                                                                 }\r
4274                                                     }\r
4275                                                 } else {\r
4276                                                     $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";\r
4277                                                 }\r
4278                                     }\r
4279                                         $b .= '</div>';\r
4280                                 }\r
4281                                 $b .= '\r
4282                                 <ul>\r
4283                         </div>\r
4284                 </div></body></html>';\r
4285                 return $b;\r
4286     }\r
4287 \r
4288         /**\r
4289         * serialize the parsed wsdl\r
4290         *\r
4291         * @param mixed $debug whether to put debug=1 in endpoint URL\r
4292         * @return string serialization of WSDL\r
4293         * @access public \r
4294         */\r
4295         function serialize($debug = 0)\r
4296         {\r
4297                 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';\r
4298                 $xml .= "\n<definitions";\r
4299                 foreach($this->namespaces as $k => $v) {\r
4300                         $xml .= " xmlns:$k=\"$v\"";\r
4301                 } \r
4302                 // 10.9.02 - add poulter fix for wsdl and tns declarations\r
4303                 if (isset($this->namespaces['wsdl'])) {\r
4304                         $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";\r
4305                 } \r
4306                 if (isset($this->namespaces['tns'])) {\r
4307                         $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";\r
4308                 } \r
4309                 $xml .= '>'; \r
4310                 // imports\r
4311                 if (sizeof($this->import) > 0) {\r
4312                         foreach($this->import as $ns => $list) {\r
4313                                 foreach ($list as $ii) {\r
4314                                         if ($ii['location'] != '') {\r
4315                                                 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';\r
4316                                         } else {\r
4317                                                 $xml .= '<import namespace="' . $ns . '" />';\r
4318                                         }\r
4319                                 }\r
4320                         } \r
4321                 } \r
4322                 // types\r
4323                 if (count($this->schemas)>=1) {\r
4324                         $xml .= "\n<types>\n";\r
4325                         foreach ($this->schemas as $ns => $list) {\r
4326                                 foreach ($list as $xs) {\r
4327                                         $xml .= $xs->serializeSchema();\r
4328                                 }\r
4329                         }\r
4330                         $xml .= '</types>';\r
4331                 } \r
4332                 // messages\r
4333                 if (count($this->messages) >= 1) {\r
4334                         foreach($this->messages as $msgName => $msgParts) {\r
4335                                 $xml .= "\n<message name=\"" . $msgName . '">';\r
4336                                 if(is_array($msgParts)){\r
4337                                         foreach($msgParts as $partName => $partType) {\r
4338                                                 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';\r
4339                                                 if (strpos($partType, ':')) {\r
4340                                                     $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));\r
4341                                                 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {\r
4342                                                     // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';\r
4343                                                     $typePrefix = 'xsd';\r
4344                                                 } else {\r
4345                                                     foreach($this->typemap as $ns => $types) {\r
4346                                                         if (isset($types[$partType])) {\r
4347                                                             $typePrefix = $this->getPrefixFromNamespace($ns);\r
4348                                                         } \r
4349                                                     } \r
4350                                                     if (!isset($typePrefix)) {\r
4351                                                         die("$partType has no namespace!");\r
4352                                                     } \r
4353                                                 }\r
4354                                                 $ns = $this->getNamespaceFromPrefix($typePrefix);\r
4355                                                 $localPart = $this->getLocalPart($partType);\r
4356                                                 $typeDef = $this->getTypeDef($localPart, $ns);\r
4357                                                 if ($typeDef['typeClass'] == 'element') {\r
4358                                                         $elementortype = 'element';\r
4359                                                         if (substr($localPart, -1) == '^') {\r
4360                                                                 $localPart = substr($localPart, 0, -1);\r
4361                                                         }\r
4362                                                 } else {\r
4363                                                         $elementortype = 'type';\r
4364                                                 }\r
4365                                                 $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';\r
4366                                         }\r
4367                                 }\r
4368                                 $xml .= '</message>';\r
4369                         } \r
4370                 } \r
4371                 // bindings & porttypes\r
4372                 if (count($this->bindings) >= 1) {\r
4373                         $binding_xml = '';\r
4374                         $portType_xml = '';\r
4375                         foreach($this->bindings as $bindingName => $attrs) {\r
4376                                 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';\r
4377                                 $binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';\r
4378                                 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';\r
4379                                 foreach($attrs['operations'] as $opName => $opParts) {\r
4380                                         $binding_xml .= "\n" . '  <operation name="' . $opName . '">';\r
4381                                         $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';\r
4382                                         if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {\r
4383                                                 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';\r
4384                                         } else {\r
4385                                                 $enc_style = '';\r
4386                                         }\r
4387                                         $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';\r
4388                                         if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {\r
4389                                                 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';\r
4390                                         } else {\r
4391                                                 $enc_style = '';\r
4392                                         }\r
4393                                         $binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';\r
4394                                         $binding_xml .= "\n" . '  </operation>';\r
4395                                         $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';\r
4396                                         if (isset($opParts['parameterOrder'])) {\r
4397                                             $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';\r
4398                                         } \r
4399                                         $portType_xml .= '>';\r
4400                                         if(isset($opParts['documentation']) && $opParts['documentation'] != '') {\r
4401                                                 $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';\r
4402                                         }\r
4403                                         $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';\r
4404                                         $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';\r
4405                                         $portType_xml .= "\n" . '  </operation>';\r
4406                                 } \r
4407                                 $portType_xml .= "\n" . '</portType>';\r
4408                                 $binding_xml .= "\n" . '</binding>';\r
4409                         } \r
4410                         $xml .= $portType_xml . $binding_xml;\r
4411                 } \r
4412                 // services\r
4413                 $xml .= "\n<service name=\"" . $this->serviceName . '">';\r
4414                 if (count($this->ports) >= 1) {\r
4415                         foreach($this->ports as $pName => $attrs) {\r
4416                                 $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';\r
4417                                 $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';\r
4418                                 $xml .= "\n" . '  </port>';\r
4419                         } \r
4420                 } \r
4421                 $xml .= "\n" . '</service>';\r
4422                 return $xml . "\n</definitions>";\r
4423         } \r
4424 \r
4425         /**\r
4426          * determine whether a set of parameters are unwrapped\r
4427          * when they are expect to be wrapped, Microsoft-style.\r
4428          *\r
4429          * @param string $type the type (element name) of the wrapper\r
4430          * @param array $parameters the parameter values for the SOAP call\r
4431          * @return boolean whether they parameters are unwrapped (and should be wrapped)\r
4432          * @access private\r
4433          */\r
4434         function parametersMatchWrapped($type, &$parameters) {\r
4435                 $this->debug("in parametersMatchWrapped type=$type, parameters=");\r
4436                 $this->appendDebug($this->varDump($parameters));\r
4437 \r
4438                 // split type into namespace:unqualified-type\r
4439                 if (strpos($type, ':')) {\r
4440                         $uqType = substr($type, strrpos($type, ':') + 1);\r
4441                         $ns = substr($type, 0, strrpos($type, ':'));\r
4442                         $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");\r
4443                         if ($this->getNamespaceFromPrefix($ns)) {\r
4444                                 $ns = $this->getNamespaceFromPrefix($ns);\r
4445                                 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");\r
4446                         }\r
4447                 } else {\r
4448                         // TODO: should the type be compared to types in XSD, and the namespace\r
4449                         // set to XSD if the type matches?\r
4450                         $this->debug("in parametersMatchWrapped: No namespace for type $type");\r
4451                         $ns = '';\r
4452                         $uqType = $type;\r
4453                 }\r
4454 \r
4455                 // get the type information\r
4456                 if (!$typeDef = $this->getTypeDef($uqType, $ns)) {\r
4457                         $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");\r
4458                         return false;\r
4459                 }\r
4460                 $this->debug("in parametersMatchWrapped: found typeDef=");\r
4461                 $this->appendDebug($this->varDump($typeDef));\r
4462                 if (substr($uqType, -1) == '^') {\r
4463                         $uqType = substr($uqType, 0, -1);\r
4464                 }\r
4465                 $phpType = $typeDef['phpType'];\r
4466                 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');\r
4467                 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");\r
4468                 \r
4469                 // we expect a complexType or element of complexType\r
4470                 if ($phpType != 'struct') {\r
4471                         $this->debug("in parametersMatchWrapped: not a struct");\r
4472                         return false;\r
4473                 }\r
4474 \r
4475                 // see whether the parameter names match the elements\r
4476                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {\r
4477                         $elements = 0;\r
4478                         $matches = 0;\r
4479                         $change = false;\r
4480                         if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {\r
4481                                 $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");\r
4482                                 $change = true;\r
4483                         }\r
4484                         foreach ($typeDef['elements'] as $name => $attrs) {\r
4485                                 if ($change) {\r
4486                                         $this->debug("in parametersMatchWrapped: change parameter $element to name $name");\r
4487                                         $parameters[$name] = $parameters[$elements];\r
4488                                         unset($parameters[$elements]);\r
4489                                         $matches++;\r
4490                                 } elseif (isset($parameters[$name])) {\r
4491                                         $this->debug("in parametersMatchWrapped: have parameter named $name");\r
4492                                         $matches++;\r
4493                                 } else {\r
4494                                         $this->debug("in parametersMatchWrapped: do not have parameter named $name");\r
4495                                 }\r
4496                                 $elements++;\r
4497                         }\r
4498 \r
4499                         $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");\r
4500                         if ($matches == 0) {\r
4501                                 return false;\r
4502                         }\r
4503                         return true;\r
4504                 }\r
4505 \r
4506                 // since there are no elements for the type, if the user passed no\r
4507                 // parameters, the parameters match wrapped.\r
4508                 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");\r
4509                 return count($parameters) == 0;\r
4510         }\r
4511 \r
4512         /**\r
4513          * serialize PHP values according to a WSDL message definition\r
4514          * contrary to the method name, this is not limited to RPC\r
4515          *\r
4516          * TODO\r
4517          * - multi-ref serialization\r
4518          * - validate PHP values against type definitions, return errors if invalid\r
4519          * \r
4520          * @param string $operation operation name\r
4521          * @param string $direction (input|output)\r
4522          * @param mixed $parameters parameter value(s)\r
4523          * @param string $bindingType (soap|soap12)\r
4524          * @return mixed parameters serialized as XML or false on error (e.g. operation not found)\r
4525          * @access public\r
4526          */\r
4527         function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {\r
4528                 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");\r
4529                 \r
4530                 //echo "in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"."<br/>";\r
4531                 //print_r($parameters);\r
4532                 //echo "<br/>";\r
4533                 \r
4534                 $this->appendDebug('parameters=' . $this->varDump($parameters));\r
4535                 \r
4536                 if ($direction != 'input' && $direction != 'output') {\r
4537                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');\r
4538                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');\r
4539                         return false;\r
4540                 } \r
4541                 if (!$opData = $this->getOperationData($operation, $bindingType)) {\r
4542                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);\r
4543                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);\r
4544                         return false;\r
4545                 }\r
4546                 $this->debug('in serializeRPCParameters: opData:');\r
4547                 $this->appendDebug($this->varDump($opData));\r
4548 \r
4549                 // Get encoding style for output and set to current\r
4550                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';\r
4551                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {\r
4552                         $encodingStyle = $opData['output']['encodingStyle'];\r
4553                         $enc_style = $encodingStyle;\r
4554                 }\r
4555 \r
4556                 // set input params\r
4557                 $xml = '';\r
4558                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {\r
4559                         $parts = &$opData[$direction]['parts'];\r
4560                         $part_count = sizeof($parts);\r
4561                         $style = $opData['style'];\r
4562                         $use = $opData[$direction]['use'];\r
4563                         $this->debug("have $part_count part(s) to serialize using $style/$use");\r
4564                         if (is_array($parameters)) {\r
4565                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);\r
4566                                 $parameter_count = count($parameters);\r
4567                                 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");\r
4568                                 // check for Microsoft-style wrapped parameters\r
4569                                 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {\r
4570                                         $this->debug('check whether the caller has wrapped the parameters');\r
4571                                         if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {\r
4572                                                 $this->debug('check whether caller\'s parameters match the wrapped ones');\r
4573                                                 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {\r
4574                                                         $this->debug('wrap the parameters for the caller');\r
4575                                                         $parameters = array('parameters' => $parameters);\r
4576                                                         $parameter_count = 1;\r
4577                                                 }\r
4578                                         }\r
4579                                 }\r
4580                                 foreach ($parts as $name => $type) {\r
4581                                         //echo "serializing part $name of type $type"."<br/>";\r
4582                                         $this->debug("serializing part $name of type $type");\r
4583                                         // Track encoding style\r
4584                                         if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {\r
4585                                                 $encodingStyle = $opData[$direction]['encodingStyle'];                  \r
4586                                                 $enc_style = $encodingStyle;\r
4587                                         } else {\r
4588                                                 $enc_style = false;\r
4589                                         }\r
4590                                         // NOTE: add error handling here\r
4591                                         // if serializeType returns false, then catch global error and fault\r
4592                                         if ($parametersArrayType == 'arraySimple') {\r
4593                                                 //echo "arraySimple<br/>";\r
4594                                                 $p = array_shift($parameters);\r
4595                                                 $this->debug('calling serializeType w/indexed param');\r
4596                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);\r
4597                                         } elseif (isset($parameters[$name])) {\r
4598                                                 //echo "array SECOND<br/>";\r
4599                                                 $this->debug('calling serializeType w/named param');\r
4600                                                 //echo "PARAMS: ";\r
4601                                                 //print_r ($parameters[$name]); \r
4602                                                 //echo "<br/>";\r
4603                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);\r
4604                                         } else {\r
4605                                                 //echo "array THIRD<br/>";\r
4606                                                 // TODO: only send nillable\r
4607                                                 $this->debug('calling serializeType w/null param');\r
4608                                                 //echo "PARAMS: ";\r
4609                                                 //print_r ($parameters); \r
4610                                                 //echo "<br/>";\r
4611                                                 //For some reason this does not work!! I am heavily (!) thinking about WHY the params here\r
4612                                                 //are passed as NULL?! What should be the resulting XML if you pass NULL as paramlist?!?!?\r
4613                                                 //seba.wagner at gmail dot com 2008/05/12\r
4614                                                 //$xml .= $this->serializeType($name, $type, null, $use, $enc_style);\r
4615                                                 $xml .= $this->serializeLinuxAxis2Type($name, $type, $parameters, $use, $enc_style);\r
4616                                         }\r
4617                                         //echo "PART XML: ".htmlentities($xml)."<br/>";\r
4618                                 }\r
4619                         } else {\r
4620                                 $this->debug('no parameters passed.');\r
4621                         }\r
4622                 }\r
4623                 $this->debug("serializeRPCParameters returning: $xml");\r
4624                 //echo "<br/>"."serializeRPCParameters returning: ".htmlentities($xml)."<BR/>";\r
4625                 return $xml;\r
4626         } \r
4627         \r
4628         /**\r
4629          * serialize a PHP value according to a WSDL message definition\r
4630          * \r
4631          * TODO\r
4632          * - multi-ref serialization\r
4633          * - validate PHP values against type definitions, return errors if invalid\r
4634          * \r
4635          * @param string $operation operation name\r
4636          * @param string $direction (input|output)\r
4637          * @param mixed $parameters parameter value(s)\r
4638          * @return mixed parameters serialized as XML or false on error (e.g. operation not found)\r
4639          * @access public\r
4640          * @deprecated\r
4641          */\r
4642         function serializeParameters($operation, $direction, $parameters)\r
4643         {\r
4644                 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); \r
4645                 $this->appendDebug('parameters=' . $this->varDump($parameters));\r
4646                 \r
4647                 if ($direction != 'input' && $direction != 'output') {\r
4648                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');\r
4649                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');\r
4650                         return false;\r
4651                 } \r
4652                 if (!$opData = $this->getOperationData($operation)) {\r
4653                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);\r
4654                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);\r
4655                         return false;\r
4656                 }\r
4657                 $this->debug('opData:');\r
4658                 $this->appendDebug($this->varDump($opData));\r
4659                 \r
4660                 // Get encoding style for output and set to current\r
4661                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';\r
4662                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {\r
4663                         $encodingStyle = $opData['output']['encodingStyle'];\r
4664                         $enc_style = $encodingStyle;\r
4665                 }\r
4666                 \r
4667                 // set input params\r
4668                 $xml = '';\r
4669                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {\r
4670                         \r
4671                         $use = $opData[$direction]['use'];\r
4672                         $this->debug("use=$use");\r
4673                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');\r
4674                         if (is_array($parameters)) {\r
4675                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);\r
4676                                 $this->debug('have ' . $parametersArrayType . ' parameters');\r
4677                                 foreach($opData[$direction]['parts'] as $name => $type) {\r
4678                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');\r
4679                                         // Track encoding style\r
4680                                         if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {\r
4681                                                 $encodingStyle = $opData[$direction]['encodingStyle'];                  \r
4682                                                 $enc_style = $encodingStyle;\r
4683                                         } else {\r
4684                                                 $enc_style = false;\r
4685                                         }\r
4686                                         // NOTE: add error handling here\r
4687                                         // if serializeType returns false, then catch global error and fault\r
4688                                         if ($parametersArrayType == 'arraySimple') {\r
4689                                                 $p = array_shift($parameters);\r
4690                                                 $this->debug('calling serializeType w/indexed param');\r
4691                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);\r
4692                                         } elseif (isset($parameters[$name])) {\r
4693                                                 $this->debug('calling serializeType w/named param');\r
4694                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);\r
4695                                         } else {\r
4696                                                 // TODO: only send nillable\r
4697                                                 $this->debug('calling serializeType w/null param');\r
4698                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);\r
4699                                         }\r
4700                                 }\r
4701                         } else {\r
4702                                 $this->debug('no parameters passed.');\r
4703                         }\r
4704                 }\r
4705                 $this->debug("serializeParameters returning: $xml");\r
4706                 return $xml;\r
4707         } \r
4708         \r
4709         function serializeLinuxAxis2Type($name, $type, $params, $use='encoded', $encodingStyle=false, $unqualified=false)\r
4710         {\r
4711                 $xml = '';\r
4712                 if (strpos($type, ':')) {\r
4713                         $uqType = substr($type, strrpos($type, ':') + 1);\r
4714                         $ns = substr($type, 0, strrpos($type, ':'));\r
4715                         $this->debug("in serializeType: got a prefixed type: $uqType, $ns");\r
4716                         if ($this->getNamespaceFromPrefix($ns)) {\r
4717                                 $ns = $this->getNamespaceFromPrefix($ns);\r
4718                                 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");\r
4719                         }\r
4720 \r
4721                         //echo "NameSpace: ".$ns."<br/>";\r
4722                         //echo "Method: ".$uqType."<br/>";\r
4723                         $methodName = substr($uqType,0,strlen($uqType)-1);\r
4724                         \r
4725                         //echo "Method: ".$methodName."<br/>";\r
4726                         \r
4727                         $xml .= '<'.$methodName.' xmlns="'.$ns.'">';\r
4728                         \r
4729                         foreach ($params as $key => $val){\r
4730                                 //echo "Key".$key." Value".$val."<br/>";\r
4731                                 \r
4732                                 $insertVal = $val;\r
4733                                 \r
4734                                 //If Boolean rewrite the Value\r
4735                                 if (is_bool($val)){\r
4736                                         if ($val) {\r
4737                                                 $insertVal = "true";\r
4738                                         } else {\r
4739                                                 $insertVal = "false";\r
4740                                         }\r
4741                                 }\r
4742                                 $xml .= '<'.$key.'>'.$insertVal.'</'.$key.'>';\r
4743                         }\r
4744                         \r
4745                         $xml .= '</'.$methodName.'>';\r
4746                         \r
4747                         //echo htmlentities($xml)."<br/>";\r
4748                         return $xml;\r
4749                         //<loginUser xmlns="http://services.axis.openmeetings.org">\r
4750                 }\r
4751                 \r
4752         }\r
4753         /**\r
4754          * serializes a PHP value according a given type definition\r
4755          * \r
4756          * @param string $name name of value (part or element)\r
4757          * @param string $type XML schema type of value (type or element)\r
4758          * @param mixed $value a native PHP value (parameter value)\r
4759          * @param string $use use for part (encoded|literal)\r
4760          * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)\r
4761          * @param boolean $unqualified a kludge for what should be XML namespace form handling\r
4762          * @return string value serialized as an XML string\r
4763          * @access private\r
4764          */\r
4765         function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)\r
4766         {\r
4767                 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));\r
4768                 //echo "in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")."<br/>";\r
4769                 \r
4770                 //echo "SerialieType: ".$type."<br/>";\r
4771                 \r
4772                 $this->appendDebug("value=" . $this->varDump($value));\r
4773                 if($use == 'encoded' && $encodingStyle) {\r
4774                         $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';\r
4775                 }\r
4776 \r
4777                 // if a soapval has been supplied, let its type override the WSDL\r
4778         if (is_object($value) && get_class($value) == 'soapval') {\r
4779                 ////echo "IS OBJECT "."<br/>";\r
4780                 if ($value->type_ns) {\r
4781                         $type = $value->type_ns . ':' . $value->type;\r
4782                         $forceType = true;\r
4783                         $this->debug("in serializeType: soapval overrides type to $type");\r
4784                 } elseif ($value->type) {\r
4785                         $type = $value->type;\r
4786                         $forceType = true;\r
4787                         $this->debug("in serializeType: soapval overrides type to $type");\r
4788                 } else {\r
4789                         $forceType = false;\r
4790                         $this->debug("in serializeType: soapval does not override type");\r
4791                 }\r
4792                 $attrs = $value->attributes;\r
4793                 $value = $value->value;\r
4794                 $this->debug("in serializeType: soapval overrides value to $value");\r
4795                 if ($attrs) {\r
4796                         if (!is_array($value)) {\r
4797                                 $value['!'] = $value;\r
4798                         }\r
4799                         foreach ($attrs as $n => $v) {\r
4800                                 $value['!' . $n] = $v;\r
4801                         }\r
4802                         $this->debug("in serializeType: soapval provides attributes");\r
4803                     }\r
4804         } else {\r
4805                 $forceType = false;\r
4806         }\r
4807 \r
4808                 $xml = '';\r
4809                 if (strpos($type, ':')) {\r
4810                         $uqType = substr($type, strrpos($type, ':') + 1);\r
4811                         \r
4812                         //echo "FIRST ### uqType: ".$uqType."<br/>";\r
4813                         \r
4814                         $ns = substr($type, 0, strrpos($type, ':'));\r
4815                         $this->debug("in serializeType: got a prefixed type: $uqType, $ns");\r
4816                         if ($this->getNamespaceFromPrefix($ns)) {\r
4817                                 $ns = $this->getNamespaceFromPrefix($ns);\r
4818                                 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");\r
4819                         }\r
4820 \r
4821                         //echo "NameSpace: ".$ns."<br/>";\r
4822                         if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){\r
4823                                 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');\r
4824                                 if ($unqualified && $use == 'literal') {\r
4825                                         $elementNS = " xmlns=\"\"";\r
4826                                 } else {\r
4827                                         $elementNS = '';\r
4828                                 }\r
4829                                 if (is_null($value)) {\r
4830                                         if ($use == 'literal') {\r
4831                                                 // TODO: depends on minOccurs\r
4832                                                 $xml = "<$name$elementNS/>";\r
4833                                         } else {\r
4834                                                 // TODO: depends on nillable, which should be checked before calling this method\r
4835                                                 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";\r
4836                                         }\r
4837                                         $this->debug("in serializeType: returning: $xml");\r
4838                                         return $xml;\r
4839                                 }\r
4840                                 //echo "uqType: ".$uqType."<br/>";\r
4841                                 if ($uqType == 'Array') {\r
4842                                         // JBoss/Axis does this sometimes\r
4843                                         return $this->serialize_val($value, $name, false, false, false, false, $use);\r
4844                                 }\r
4845                         if ($uqType == 'boolean') {\r
4846                                 if ((is_string($value) && $value == 'false') || (! $value)) {\r
4847                                                 $value = 'false';\r
4848                                         } else {\r
4849                                                 $value = 'true';\r
4850                                         }\r
4851                                 } \r
4852                                 if ($uqType == 'string' && gettype($value) == 'string') {\r
4853                                         $value = $this->expandEntities($value);\r
4854                                 }\r
4855                                 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {\r
4856                                         $value = sprintf("%.0lf", $value);\r
4857                                 }\r
4858                                 // it's a scalar\r
4859                                 // TODO: what about null/nil values?\r
4860                                 // check type isn't a custom type extending xmlschema namespace\r
4861                                 if (!$this->getTypeDef($uqType, $ns)) {\r
4862                                         if ($use == 'literal') {\r
4863                                                 if ($forceType) {\r
4864                                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";\r
4865                                                 } else {\r
4866                                                         $xml = "<$name$elementNS>$value</$name>";\r
4867                                                 }\r
4868                                         } else {\r
4869                                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";\r
4870                                         }\r
4871                                         $this->debug("in serializeType: returning: $xml");\r
4872                                         return $xml;\r
4873                                 }\r
4874                                 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');\r
4875                         } else if ($ns == 'http://xml.apache.org/xml-soap') {\r
4876                                 $this->debug('in serializeType: appears to be Apache SOAP type');\r
4877                                 if ($uqType == 'Map') {\r
4878                                         $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');\r
4879                                         if (! $tt_prefix) {\r
4880                                                 $this->debug('in serializeType: Add namespace for Apache SOAP type');\r
4881                                                 $tt_prefix = 'ns' . rand(1000, 9999);\r
4882                                                 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';\r
4883                                                 // force this to be added to usedNamespaces\r
4884                                                 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');\r
4885                                         }\r
4886                                         $contents = '';\r
4887                                         foreach($value as $k => $v) {\r
4888                                                 $this->debug("serializing map element: key $k, value $v");\r
4889                                                 $contents .= '<item>';\r
4890                                                 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);\r
4891                                                 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);\r
4892                                                 $contents .= '</item>';\r
4893                                         }\r
4894                                         if ($use == 'literal') {\r
4895                                                 if ($forceType) {\r
4896                                                         $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";\r
4897                                                 } else {\r
4898                                                         $xml = "<$name>$contents</$name>";\r
4899                                                 }\r
4900                                         } else {\r
4901                                                 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";\r
4902                                         }\r
4903                                         $this->debug("in serializeType: returning: $xml");\r
4904                                         return $xml;\r
4905                                 }\r
4906                                 $this->debug('in serializeType: Apache SOAP type, but only support Map');\r
4907                         }\r
4908                 } else {\r
4909                         // TODO: should the type be compared to types in XSD, and the namespace\r
4910                         // set to XSD if the type matches?\r
4911                         $this->debug("in serializeType: No namespace for type $type");\r
4912                         $ns = '';\r
4913                         $uqType = $type;\r
4914                 }\r
4915                 if(!$typeDef = $this->getTypeDef($uqType, $ns)){\r
4916                         $this->setError("$type ($uqType) is not a supported type.");\r
4917                         $this->debug("in serializeType: $type ($uqType) is not a supported type.");\r
4918                         return false;\r
4919                 } else {\r
4920                         $this->debug("in serializeType: found typeDef");\r
4921                         $this->appendDebug('typeDef=' . $this->varDump($typeDef));\r
4922                         if (substr($uqType, -1) == '^') {\r
4923                                 $uqType = substr($uqType, 0, -1);\r
4924                         }\r
4925                 }\r
4926                 $phpType = $typeDef['phpType'];\r
4927                 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); \r
4928                 // if php type == struct, map value to the <all> element names\r
4929                 if ($phpType == 'struct') {\r
4930                         if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {\r
4931                                 $elementName = $uqType;\r
4932                                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {\r
4933                                         $elementNS = " xmlns=\"$ns\"";\r
4934                                 } else {\r
4935                                         $elementNS = " xmlns=\"\"";\r
4936                                 }\r
4937                         } else {\r
4938                                 $elementName = $name;\r
4939                                 if ($unqualified) {\r
4940                                         $elementNS = " xmlns=\"\"";\r
4941                                 } else {\r
4942                                         $elementNS = '';\r
4943                                 }\r
4944                         }\r
4945                         if (is_null($value)) {\r
4946                                 if ($use == 'literal') {\r
4947                                         // TODO: depends on minOccurs\r
4948                                         $xml = "<$elementName$elementNS/>";\r
4949                                 } else {\r
4950                                         $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";\r
4951                                 }\r
4952                                 $this->debug("in serializeType: returning: $xml");\r
4953                                 return $xml;\r
4954                         }\r
4955                         if (is_object($value)) {\r
4956                                 $value = get_object_vars($value);\r
4957                         }\r
4958                         if (is_array($value)) {\r
4959                                 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);\r
4960                                 if ($use == 'literal') {\r
4961                                         if ($forceType) {\r
4962                                                 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";\r
4963                                         } else {\r
4964                                                 $xml = "<$elementName$elementNS$elementAttrs>";\r
4965                                         }\r
4966                                 } else {\r
4967                                         $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";\r
4968                                 }\r
4969         \r
4970                                 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);\r
4971                                 $xml .= "</$elementName>";\r
4972                         } else {\r
4973                                 $this->debug("in serializeType: phpType is struct, but value is not an array");\r
4974                                 $this->setError("phpType is struct, but value is not an array: see debug output for details");\r
4975                                 $xml = '';\r
4976                         }\r
4977                 } elseif ($phpType == 'array') {\r
4978                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {\r
4979                                 $elementNS = " xmlns=\"$ns\"";\r
4980                         } else {\r
4981                                 if ($unqualified) {\r
4982                                         $elementNS = " xmlns=\"\"";\r
4983                                 } else {\r
4984                                         $elementNS = '';\r
4985                                 }\r
4986                         }\r
4987                         if (is_null($value)) {\r
4988                                 if ($use == 'literal') {\r
4989                                         // TODO: depends on minOccurs\r
4990                                         $xml = "<$name$elementNS/>";\r
4991                                 } else {\r
4992                                         $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .\r
4993                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .\r
4994                                                 ":Array\" " .\r
4995                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .\r
4996                                                 ':arrayType="' .\r
4997                                                 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .\r
4998                                                 ':' .\r
4999                                                 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";\r
5000                                 }\r
5001                                 $this->debug("in serializeType: returning: $xml");\r
5002                                 return $xml;\r
5003                         }\r
5004                         if (isset($typeDef['multidimensional'])) {\r
5005                                 $nv = array();\r
5006                                 foreach($value as $v) {\r
5007                                         $cols = ',' . sizeof($v);\r
5008                                         $nv = array_merge($nv, $v);\r
5009                                 } \r
5010                                 $value = $nv;\r
5011                         } else {\r
5012                                 $cols = '';\r
5013                         } \r
5014                         if (is_array($value) && sizeof($value) >= 1) {\r
5015                                 ////echo "IS ARRAY !! ".sizeof($value)."<br/>";\r
5016                                 $rows = sizeof($value);\r
5017                                 $contents = '';\r
5018                                 foreach($value as $k => $v) {\r
5019                                         \r
5020                                         ////echo $k." => ".$v."<br/>";\r
5021                                         \r
5022                                         $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");\r
5023                                         //if (strpos($typeDef['arrayType'], ':') ) {\r
5024                                         if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {\r
5025                                             //echo "CALL AGAIN HEHRERERERER ########### <br/>";\r
5026                                             $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);\r
5027                                         } else {\r
5028                                             $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);\r
5029                                         } \r
5030                                 }\r
5031                         } else {\r
5032                                 $rows = 0;\r
5033                                 $contents = null;\r
5034                         }\r
5035                         // TODO: for now, an empty value will be serialized as a zero element\r
5036                         // array.  Revisit this when coding the handling of null/nil values.\r
5037                         if ($use == 'literal') {\r
5038                                 $xml = "<$name$elementNS>"\r
5039                                         .$contents\r
5040                                         ."</$name>";\r
5041                         } else {\r
5042                                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.\r
5043                                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')\r
5044                                         .':arrayType="'\r
5045                                         .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))\r
5046                                         .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"\r
5047                                         .$contents\r
5048                                         ."</$name>";\r
5049                         }\r
5050                 } elseif ($phpType == 'scalar') {\r
5051                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {\r
5052                                 $elementNS = " xmlns=\"$ns\"";\r
5053                         } else {\r
5054                                 if ($unqualified) {\r
5055                                         $elementNS = " xmlns=\"\"";\r
5056                                 } else {\r
5057                                         $elementNS = '';\r
5058                                 }\r
5059                         }\r
5060                         if ($use == 'literal') {\r
5061                                 if ($forceType) {\r
5062                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";\r
5063                                 } else {\r
5064                                         $xml = "<$name$elementNS>$value</$name>";\r
5065                                 }\r
5066                         } else {\r
5067                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";\r
5068                         }\r
5069                 }\r
5070                 $this->debug("in serializeType: returning: $xml");\r
5071                 return $xml;\r
5072         }\r
5073         \r
5074         /**\r
5075          * serializes the attributes for a complexType\r
5076          *\r
5077          * @param array $typeDef our internal representation of an XML schema type (or element)\r
5078          * @param mixed $value a native PHP value (parameter value)\r
5079          * @param string $ns the namespace of the type\r
5080          * @param string $uqType the local part of the type\r
5081          * @return string value serialized as an XML string\r
5082          * @access private\r
5083          */\r
5084         function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {\r
5085                 $xml = '';\r
5086                 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {\r
5087                         $this->debug("serialize attributes for XML Schema type $ns:$uqType");\r
5088                         if (is_array($value)) {\r
5089                                 $xvalue = $value;\r
5090                         } elseif (is_object($value)) {\r
5091                                 $xvalue = get_object_vars($value);\r
5092                         } else {\r
5093                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");\r
5094                                 $xvalue = array();\r
5095                         }\r
5096                         foreach ($typeDef['attrs'] as $aName => $attrs) {\r
5097                                 if (isset($xvalue['!' . $aName])) {\r
5098                                         $xname = '!' . $aName;\r
5099                                         $this->debug("value provided for attribute $aName with key $xname");\r
5100                                 } elseif (isset($xvalue[$aName])) {\r
5101                                         $xname = $aName;\r
5102                                         $this->debug("value provided for attribute $aName with key $xname");\r
5103                                 } elseif (isset($attrs['default'])) {\r
5104                                         $xname = '!' . $aName;\r
5105                                         $xvalue[$xname] = $attrs['default'];\r
5106                                         $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);\r
5107                                 } else {\r
5108                                         $xname = '';\r
5109                                         $this->debug("no value provided for attribute $aName");\r
5110                                 }\r
5111                                 if ($xname) {\r
5112                                         $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";\r
5113                                 }\r
5114                         } \r
5115                 } else {\r
5116                         $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");\r
5117                 }\r
5118                 if (isset($typeDef['extensionBase'])) {\r
5119                         $ns = $this->getPrefix($typeDef['extensionBase']);\r
5120                         $uqType = $this->getLocalPart($typeDef['extensionBase']);\r
5121                         if ($this->getNamespaceFromPrefix($ns)) {\r
5122                                 $ns = $this->getNamespaceFromPrefix($ns);\r
5123                         }\r
5124                         if ($typeDef = $this->getTypeDef($uqType, $ns)) {\r
5125                                 $this->debug("serialize attributes for extension base $ns:$uqType");\r
5126                                 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);\r
5127                         } else {\r
5128                                 $this->debug("extension base $ns:$uqType is not a supported type");\r
5129                         }\r
5130                 }\r
5131                 return $xml;\r
5132         }\r
5133 \r
5134         /**\r
5135          * serializes the elements for a complexType\r
5136          *\r
5137          * @param array $typeDef our internal representation of an XML schema type (or element)\r
5138          * @param mixed $value a native PHP value (parameter value)\r
5139          * @param string $ns the namespace of the type\r
5140          * @param string $uqType the local part of the type\r
5141          * @param string $use use for part (encoded|literal)\r
5142          * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)\r
5143          * @return string value serialized as an XML string\r
5144          * @access private\r
5145          */\r
5146         function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {\r
5147                 $xml = '';\r
5148                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {\r
5149                         $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");\r
5150                         if (is_array($value)) {\r
5151                                 $xvalue = $value;\r
5152                         } elseif (is_object($value)) {\r
5153                                 $xvalue = get_object_vars($value);\r
5154                         } else {\r
5155                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");\r
5156                                 $xvalue = array();\r
5157                         }\r
5158                         // toggle whether all elements are present - ideally should validate against schema\r
5159                         if (count($typeDef['elements']) != count($xvalue)){\r
5160                                 $optionals = true;\r
5161                         }\r
5162                         foreach ($typeDef['elements'] as $eName => $attrs) {\r
5163                                 if (!isset($xvalue[$eName])) {\r
5164                                         if (isset($attrs['default'])) {\r
5165                                                 $xvalue[$eName] = $attrs['default'];\r
5166                                                 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);\r
5167                                         }\r
5168                                 }\r
5169                                 // if user took advantage of a minOccurs=0, then only serialize named parameters\r
5170                                 if (isset($optionals)\r
5171                                     && (!isset($xvalue[$eName])) \r
5172                                         && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')\r
5173                                         ){\r
5174                                         if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {\r
5175                                                 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);\r
5176                                         }\r
5177                                         // do nothing\r
5178                                         $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");\r
5179                                 } else {\r
5180                                         // get value\r
5181                                         if (isset($xvalue[$eName])) {\r
5182                                             $v = $xvalue[$eName];\r
5183                                         } else {\r
5184                                             $v = null;\r
5185                                         }\r
5186                                         if (isset($attrs['form'])) {\r
5187                                                 $unqualified = ($attrs['form'] == 'unqualified');\r
5188                                         } else {\r
5189                                                 $unqualified = false;\r
5190                                         }\r
5191                                         if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {\r
5192                                                 $vv = $v;\r
5193                                                 foreach ($vv as $k => $v) {\r
5194                                                         if (isset($attrs['type']) || isset($attrs['ref'])) {\r
5195                                                                 // serialize schema-defined type\r
5196                                                             $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);\r
5197                                                         } else {\r
5198                                                                 // serialize generic type (can this ever really happen?)\r
5199                                                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");\r
5200                                                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);\r
5201                                                         }\r
5202                                                 }\r
5203                                         } else {\r
5204                                                 if (isset($attrs['type']) || isset($attrs['ref'])) {\r
5205                                                         // serialize schema-defined type\r
5206                                                     $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);\r
5207                                                 } else {\r
5208                                                         // serialize generic type (can this ever really happen?)\r
5209                                                     $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");\r
5210                                                     $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);\r
5211                                                 }\r
5212                                         }\r
5213                                 }\r
5214                         } \r
5215                 } else {\r
5216                         $this->debug("no elements to serialize for XML Schema type $ns:$uqType");\r
5217                 }\r
5218                 if (isset($typeDef['extensionBase'])) {\r
5219                         $ns = $this->getPrefix($typeDef['extensionBase']);\r
5220                         $uqType = $this->getLocalPart($typeDef['extensionBase']);\r
5221                         if ($this->getNamespaceFromPrefix($ns)) {\r
5222                                 $ns = $this->getNamespaceFromPrefix($ns);\r
5223                         }\r
5224                         if ($typeDef = $this->getTypeDef($uqType, $ns)) {\r
5225                                 $this->debug("serialize elements for extension base $ns:$uqType");\r
5226                                 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);\r
5227                         } else {\r
5228                                 $this->debug("extension base $ns:$uqType is not a supported type");\r
5229                         }\r
5230                 }\r
5231                 return $xml;\r
5232         }\r
5233 \r
5234         /**\r
5235         * adds an XML Schema complex type to the WSDL types\r
5236         *\r
5237         * @param string $name\r
5238         * @param string $typeClass (complexType|simpleType|attribute)\r
5239         * @param string $phpType currently supported are array and struct (php assoc array)\r
5240         * @param string $compositor (all|sequence|choice)\r
5241         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)\r
5242         * @param array $elements e.g. array ( name => array(name=>'',type=>'') )\r
5243         * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))\r
5244         * @param string $arrayType as namespace:name (xsd:string)\r
5245         * @see nusoap_xmlschema\r
5246         * @access public\r
5247         */\r
5248         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {\r
5249                 if (count($elements) > 0) {\r
5250                         $eElements = array();\r
5251                 foreach($elements as $n => $e){\r
5252                     // expand each element\r
5253                     $ee = array();\r
5254                     foreach ($e as $k => $v) {\r
5255                             $k = strpos($k,':') ? $this->expandQname($k) : $k;\r
5256                             $v = strpos($v,':') ? $this->expandQname($v) : $v;\r
5257                             $ee[$k] = $v;\r
5258                         }\r
5259                         $eElements[$n] = $ee;\r
5260                 }\r
5261                 $elements = $eElements;\r
5262                 }\r
5263                 \r
5264                 if (count($attrs) > 0) {\r
5265                 foreach($attrs as $n => $a){\r
5266                     // expand each attribute\r
5267                     foreach ($a as $k => $v) {\r
5268                             $k = strpos($k,':') ? $this->expandQname($k) : $k;\r
5269                             $v = strpos($v,':') ? $this->expandQname($v) : $v;\r
5270                             $aa[$k] = $v;\r
5271                         }\r
5272                         $eAttrs[$n] = $aa;\r
5273                 }\r
5274                 $attrs = $eAttrs;\r
5275                 }\r
5276 \r
5277                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;\r
5278                 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;\r
5279 \r
5280                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];\r
5281                 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);\r
5282         }\r
5283 \r
5284         /**\r
5285         * adds an XML Schema simple type to the WSDL types\r
5286         *\r
5287         * @param string $name\r
5288         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)\r
5289         * @param string $typeClass (should always be simpleType)\r
5290         * @param string $phpType (should always be scalar)\r
5291         * @param array $enumeration array of values\r
5292         * @see nusoap_xmlschema\r
5293         * @access public\r
5294         */\r
5295         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {\r
5296                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;\r
5297 \r
5298                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];\r
5299                 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);\r
5300         }\r
5301 \r
5302         /**\r
5303         * adds an element to the WSDL types\r
5304         *\r
5305         * @param array $attrs attributes that must include name and type\r
5306         * @see nusoap_xmlschema\r
5307         * @access public\r
5308         */\r
5309         function addElement($attrs) {\r
5310                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];\r
5311                 $this->schemas[$typens][0]->addElement($attrs);\r
5312         }\r
5313 \r
5314         /**\r
5315         * register an operation with the server\r
5316         * \r
5317         * @param string $name operation (method) name\r
5318         * @param array $in assoc array of input values: key = param name, value = param type\r
5319         * @param array $out assoc array of output values: key = param name, value = param type\r
5320         * @param string $namespace optional The namespace for the operation\r
5321         * @param string $soapaction optional The soapaction for the operation\r
5322         * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically\r
5323         * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)\r
5324         * @param string $documentation optional The description to include in the WSDL\r
5325         * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)\r
5326         * @access public \r
5327         */\r
5328         function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){\r
5329                 if ($use == 'encoded' && $encodingStyle == '') {\r
5330                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';\r
5331                 }\r
5332 \r
5333                 if ($style == 'document') {\r
5334                         $elements = array();\r
5335                         foreach ($in as $n => $t) {\r
5336                                 $elements[$n] = array('name' => $n, 'type' => $t);\r
5337                         }\r
5338                         $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);\r
5339                         $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));\r
5340                         $in = array('parameters' => 'tns:' . $name . '^');\r
5341 \r
5342                         $elements = array();\r
5343                         foreach ($out as $n => $t) {\r
5344                                 $elements[$n] = array('name' => $n, 'type' => $t);\r
5345                         }\r
5346                         $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);\r
5347                         $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));\r
5348                         $out = array('parameters' => 'tns:' . $name . 'Response' . '^');\r
5349                 }\r
5350 \r
5351                 // get binding\r
5352                 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =\r
5353                 array(\r
5354                 'name' => $name,\r
5355                 'binding' => $this->serviceName . 'Binding',\r
5356                 'endpoint' => $this->endpoint,\r
5357                 'soapAction' => $soapaction,\r
5358                 'style' => $style,\r
5359                 'input' => array(\r
5360                         'use' => $use,\r
5361                         'namespace' => $namespace,\r
5362                         'encodingStyle' => $encodingStyle,\r
5363                         'message' => $name . 'Request',\r
5364                         'parts' => $in),\r
5365                 'output' => array(\r
5366                         'use' => $use,\r
5367                         'namespace' => $namespace,\r
5368                         'encodingStyle' => $encodingStyle,\r
5369                         'message' => $name . 'Response',\r
5370                         'parts' => $out),\r
5371                 'namespace' => $namespace,\r
5372                 'transport' => 'http://schemas.xmlsoap.org/soap/http',\r
5373                 'documentation' => $documentation); \r
5374                 // add portTypes\r
5375                 // add messages\r
5376                 if($in)\r
5377                 {\r
5378                         foreach($in as $pName => $pType)\r
5379                         {\r
5380                                 if(strpos($pType,':')) {\r
5381                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);\r
5382                                 }\r
5383                                 $this->messages[$name.'Request'][$pName] = $pType;\r
5384                         }\r
5385                 } else {\r
5386             $this->messages[$name.'Request']= '0';\r
5387         }\r
5388                 if($out)\r
5389                 {\r
5390                         foreach($out as $pName => $pType)\r
5391                         {\r
5392                                 if(strpos($pType,':')) {\r
5393                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);\r
5394                                 }\r
5395                                 $this->messages[$name.'Response'][$pName] = $pType;\r
5396                         }\r
5397                 } else {\r
5398             $this->messages[$name.'Response']= '0';\r
5399         }\r
5400                 return true;\r
5401         } \r
5402 }\r
5403 ?><?php\r
5404 \r
5405 \r
5406 \r
5407 /**\r
5408 *\r
5409 * nusoap_parser class parses SOAP XML messages into native PHP values\r
5410 *\r
5411 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
5412 * @author   Scott Nichol <snichol@users.sourceforge.net>\r
5413 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
5414 * @access   public\r
5415 */\r
5416 class nusoap_parser extends nusoap_base {\r
5417 \r
5418         var $xml = '';\r
5419         var $xml_encoding = '';\r
5420         var $method = '';\r
5421         var $root_struct = '';\r
5422         var $root_struct_name = '';\r
5423         var $root_struct_namespace = '';\r
5424         var $root_header = '';\r
5425     var $document = '';                 // incoming SOAP body (text)\r
5426         // determines where in the message we are (envelope,header,body,method)\r
5427         var $status = '';\r
5428         var $position = 0;\r
5429         var $depth = 0;\r
5430         var $default_namespace = '';\r
5431         var $namespaces = array();\r
5432         var $message = array();\r
5433     var $parent = '';\r
5434         var $fault = false;\r
5435         var $fault_code = '';\r
5436         var $fault_str = '';\r
5437         var $fault_detail = '';\r
5438         var $depth_array = array();\r
5439         var $debug_flag = true;\r
5440         var $soapresponse = NULL;       // parsed SOAP Body\r
5441         var $soapheader = NULL;         // parsed SOAP Header\r
5442         var $responseHeaders = '';      // incoming SOAP headers (text)\r
5443         var $body_position = 0;\r
5444         // for multiref parsing:\r
5445         // array of id => pos\r
5446         var $ids = array();\r
5447         // array of id => hrefs => pos\r
5448         var $multirefs = array();\r
5449         // toggle for auto-decoding element content\r
5450         var $decode_utf8 = true;\r
5451 \r
5452         /**\r
5453         * constructor that actually does the parsing\r
5454         *\r
5455         * @param    string $xml SOAP message\r
5456         * @param    string $encoding character encoding scheme of message\r
5457         * @param    string $method method for which XML is parsed (unused?)\r
5458         * @param    string $decode_utf8 whether to decode UTF-8 to ISO-8859-1\r
5459         * @access   public\r
5460         */\r
5461         function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){\r
5462                 parent::nusoap_base();\r
5463                 $this->xml = $xml;\r
5464                 $this->xml_encoding = $encoding;\r
5465                 $this->method = $method;\r
5466                 $this->decode_utf8 = $decode_utf8;\r
5467 \r
5468                 // Check whether content has been read.\r
5469                 if(!empty($xml)){\r
5470                         // Check XML encoding\r
5471                         $pos_xml = strpos($xml, '<?xml');\r
5472                         if ($pos_xml !== FALSE) {\r
5473                                 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);\r
5474                                 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {\r
5475                                         $xml_encoding = $res[1];\r
5476                                         if (strtoupper($xml_encoding) != $encoding) {\r
5477                                                 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";\r
5478                                                 $this->debug($err);\r
5479                                                 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {\r
5480                                                         $this->setError($err);\r
5481                                                         return;\r
5482                                                 }\r
5483                                                 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed\r
5484                                         } else {\r
5485                                                 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');\r
5486                                         }\r
5487                                 } else {\r
5488                                         $this->debug('No encoding specified in XML declaration');\r
5489                                 }\r
5490                         } else {\r
5491                                 $this->debug('No XML declaration');\r
5492                         }\r
5493                         $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);\r
5494                         // Create an XML parser - why not xml_parser_create_ns?\r
5495                         $this->parser = xml_parser_create($this->xml_encoding);\r
5496                         // Set the options for parsing the XML data.\r
5497                         //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);\r
5498                         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);\r
5499                         xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);\r
5500                         // Set the object for the parser.\r
5501                         xml_set_object($this->parser, $this);\r
5502                         // Set the element handlers for the parser.\r
5503                         xml_set_element_handler($this->parser, 'start_element','end_element');\r
5504                         xml_set_character_data_handler($this->parser,'character_data');\r
5505 \r
5506                         // Parse the XML file.\r
5507                         if(!xml_parse($this->parser,$xml,true)){\r
5508                             // Display an error message.\r
5509                             $err = sprintf('XML error parsing SOAP payload on line %d: %s',\r
5510                             xml_get_current_line_number($this->parser),\r
5511                             xml_error_string(xml_get_error_code($this->parser)));\r
5512                                 $this->debug($err);\r
5513                                 $this->debug("XML payload:\n" . $xml);\r
5514                                 $this->setError($err);\r
5515                         } else {\r
5516                                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);\r
5517                                 // get final value\r
5518                                 $this->soapresponse = $this->message[$this->root_struct]['result'];\r
5519                                 // get header value\r
5520                                 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){\r
5521                                         $this->soapheader = $this->message[$this->root_header]['result'];\r
5522                                 }\r
5523                                 // resolve hrefs/ids\r
5524                                 if(sizeof($this->multirefs) > 0){\r
5525                                         foreach($this->multirefs as $id => $hrefs){\r
5526                                                 $this->debug('resolving multirefs for id: '.$id);\r
5527                                                 $idVal = $this->buildVal($this->ids[$id]);\r
5528                                                 if (is_array($idVal) && isset($idVal['!id'])) {\r
5529                                                         unset($idVal['!id']);\r
5530                                                 }\r
5531                                                 foreach($hrefs as $refPos => $ref){\r
5532                                                         $this->debug('resolving href at pos '.$refPos);\r
5533                                                         $this->multirefs[$id][$refPos] = $idVal;\r
5534                                                 }\r
5535                                         }\r
5536                                 }\r
5537                         }\r
5538                         xml_parser_free($this->parser);\r
5539                 } else {\r
5540                         $this->debug('xml was empty, didn\'t parse!');\r
5541                         $this->setError('xml was empty, didn\'t parse!');\r
5542                 }\r
5543         }\r
5544 \r
5545         /**\r
5546         * start-element handler\r
5547         *\r
5548         * @param    resource $parser XML parser object\r
5549         * @param    string $name element name\r
5550         * @param    array $attrs associative array of attributes\r
5551         * @access   private\r
5552         */\r
5553         function start_element($parser, $name, $attrs) {\r
5554                 // position in a total number of elements, starting from 0\r
5555                 // update class level pos\r
5556                 $pos = $this->position++;\r
5557                 // and set mine\r
5558                 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');\r
5559                 // depth = how many levels removed from root?\r
5560                 // set mine as current global depth and increment global depth value\r
5561                 $this->message[$pos]['depth'] = $this->depth++;\r
5562 \r
5563                 // else add self as child to whoever the current parent is\r
5564                 if($pos != 0){\r
5565                         $this->message[$this->parent]['children'] .= '|'.$pos;\r
5566                 }\r
5567                 // set my parent\r
5568                 $this->message[$pos]['parent'] = $this->parent;\r
5569                 // set self as current parent\r
5570                 $this->parent = $pos;\r
5571                 // set self as current value for this depth\r
5572                 $this->depth_array[$this->depth] = $pos;\r
5573                 // get element prefix\r
5574                 if(strpos($name,':')){\r
5575                         // get ns prefix\r
5576                         $prefix = substr($name,0,strpos($name,':'));\r
5577                         // get unqualified name\r
5578                         $name = substr(strstr($name,':'),1);\r
5579                 }\r
5580                 // set status\r
5581                 if($name == 'Envelope'){\r
5582                         $this->status = 'envelope';\r
5583                 } elseif($name == 'Header' && $this->status = 'envelope'){\r
5584                         $this->root_header = $pos;\r
5585                         $this->status = 'header';\r
5586                 } elseif($name == 'Body' && $this->status = 'envelope'){\r
5587                         $this->status = 'body';\r
5588                         $this->body_position = $pos;\r
5589                 // set method\r
5590                 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){\r
5591                         $this->status = 'method';\r
5592                         $this->root_struct_name = $name;\r
5593                         $this->root_struct = $pos;\r
5594                         $this->message[$pos]['type'] = 'struct';\r
5595                         $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");\r
5596                 }\r
5597                 // set my status\r
5598                 $this->message[$pos]['status'] = $this->status;\r
5599                 // set name\r
5600                 $this->message[$pos]['name'] = htmlspecialchars($name);\r
5601                 // set attrs\r
5602                 $this->message[$pos]['attrs'] = $attrs;\r
5603 \r
5604                 // loop through atts, logging ns and type declarations\r
5605         $attstr = '';\r
5606                 foreach($attrs as $key => $value){\r
5607                 $key_prefix = $this->getPrefix($key);\r
5608                         $key_localpart = $this->getLocalPart($key);\r
5609                         // if ns declarations, add to class level array of valid namespaces\r
5610             if($key_prefix == 'xmlns'){\r
5611                                 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){\r
5612                                         $this->XMLSchemaVersion = $value;\r
5613                                         $this->namespaces['xsd'] = $this->XMLSchemaVersion;\r
5614                                         $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';\r
5615                                 }\r
5616                 $this->namespaces[$key_localpart] = $value;\r
5617                                 // set method namespace\r
5618                                 if($name == $this->root_struct_name){\r
5619                                         $this->methodNamespace = $value;\r
5620                                 }\r
5621                         // if it's a type declaration, set type\r
5622         } elseif($key_localpart == 'type'){\r
5623                         if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {\r
5624                                 // do nothing: already processed arrayType\r
5625                         } else {\r
5626                         $value_prefix = $this->getPrefix($value);\r
5627                         $value_localpart = $this->getLocalPart($value);\r
5628                                         $this->message[$pos]['type'] = $value_localpart;\r
5629                                         $this->message[$pos]['typePrefix'] = $value_prefix;\r
5630                         if(isset($this->namespaces[$value_prefix])){\r
5631                                 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];\r
5632                         } else if(isset($attrs['xmlns:'.$value_prefix])) {\r
5633                                                 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];\r
5634                         }\r
5635                                         // should do something here with the namespace of specified type?\r
5636                                 }\r
5637                         } elseif($key_localpart == 'arrayType'){\r
5638                                 $this->message[$pos]['type'] = 'array';\r
5639                                 /* do arrayType ereg here\r
5640                                 [1]    arrayTypeValue    ::=    atype asize\r
5641                                 [2]    atype    ::=    QName rank*\r
5642                                 [3]    rank    ::=    '[' (',')* ']'\r
5643                                 [4]    asize    ::=    '[' length~ ']'\r
5644                                 [5]    length    ::=    nextDimension* Digit+\r
5645                                 [6]    nextDimension    ::=    Digit+ ','\r
5646                                 */\r
5647                                 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';\r
5648                                 if(ereg($expr,$value,$regs)){\r
5649                                         $this->message[$pos]['typePrefix'] = $regs[1];\r
5650                                         $this->message[$pos]['arrayTypePrefix'] = $regs[1];\r
5651                         if (isset($this->namespaces[$regs[1]])) {\r
5652                                 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];\r
5653                         } else if (isset($attrs['xmlns:'.$regs[1]])) {\r
5654                                                 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];\r
5655                         }\r
5656                                         $this->message[$pos]['arrayType'] = $regs[2];\r
5657                                         $this->message[$pos]['arraySize'] = $regs[3];\r
5658                                         $this->message[$pos]['arrayCols'] = $regs[4];\r
5659                                 }\r
5660                         // specifies nil value (or not)\r
5661                         } elseif ($key_localpart == 'nil'){\r
5662                                 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');\r
5663                         // some other attribute\r
5664                         } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {\r
5665                                 $this->message[$pos]['xattrs']['!' . $key] = $value;\r
5666                         }\r
5667 \r
5668                         if ($key == 'xmlns') {\r
5669                                 $this->default_namespace = $value;\r
5670                         }\r
5671                         // log id\r
5672                         if($key == 'id'){\r
5673                                 $this->ids[$value] = $pos;\r
5674                         }\r
5675                         // root\r
5676                         if($key_localpart == 'root' && $value == 1){\r
5677                                 $this->status = 'method';\r
5678                                 $this->root_struct_name = $name;\r
5679                                 $this->root_struct = $pos;\r
5680                                 $this->debug("found root struct $this->root_struct_name, pos $pos");\r
5681                         }\r
5682             // for doclit\r
5683             $attstr .= " $key=\"$value\"";\r
5684                 }\r
5685         // get namespace - must be done after namespace atts are processed\r
5686                 if(isset($prefix)){\r
5687                         $this->message[$pos]['namespace'] = $this->namespaces[$prefix];\r
5688                         $this->default_namespace = $this->namespaces[$prefix];\r
5689                 } else {\r
5690                         $this->message[$pos]['namespace'] = $this->default_namespace;\r
5691                 }\r
5692         if($this->status == 'header'){\r
5693                 if ($this->root_header != $pos) {\r
5694                         $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";\r
5695                 }\r
5696         } elseif($this->root_struct_name != ''){\r
5697                 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";\r
5698         }\r
5699         }\r
5700 \r
5701         /**\r
5702         * end-element handler\r
5703         *\r
5704         * @param    resource $parser XML parser object\r
5705         * @param    string $name element name\r
5706         * @access   private\r
5707         */\r
5708         function end_element($parser, $name) {\r
5709                 // position of current element is equal to the last value left in depth_array for my depth\r
5710                 $pos = $this->depth_array[$this->depth--];\r
5711 \r
5712         // get element prefix\r
5713                 if(strpos($name,':')){\r
5714                         // get ns prefix\r
5715                         $prefix = substr($name,0,strpos($name,':'));\r
5716                         // get unqualified name\r
5717                         $name = substr(strstr($name,':'),1);\r
5718                 }\r
5719                 \r
5720                 // build to native type\r
5721                 if(isset($this->body_position) && $pos > $this->body_position){\r
5722                         // deal w/ multirefs\r
5723                         if(isset($this->message[$pos]['attrs']['href'])){\r
5724                                 // get id\r
5725                                 $id = substr($this->message[$pos]['attrs']['href'],1);\r
5726                                 // add placeholder to href array\r
5727                                 $this->multirefs[$id][$pos] = 'placeholder';\r
5728                                 // add set a reference to it as the result value\r
5729                                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];\r
5730             // build complexType values\r
5731                         } elseif($this->message[$pos]['children'] != ''){\r
5732                                 // if result has already been generated (struct/array)\r
5733                                 if(!isset($this->message[$pos]['result'])){\r
5734                                         $this->message[$pos]['result'] = $this->buildVal($pos);\r
5735                                 }\r
5736                         // build complexType values of attributes and possibly simpleContent\r
5737                         } elseif (isset($this->message[$pos]['xattrs'])) {\r
5738                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {\r
5739                                         $this->message[$pos]['xattrs']['!'] = null;\r
5740                                 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {\r
5741                         if (isset($this->message[$pos]['type'])) {\r
5742                                                 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');\r
5743                                         } else {\r
5744                                                 $parent = $this->message[$pos]['parent'];\r
5745                                                 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {\r
5746                                                         $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');\r
5747                                                 } else {\r
5748                                                         $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];\r
5749                                                 }\r
5750                                         }\r
5751                                 }\r
5752                                 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];\r
5753                         // set value of simpleType (or nil complexType)\r
5754                         } else {\r
5755                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);\r
5756                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {\r
5757                                         $this->message[$pos]['xattrs']['!'] = null;\r
5758                                 } elseif (isset($this->message[$pos]['type'])) {\r
5759                                         $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');\r
5760                                 } else {\r
5761                                         $parent = $this->message[$pos]['parent'];\r
5762                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {\r
5763                                                 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');\r
5764                                         } else {\r
5765                                                 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];\r
5766                                         }\r
5767                                 }\r
5768 \r
5769                                 /* add value to parent's result, if parent is struct/array\r
5770                                 $parent = $this->message[$pos]['parent'];\r
5771                                 if($this->message[$parent]['type'] != 'map'){\r
5772                                         if(strtolower($this->message[$parent]['type']) == 'array'){\r
5773                                                 $this->message[$parent]['result'][] = $this->message[$pos]['result'];\r
5774                                         } else {\r
5775                                                 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];\r
5776                                         }\r
5777                                 }\r
5778                                 */\r
5779                         }\r
5780                 }\r
5781                 \r
5782         // for doclit\r
5783         if($this->status == 'header'){\r
5784                 if ($this->root_header != $pos) {\r
5785                         $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";\r
5786                 }\r
5787         } elseif($pos >= $this->root_struct){\r
5788                 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";\r
5789         }\r
5790                 // switch status\r
5791                 if($pos == $this->root_struct){\r
5792                         $this->status = 'body';\r
5793                         $this->root_struct_namespace = $this->message[$pos]['namespace'];\r
5794                 } elseif($name == 'Body'){\r
5795                         $this->status = 'envelope';\r
5796                  } elseif($name == 'Header'){\r
5797                         $this->status = 'envelope';\r
5798                 } elseif($name == 'Envelope'){\r
5799                         //\r
5800                 }\r
5801                 // set parent back to my parent\r
5802                 $this->parent = $this->message[$pos]['parent'];\r
5803         }\r
5804 \r
5805         /**\r
5806         * element content handler\r
5807         *\r
5808         * @param    resource $parser XML parser object\r
5809         * @param    string $data element content\r
5810         * @access   private\r
5811         */\r
5812         function character_data($parser, $data){\r
5813                 $pos = $this->depth_array[$this->depth];\r
5814                 if ($this->xml_encoding=='UTF-8'){\r
5815                         // TODO: add an option to disable this for folks who want\r
5816                         // raw UTF-8 that, e.g., might not map to iso-8859-1\r
5817                         // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");\r
5818                         if($this->decode_utf8){\r
5819                                 $data = utf8_decode($data);\r
5820                         }\r
5821                 }\r
5822         $this->message[$pos]['cdata'] .= $data;\r
5823         // for doclit\r
5824         if($this->status == 'header'){\r
5825                 $this->responseHeaders .= $data;\r
5826         } else {\r
5827                 $this->document .= $data;\r
5828         }\r
5829         }\r
5830 \r
5831         /**\r
5832         * get the parsed message (SOAP Body)\r
5833         *\r
5834         * @return       mixed\r
5835         * @access   public\r
5836         * @deprecated   use get_soapbody instead\r
5837         */\r
5838         function get_response(){\r
5839                 return $this->soapresponse;\r
5840         }\r
5841 \r
5842         /**\r
5843         * get the parsed SOAP Body (NULL if there was none)\r
5844         *\r
5845         * @return       mixed\r
5846         * @access   public\r
5847         */\r
5848         function get_soapbody(){\r
5849                 return $this->soapresponse;\r
5850         }\r
5851 \r
5852         /**\r
5853         * get the parsed SOAP Header (NULL if there was none)\r
5854         *\r
5855         * @return       mixed\r
5856         * @access   public\r
5857         */\r
5858         function get_soapheader(){\r
5859                 return $this->soapheader;\r
5860         }\r
5861 \r
5862         /**\r
5863         * get the unparsed SOAP Header\r
5864         *\r
5865         * @return       string XML or empty if no Header\r
5866         * @access   public\r
5867         */\r
5868         function getHeaders(){\r
5869             return $this->responseHeaders;\r
5870         }\r
5871 \r
5872         /**\r
5873         * decodes simple types into PHP variables\r
5874         *\r
5875         * @param    string $value value to decode\r
5876         * @param    string $type XML type to decode\r
5877         * @param    string $typens XML type namespace to decode\r
5878         * @return       mixed PHP value\r
5879         * @access   private\r
5880         */\r
5881         function decodeSimple($value, $type, $typens) {\r
5882                 // TODO: use the namespace!\r
5883                 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {\r
5884                         return (string) $value;\r
5885                 }\r
5886                 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {\r
5887                         return (int) $value;\r
5888                 }\r
5889                 if ($type == 'float' || $type == 'double' || $type == 'decimal') {\r
5890                         return (double) $value;\r
5891                 }\r
5892                 if ($type == 'boolean') {\r
5893                         if (strtolower($value) == 'false' || strtolower($value) == 'f') {\r
5894                                 return false;\r
5895                         }\r
5896                         return (boolean) $value;\r
5897                 }\r
5898                 if ($type == 'base64' || $type == 'base64Binary') {\r
5899                         $this->debug('Decode base64 value');\r
5900                         return base64_decode($value);\r
5901                 }\r
5902                 // obscure numeric types\r
5903                 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'\r
5904                         || $type == 'nonNegativeInteger' || $type == 'positiveInteger'\r
5905                         || $type == 'unsignedInt'\r
5906                         || $type == 'unsignedShort' || $type == 'unsignedByte') {\r
5907                         return (int) $value;\r
5908                 }\r
5909                 // bogus: parser treats array with no elements as a simple type\r
5910                 if ($type == 'array') {\r
5911                         return array();\r
5912                 }\r
5913                 // everything else\r
5914                 return (string) $value;\r
5915         }\r
5916 \r
5917         /**\r
5918         * builds response structures for compound values (arrays/structs)\r
5919         * and scalars\r
5920         *\r
5921         * @param    integer $pos position in node tree\r
5922         * @return       mixed   PHP value\r
5923         * @access   private\r
5924         */\r
5925         function buildVal($pos){\r
5926                 if(!isset($this->message[$pos]['type'])){\r
5927                         $this->message[$pos]['type'] = '';\r
5928                 }\r
5929                 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);\r
5930                 // if there are children...\r
5931                 if($this->message[$pos]['children'] != ''){\r
5932                         $this->debug('in buildVal, there are children');\r
5933                         $children = explode('|',$this->message[$pos]['children']);\r
5934                         array_shift($children); // knock off empty\r
5935                         // md array\r
5936                         if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){\r
5937                 $r=0; // rowcount\r
5938                 $c=0; // colcount\r
5939                 foreach($children as $child_pos){\r
5940                                         $this->debug("in buildVal, got an MD array element: $r, $c");\r
5941                                         $params[$r][] = $this->message[$child_pos]['result'];\r
5942                                     $c++;\r
5943                                     if($c == $this->message[$pos]['arrayCols']){\r
5944                                         $c = 0;\r
5945                                                 $r++;\r
5946                                     }\r
5947                 }\r
5948             // array\r
5949                         } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){\r
5950                 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);\r
5951                 foreach($children as $child_pos){\r
5952                         $params[] = &$this->message[$child_pos]['result'];\r
5953                 }\r
5954             // apache Map type: java hashtable\r
5955             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){\r
5956                 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);\r
5957                 foreach($children as $child_pos){\r
5958                         $kv = explode("|",$this->message[$child_pos]['children']);\r
5959                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];\r
5960                 }\r
5961             // generic compound type\r
5962             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {\r
5963                     } else {\r
5964                         // Apache Vector type: treat as an array\r
5965                 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);\r
5966                                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {\r
5967                                         $notstruct = 1;\r
5968                                 } else {\r
5969                                         $notstruct = 0;\r
5970                     }\r
5971                 //\r
5972                 foreach($children as $child_pos){\r
5973                         if($notstruct){\r
5974                                 $params[] = &$this->message[$child_pos]['result'];\r
5975                         } else {\r
5976                                 if (isset($params[$this->message[$child_pos]['name']])) {\r
5977                                         // de-serialize repeated element name into an array\r
5978                                         if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {\r
5979                                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);\r
5980                                         }\r
5981                                         $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];\r
5982                                 } else {\r
5983                                                 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];\r
5984                                             }\r
5985                         }\r
5986                 }\r
5987                         }\r
5988                         if (isset($this->message[$pos]['xattrs'])) {\r
5989                 $this->debug('in buildVal, handling attributes');\r
5990                                 foreach ($this->message[$pos]['xattrs'] as $n => $v) {\r
5991                                         $params[$n] = $v;\r
5992                                 }\r
5993                         }\r
5994                         // handle simpleContent\r
5995                         if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {\r
5996                 $this->debug('in buildVal, handling simpleContent');\r
5997                 if (isset($this->message[$pos]['type'])) {\r
5998                                         $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');\r
5999                                 } else {\r
6000                                         $parent = $this->message[$pos]['parent'];\r
6001                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {\r
6002                                                 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');\r
6003                                         } else {\r
6004                                                 $params['!'] = $this->message[$pos]['cdata'];\r
6005                                         }\r
6006                                 }\r
6007                         }\r
6008                         $ret = is_array($params) ? $params : array();\r
6009                         $this->debug('in buildVal, return:');\r
6010                         $this->appendDebug($this->varDump($ret));\r
6011                         return $ret;\r
6012                 } else {\r
6013                 $this->debug('in buildVal, no children, building scalar');\r
6014                         $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';\r
6015                 if (isset($this->message[$pos]['type'])) {\r
6016                                 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');\r
6017                                 $this->debug("in buildVal, return: $ret");\r
6018                                 return $ret;\r
6019                         }\r
6020                         $parent = $this->message[$pos]['parent'];\r
6021                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {\r
6022                                 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');\r
6023                                 $this->debug("in buildVal, return: $ret");\r
6024                                 return $ret;\r
6025                         }\r
6026                 $ret = $this->message[$pos]['cdata'];\r
6027                         $this->debug("in buildVal, return: $ret");\r
6028                 return $ret;\r
6029                 }\r
6030         }\r
6031 }\r
6032 \r
6033 /**\r
6034  * Backward compatibility\r
6035  */\r
6036 class soap_parser extends nusoap_parser {\r
6037 }\r
6038 \r
6039 ?><?php\r
6040 \r
6041 \r
6042 \r
6043 /**\r
6044 *\r
6045 * [nu]soapclient higher level class for easy usage.\r
6046 *\r
6047 * usage:\r
6048 *\r
6049 * // instantiate client with server info\r
6050 * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );\r
6051 *\r
6052 * // call method, get results\r
6053 * //echo $soapclient->call( string methodname [ ,array parameters] );\r
6054 *\r
6055 * // bye bye client\r
6056 * unset($soapclient);\r
6057 *\r
6058 * @author   Dietrich Ayala <dietrich@ganx4.com>\r
6059 * @author   Scott Nichol <snichol@users.sourceforge.net>\r
6060 * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $\r
6061 * @access   public\r
6062 */\r
6063 class nusoap_client extends nusoap_base  {\r
6064 \r
6065         var $username = '';                             // Username for HTTP authentication\r
6066         var $password = '';                             // Password for HTTP authentication\r
6067         var $authtype = '';                             // Type of HTTP authentication\r
6068         var $certRequest = array();             // Certificate for HTTP SSL authentication\r
6069         var $requestHeaders = false;    // SOAP headers in request (text)\r
6070         var $responseHeaders = '';              // SOAP headers from response (incomplete namespace resolution) (text)\r
6071         var $responseHeader = NULL;             // SOAP Header from response (parsed)\r
6072         var $document = '';                             // SOAP body response portion (incomplete namespace resolution) (text)\r
6073         var $endpoint;\r
6074         var $forceEndpoint = '';                // overrides WSDL endpoint\r
6075     var $proxyhost = '';\r
6076     var $proxyport = '';\r
6077         var $proxyusername = '';\r
6078         var $proxypassword = '';\r
6079     var $xml_encoding = '';                     // character set encoding of incoming (response) messages\r
6080         var $http_encoding = false;\r
6081         var $timeout = 0;                               // HTTP connection timeout\r
6082         var $response_timeout = 30;             // HTTP response timeout\r
6083         var $endpointType = '';                 // soap|wsdl, empty for WSDL initialization error\r
6084         var $persistentConnection = false;\r
6085         var $defaultRpcParams = false;  // This is no longer used\r
6086         var $request = '';                              // HTTP request\r
6087         var $response = '';                             // HTTP response\r
6088         var $responseData = '';                 // SOAP payload of response\r
6089         var $cookies = array();                 // Cookies from response or for request\r
6090     var $decode_utf8 = true;            // toggles whether the parser decodes element content w/ utf8_decode()\r
6091         var $operations = array();              // WSDL operations, empty for WSDL initialization error\r
6092         var $curl_options = array();    // User-specified cURL options\r
6093         var $bindingType = '';                  // WSDL operation binding type\r
6094         var $use_curl = false;                  // whether to always try to use cURL\r
6095 \r
6096         /*\r
6097          * fault related variables\r
6098          */\r
6099         /**\r
6100          * @var      fault\r
6101          * @access   public\r
6102          */\r
6103         var $fault;\r
6104         /**\r
6105          * @var      faultcode\r
6106          * @access   public\r
6107          */\r
6108         var $faultcode;\r
6109         /**\r
6110          * @var      faultstring\r
6111          * @access   public\r
6112          */\r
6113         var $faultstring;\r
6114         /**\r
6115          * @var      faultdetail\r
6116          * @access   public\r
6117          */\r
6118         var $faultdetail;\r
6119 \r
6120         /**\r
6121         * constructor\r
6122         *\r
6123         * @param    mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)\r
6124         * @param    bool $wsdl optional, set to true if using WSDL\r
6125         * @param        int $portName optional portName in WSDL document\r
6126         * @param    string $proxyhost\r
6127         * @param    string $proxyport\r
6128         * @param        string $proxyusername\r
6129         * @param        string $proxypassword\r
6130         * @param        integer $timeout set the connection timeout\r
6131         * @param        integer $response_timeout set the response timeout\r
6132         * @access   public\r
6133         */\r
6134         function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){\r
6135                 parent::nusoap_base();\r
6136                 $this->endpoint = $endpoint;\r
6137                 $this->proxyhost = $proxyhost;\r
6138                 $this->proxyport = $proxyport;\r
6139                 $this->proxyusername = $proxyusername;\r
6140                 $this->proxypassword = $proxypassword;\r
6141                 $this->timeout = $timeout;\r
6142                 $this->response_timeout = $response_timeout;\r
6143 \r
6144                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");\r
6145                 $this->appendDebug('endpoint=' . $this->varDump($endpoint));\r
6146 \r
6147                 // make values\r
6148                 if($wsdl){\r
6149                         if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {\r
6150                                 $this->wsdl = $endpoint;\r
6151                                 $this->endpoint = $this->wsdl->wsdl;\r
6152                                 $this->wsdlFile = $this->endpoint;\r
6153                                 $this->debug('existing wsdl instance created from ' . $this->endpoint);\r
6154                                 $this->checkWSDL();\r
6155                         } else {\r
6156                                 $this->wsdlFile = $this->endpoint;\r
6157                                 $this->wsdl = null;\r
6158                                 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);\r
6159                         }\r
6160                         $this->endpointType = 'wsdl';\r
6161                 } else {\r
6162                         $this->debug("instantiate SOAP with endpoint at $endpoint");\r
6163                         $this->endpointType = 'soap';\r
6164                 }\r
6165         }\r
6166 \r
6167         /**\r
6168         * calls method, returns PHP native type\r
6169         *\r
6170         * @param    string $operation SOAP server URL or path\r
6171         * @param    mixed $params An array, associative or simple, of the parameters\r
6172         *                                     for the method call, or a string that is the XML\r
6173         *                                     for the call.  For rpc style, this call will\r
6174         *                                     wrap the XML in a tag named after the method, as\r
6175         *                                     well as the SOAP Envelope and Body.  For document\r
6176         *                                     style, this will only wrap with the Envelope and Body.\r
6177         *                                     IMPORTANT: when using an array with document style,\r
6178         *                                     in which case there\r
6179         *                         is really one parameter, the root of the fragment\r
6180         *                         used in the call, which encloses what programmers\r
6181         *                         normally think of parameters.  A parameter array\r
6182         *                         *must* include the wrapper.\r
6183         * @param        string $namespace optional method namespace (WSDL can override)\r
6184         * @param        string $soapAction optional SOAPAction value (WSDL can override)\r
6185         * @param        mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array\r
6186         * @param        boolean $rpcParams optional (no longer used)\r
6187         * @param        string  $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)\r
6188         * @param        string  $use optional (encoded|literal) the use when serializing parameters (WSDL can override)\r
6189         * @return       mixed   response from SOAP call\r
6190         * @access   public\r
6191         */\r
6192         function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){\r
6193                 $this->operation = $operation;\r
6194                 $this->fault = false;\r
6195                 $this->setError('');\r
6196                 $this->request = '';\r
6197                 $this->response = '';\r
6198                 $this->responseData = '';\r
6199                 $this->faultstring = '';\r
6200                 $this->faultcode = '';\r
6201                 $this->opData = array();\r
6202                 \r
6203                 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");\r
6204                 $this->appendDebug('params=' . $this->varDump($params));\r
6205                 $this->appendDebug('headers=' . $this->varDump($headers));\r
6206                 if ($headers) {\r
6207                         $this->requestHeaders = $headers;\r
6208                 }\r
6209                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {\r
6210                         $this->loadWSDL();\r
6211                         if ($this->getError())\r
6212                                 return false;\r
6213                 }\r
6214                 // serialize parameters\r
6215                 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){\r
6216                         // use WSDL for operation\r
6217                         //echo "use WSDL for operation<br/>";\r
6218                         $this->opData = $opData;\r
6219                         $this->debug("found operation");\r
6220                         $this->appendDebug('opData=' . $this->varDump($opData));\r
6221                         if (isset($opData['soapAction'])) {\r
6222                                 $soapAction = $opData['soapAction'];\r
6223                         }\r
6224                         if (! $this->forceEndpoint) {\r
6225                                 $this->endpoint = $opData['endpoint'];\r
6226                         } else {\r
6227                                 $this->endpoint = $this->forceEndpoint;\r
6228                         }\r
6229                         $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     $namespace;\r
6230                         $style = $opData['style'];\r
6231                         $use = $opData['input']['use'];\r
6232                         // add ns to ns array\r
6233                         if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){\r
6234                                 $nsPrefix = 'ns' . rand(1000, 9999);\r
6235                                 $this->wsdl->namespaces[$nsPrefix] = $namespace;\r
6236                         }\r
6237             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);\r
6238                         // serialize payload\r
6239                         if (is_string($params)) {\r
6240                                 $this->debug("serializing param string for WSDL operation $operation");\r
6241                                 $payload = $params;\r
6242                         } elseif (is_array($params)) {\r
6243                                 $this->debug("serializing param array for WSDL operation $operation");\r
6244                                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);\r
6245                                 //echo "#####PAYLOAD 2 ####<br/>";\r
6246                                 //echo htmlentities($payload)."<br/>";\r
6247                                 //echo "#####PAYLOAD 2 ####<br/>";\r
6248                         } else {\r
6249                                 $this->debug('params must be array or string');\r
6250                                 $this->setError('params must be array or string');\r
6251                                 return false;\r
6252                         }\r
6253             $usedNamespaces = $this->wsdl->usedNamespaces;\r
6254                         if (isset($opData['input']['encodingStyle'])) {\r
6255                                 $encodingStyle = $opData['input']['encodingStyle'];\r
6256                         } else {\r
6257                                 $encodingStyle = '';\r
6258                         }\r
6259                         $this->appendDebug($this->wsdl->getDebug());\r
6260                         $this->wsdl->clearDebug();\r
6261                         if ($errstr = $this->wsdl->getError()) {\r
6262                                 $this->debug('got wsdl error: '.$errstr);\r
6263                                 $this->setError('wsdl error: '.$errstr);\r
6264                                 return false;\r
6265                         }\r
6266                 } elseif($this->endpointType == 'wsdl') {\r
6267                         // operation not in WSDL\r
6268                         $this->appendDebug($this->wsdl->getDebug());\r
6269                         $this->wsdl->clearDebug();\r
6270                         $this->setError( 'operation '.$operation.' not present.');\r
6271                         $this->debug("operation '$operation' not present.");\r
6272                         return false;\r
6273                 } else {\r
6274                         // no WSDL\r
6275                         //$this->namespaces['ns1'] = $namespace;\r
6276                         $nsPrefix = 'ns' . rand(1000, 9999);\r
6277                         // serialize \r
6278                         $payload = '';\r
6279                         if (is_string($params)) {\r
6280                                 $this->debug("serializing param string for operation $operation");\r
6281                                 $payload = $params;\r
6282                         } elseif (is_array($params)) {\r
6283                                 $this->debug("serializing param array for operation $operation");\r
6284                                 foreach($params as $k => $v){\r
6285                                         $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);\r
6286                                 }\r
6287                         } else {\r
6288                                 $this->debug('params must be array or string');\r
6289                                 $this->setError('params must be array or string');\r
6290                                 return false;\r
6291                         }\r
6292                         $usedNamespaces = array();\r
6293                         if ($use == 'encoded') {\r
6294                                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';\r
6295                         } else {\r
6296                                 $encodingStyle = '';\r
6297                         }\r
6298                 }\r
6299                 //echo "#####PAYLOAD 1 ####<br/>";\r
6300                 //echo htmlentities($payload)."<br/>";\r
6301                 //echo "#####PAYLOAD 1 ####<br/>";\r
6302                 // wrap RPC calls with method element\r
6303                 if ($style == 'rpc') {\r
6304                         if ($use == 'literal') {\r
6305                                 $this->debug("wrapping RPC request with literal method element");\r
6306                                 if ($namespace) {\r
6307                                         // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace\r
6308                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .\r
6309                                                                 $payload .\r
6310                                                                 "</$nsPrefix:$operation>";\r
6311                                 } else {\r
6312                                         $payload = "<$operation>" . $payload . "</$operation>";\r
6313                                 }\r
6314                         } else {\r
6315                                 $this->debug("wrapping RPC request with encoded method element");\r
6316                                 if ($namespace) {\r
6317                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .\r
6318                                                                 $payload .\r
6319                                                                 "</$nsPrefix:$operation>";\r
6320                                 } else {\r
6321                                         $payload = "<$operation>" .\r
6322                                                                 $payload .\r
6323                                                                 "</$operation>";\r
6324                                 }\r
6325                         }\r
6326                 }\r
6327                 //echo "#####PAYLOAD####<br/>";\r
6328                 //echo htmlentities($payload)."<br/>";\r
6329                 //echo "#####PAYLOAD####<br/>";\r
6330                 // serialize envelope\r
6331                 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);\r
6332                 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");\r
6333                 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));\r
6334                 // send\r
6335                 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);\r
6336                 if($errstr = $this->getError()){\r
6337                         $this->debug('Error: '.$errstr);\r
6338                         return false;\r
6339                 } else {\r
6340                         $this->return = $return;\r
6341                         $this->debug('sent message successfully and got a(n) '.gettype($return));\r
6342                 $this->appendDebug('return=' . $this->varDump($return));\r
6343                         \r
6344                         // fault?\r
6345                         if(is_array($return) && isset($return['faultcode'])){\r
6346                                 $this->debug('got fault');\r
6347                                 $this->setError($return['faultcode'].': '.$return['faultstring']);\r
6348                                 $this->fault = true;\r
6349                                 foreach($return as $k => $v){\r
6350                                         $this->$k = $v;\r
6351                                         $this->debug("$k = $v<br>");\r
6352                                 }\r
6353                                 return $return;\r
6354                         } elseif ($style == 'document') {\r
6355                                 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),\r
6356                                 // we are only going to return the first part here...sorry about that\r
6357                                 return $return;\r
6358                         } else {\r
6359                                 // array of return values\r
6360                                 if(is_array($return)){\r
6361                                         // multiple 'out' parameters, which we return wrapped up\r
6362                                         // in the array\r
6363                                         if(sizeof($return) > 1){\r
6364                                                 return $return;\r
6365                                         }\r
6366                                         // single 'out' parameter (normally the return value)\r
6367                                         $return = array_shift($return);\r
6368                                         $this->debug('return shifted value: ');\r
6369                                         $this->appendDebug($this->varDump($return));\r
6370                                 return $return;\r
6371                                 // nothing returned (ie, echoVoid)\r
6372                                 } else {\r
6373                                         return "";\r
6374                                 }\r
6375                         }\r
6376                 }\r
6377         }\r
6378 \r
6379         /**\r
6380         * check WSDL passed as an instance or pulled from an endpoint\r
6381         *\r
6382         * @access   private\r
6383         */\r
6384         function checkWSDL() {\r
6385                 $this->appendDebug($this->wsdl->getDebug());\r
6386                 $this->wsdl->clearDebug();\r
6387                 $this->debug('checkWSDL');\r
6388                 // catch errors\r
6389                 if ($errstr = $this->wsdl->getError()) {\r
6390                         $this->debug('got wsdl error: '.$errstr);\r
6391                         $this->setError('wsdl error: '.$errstr);\r
6392                 } elseif ($this->operations = $this->wsdl->getOperations('soap')) {\r
6393                         $this->bindingType = 'soap';\r
6394                         $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);\r
6395                 } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {\r
6396                         $this->bindingType = 'soap12';\r
6397                         $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);\r
6398                         $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');\r
6399                 } else {\r
6400                         $this->debug('getOperations returned false');\r
6401                         $this->setError('no operations defined in the WSDL document!');\r
6402                 }\r
6403         }\r
6404 \r
6405         /**\r
6406          * instantiate wsdl object and parse wsdl file\r
6407          *\r
6408          * @access      public\r
6409          */\r
6410         function loadWSDL() {\r
6411                 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);\r
6412                 $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);\r
6413                 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);\r
6414                 $this->wsdl->fetchWSDL($this->wsdlFile);\r
6415                 $this->checkWSDL();\r
6416         }\r
6417 \r
6418         /**\r
6419         * get available data pertaining to an operation\r
6420         *\r
6421         * @param    string $operation operation name\r
6422         * @return       array array of data pertaining to the operation\r
6423         * @access   public\r
6424         */\r
6425         function getOperationData($operation){\r
6426                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {\r
6427                         $this->loadWSDL();\r
6428                         if ($this->getError())\r
6429                                 return false;\r
6430                 }\r
6431                 if(isset($this->operations[$operation])){\r
6432                         return $this->operations[$operation];\r
6433                 }\r
6434                 $this->debug("No data for operation: $operation");\r
6435         }\r
6436 \r
6437     /**\r
6438     * send the SOAP message\r
6439     *\r
6440     * Note: if the operation has multiple return values\r
6441     * the return value of this method will be an array\r
6442     * of those values.\r
6443     *\r
6444         * @param    string $msg a SOAPx4 soapmsg object\r
6445         * @param    string $soapaction SOAPAction value\r
6446         * @param    integer $timeout set connection timeout in seconds\r
6447         * @param        integer $response_timeout set response timeout in seconds\r
6448         * @return       mixed native PHP types.\r
6449         * @access   private\r
6450         */\r
6451         function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {\r
6452                 $this->checkCookies();\r
6453                 // detect transport\r
6454                 switch(true){\r
6455                         // http(s)\r
6456                         case ereg('^http',$this->endpoint):\r
6457                                 $this->debug('transporting via HTTP');\r
6458                                 if($this->persistentConnection == true && is_object($this->persistentConnection)){\r
6459                                         $http =& $this->persistentConnection;\r
6460                                 } else {\r
6461                                         $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);\r
6462                                         if ($this->persistentConnection) {\r
6463                                                 $http->usePersistentConnection();\r
6464                                         }\r
6465                                 }\r
6466                                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());\r
6467                                 $http->setSOAPAction($soapaction);\r
6468                                 if($this->proxyhost && $this->proxyport){\r
6469                                         $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);\r
6470                                 }\r
6471                 if($this->authtype != '') {\r
6472                                         $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);\r
6473                                 }\r
6474                                 if($this->http_encoding != ''){\r
6475                                         $http->setEncoding($this->http_encoding);\r
6476                                 }\r
6477                                 $this->debug('sending message, length='.strlen($msg));\r
6478                                 if(ereg('^http:',$this->endpoint)){\r
6479                                 //if(strpos($this->endpoint,'http:')){\r
6480                                         $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);\r
6481                                 } elseif(ereg('^https',$this->endpoint)){\r
6482                                 //} elseif(strpos($this->endpoint,'https:')){\r
6483                                         //if(phpversion() == '4.3.0-dev'){\r
6484                                                 //$response = $http->send($msg,$timeout,$response_timeout);\r
6485                                 //$this->request = $http->outgoing_payload;\r
6486                                                 //$this->response = $http->incoming_payload;\r
6487                                         //} else\r
6488                                         $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);\r
6489                                 } else {\r
6490                                         $this->setError('no http/s in endpoint url');\r
6491                                 }\r
6492                                 $this->request = $http->outgoing_payload;\r
6493                                 $this->response = $http->incoming_payload;\r
6494                                 $this->appendDebug($http->getDebug());\r
6495                                 $this->UpdateCookies($http->incoming_cookies);\r
6496 \r
6497                                 // save transport object if using persistent connections\r
6498                                 if ($this->persistentConnection) {\r
6499                                         $http->clearDebug();\r
6500                                         if (!is_object($this->persistentConnection)) {\r
6501                                                 $this->persistentConnection = $http;\r
6502                                         }\r
6503                                 }\r
6504                                 \r
6505                                 if($err = $http->getError()){\r
6506                                         $this->setError('HTTP Error: '.$err);\r
6507                                         return false;\r
6508                                 } elseif($this->getError()){\r
6509                                         return false;\r
6510                                 } else {\r
6511                                         $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);\r
6512                                         return $this->parseResponse($http->incoming_headers, $this->responseData);\r
6513                                 }\r
6514                         break;\r
6515                         default:\r
6516                                 $this->setError('no transport found, or selected transport is not yet supported!');\r
6517                         return false;\r
6518                         break;\r
6519                 }\r
6520         }\r
6521 \r
6522         /**\r
6523         * processes SOAP message returned from server\r
6524         *\r
6525         * @param        array   $headers        The HTTP headers\r
6526         * @param        string  $data           unprocessed response data from server\r
6527         * @return       mixed   value of the message, decoded into a PHP type\r
6528         * @access   private\r
6529         */\r
6530     function parseResponse($headers, $data) {\r
6531                 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');\r
6532                 $this->appendDebug($this->varDump($headers));\r
6533                 if (!strstr($headers['content-type'], 'text/xml')) {\r
6534                         $this->setError('Response not of type text/xml: ' . $headers['content-type']);\r
6535                         return false;\r
6536                 }\r
6537                 if (strpos($headers['content-type'], '=')) {\r
6538                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));\r
6539                         $this->debug('Got response encoding: ' . $enc);\r
6540                         if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){\r
6541                                 $this->xml_encoding = strtoupper($enc);\r
6542                         } else {\r
6543                                 $this->xml_encoding = 'US-ASCII';\r
6544                         }\r
6545                 } else {\r
6546                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1\r
6547                         $this->xml_encoding = 'ISO-8859-1';\r
6548                 }\r
6549                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');\r
6550                 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);\r
6551                 // add parser debug data to our debug\r
6552                 $this->appendDebug($parser->getDebug());\r
6553                 // if parse errors\r
6554                 if($errstr = $parser->getError()){\r
6555                         $this->setError( $errstr);\r
6556                         // destroy the parser object\r
6557                         unset($parser);\r
6558                         return false;\r
6559                 } else {\r
6560                         // get SOAP headers\r
6561                         $this->responseHeaders = $parser->getHeaders();\r
6562                         // get SOAP headers\r
6563                         $this->responseHeader = $parser->get_soapheader();\r
6564                         // get decoded message\r
6565                         $return = $parser->get_soapbody();\r
6566             // add document for doclit support\r
6567             $this->document = $parser->document;\r
6568                         // destroy the parser object\r
6569                         unset($parser);\r
6570                         // return decode message\r
6571                         return $return;\r
6572                 }\r
6573          }\r
6574 \r
6575         /**\r
6576         * sets user-specified cURL options\r
6577         *\r
6578         * @param        mixed $option The cURL option (always integer?)\r
6579         * @param        mixed $value The cURL option value\r
6580         * @access   public\r
6581         */\r
6582         function setCurlOption($option, $value) {\r
6583                 $this->debug("setCurlOption option=$option, value=");\r
6584                 $this->appendDebug($this->varDump($value));\r
6585                 $this->curl_options[$option] = $value;\r
6586         }\r
6587 \r
6588         /**\r
6589         * sets the SOAP endpoint, which can override WSDL\r
6590         *\r
6591         * @param        string $endpoint The endpoint URL to use, or empty string or false to prevent override\r
6592         * @access   public\r
6593         */\r
6594         function setEndpoint($endpoint) {\r
6595                 $this->debug("setEndpoint(\"$endpoint\")");\r
6596                 $this->forceEndpoint = $endpoint;\r
6597         }\r
6598 \r
6599         /**\r
6600         * set the SOAP headers\r
6601         *\r
6602         * @param        mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers\r
6603         * @access   public\r
6604         */\r
6605         function setHeaders($headers){\r
6606                 $this->debug("setHeaders headers=");\r
6607                 $this->appendDebug($this->varDump($headers));\r
6608                 $this->requestHeaders = $headers;\r
6609         }\r
6610 \r
6611         /**\r
6612         * get the SOAP response headers (namespace resolution incomplete)\r
6613         *\r
6614         * @return       string\r
6615         * @access   public\r
6616         */\r
6617         function getHeaders(){\r
6618                 return $this->responseHeaders;\r
6619         }\r
6620 \r
6621         /**\r
6622         * get the SOAP response Header (parsed)\r
6623         *\r
6624         * @return       mixed\r
6625         * @access   public\r
6626         */\r
6627         function getHeader(){\r
6628                 return $this->responseHeader;\r
6629         }\r
6630 \r
6631         /**\r
6632         * set proxy info here\r
6633         *\r
6634         * @param    string $proxyhost\r
6635         * @param    string $proxyport\r
6636         * @param        string $proxyusername\r
6637         * @param        string $proxypassword\r
6638         * @access   public\r
6639         */\r
6640         function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {\r
6641                 $this->proxyhost = $proxyhost;\r
6642                 $this->proxyport = $proxyport;\r
6643                 $this->proxyusername = $proxyusername;\r
6644                 $this->proxypassword = $proxypassword;\r
6645         }\r
6646 \r
6647         /**\r
6648         * if authenticating, set user credentials here\r
6649         *\r
6650         * @param    string $username\r
6651         * @param    string $password\r
6652         * @param        string $authtype (basic|digest|certificate|ntlm)\r
6653         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)\r
6654         * @access   public\r
6655         */\r
6656         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {\r
6657                 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");\r
6658                 $this->appendDebug($this->varDump($certRequest));\r
6659                 $this->username = $username;\r
6660                 $this->password = $password;\r
6661                 $this->authtype = $authtype;\r
6662                 $this->certRequest = $certRequest;\r
6663         }\r
6664         \r
6665         /**\r
6666         * use HTTP encoding\r
6667         *\r
6668         * @param    string $enc HTTP encoding\r
6669         * @access   public\r
6670         */\r
6671         function setHTTPEncoding($enc='gzip, deflate'){\r
6672                 $this->debug("setHTTPEncoding(\"$enc\")");\r
6673                 $this->http_encoding = $enc;\r
6674         }\r
6675         \r
6676         /**\r
6677         * Set whether to try to use cURL connections if possible\r
6678         *\r
6679         * @param        boolean $use Whether to try to use cURL\r
6680         * @access   public\r
6681         */\r
6682         function setUseCURL($use) {\r
6683                 $this->debug("setUseCURL($use)");\r
6684                 $this->use_curl = $use;\r
6685         }\r
6686 \r
6687         /**\r
6688         * use HTTP persistent connections if possible\r
6689         *\r
6690         * @access   public\r
6691         */\r
6692         function useHTTPPersistentConnection(){\r
6693                 $this->debug("useHTTPPersistentConnection");\r
6694                 $this->persistentConnection = true;\r
6695         }\r
6696         \r
6697         /**\r
6698         * gets the default RPC parameter setting.\r
6699         * If true, default is that call params are like RPC even for document style.\r
6700         * Each call() can override this value.\r
6701         *\r
6702         * This is no longer used.\r
6703         *\r
6704         * @return boolean\r
6705         * @access public\r
6706         * @deprecated\r
6707         */\r
6708         function getDefaultRpcParams() {\r
6709                 return $this->defaultRpcParams;\r
6710         }\r
6711 \r
6712         /**\r
6713         * sets the default RPC parameter setting.\r
6714         * If true, default is that call params are like RPC even for document style\r
6715         * Each call() can override this value.\r
6716         *\r
6717         * This is no longer used.\r
6718         *\r
6719         * @param    boolean $rpcParams\r
6720         * @access public\r
6721         * @deprecated\r
6722         */\r
6723         function setDefaultRpcParams($rpcParams) {\r
6724                 $this->defaultRpcParams = $rpcParams;\r
6725         }\r
6726         \r
6727         /**\r
6728         * dynamically creates an instance of a proxy class,\r
6729         * allowing user to directly call methods from wsdl\r
6730         *\r
6731         * @return   object soap_proxy object\r
6732         * @access   public\r
6733         */\r
6734         function getProxy() {\r
6735                 $r = rand();\r
6736                 $evalStr = $this->_getProxyClassCode($r);\r
6737                 //$this->debug("proxy class: $evalStr");\r
6738                 if ($this->getError()) {\r
6739                         $this->debug("Error from _getProxyClassCode, so return NULL");\r
6740                         return null;\r
6741                 }\r
6742                 // eval the class\r
6743                 eval($evalStr);\r
6744                 // instantiate proxy object\r
6745                 eval("\$proxy = new nusoap_proxy_$r('');");\r
6746                 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice\r
6747                 $proxy->endpointType = 'wsdl';\r
6748                 $proxy->wsdlFile = $this->wsdlFile;\r
6749                 $proxy->wsdl = $this->wsdl;\r
6750                 $proxy->operations = $this->operations;\r
6751                 $proxy->defaultRpcParams = $this->defaultRpcParams;\r
6752                 // transfer other state\r
6753                 $proxy->soap_defencoding = $this->soap_defencoding;\r
6754                 $proxy->username = $this->username;\r
6755                 $proxy->password = $this->password;\r
6756                 $proxy->authtype = $this->authtype;\r
6757                 $proxy->certRequest = $this->certRequest;\r
6758                 $proxy->requestHeaders = $this->requestHeaders;\r
6759                 $proxy->endpoint = $this->endpoint;\r
6760                 $proxy->forceEndpoint = $this->forceEndpoint;\r
6761                 $proxy->proxyhost = $this->proxyhost;\r
6762                 $proxy->proxyport = $this->proxyport;\r
6763                 $proxy->proxyusername = $this->proxyusername;\r
6764                 $proxy->proxypassword = $this->proxypassword;\r
6765                 $proxy->http_encoding = $this->http_encoding;\r
6766                 $proxy->timeout = $this->timeout;\r
6767                 $proxy->response_timeout = $this->response_timeout;\r
6768                 $proxy->persistentConnection = &$this->persistentConnection;\r
6769                 $proxy->decode_utf8 = $this->decode_utf8;\r
6770                 $proxy->curl_options = $this->curl_options;\r
6771                 $proxy->bindingType = $this->bindingType;\r
6772                 $proxy->use_curl = $this->use_curl;\r
6773                 return $proxy;\r
6774         }\r
6775 \r
6776         /**\r
6777         * dynamically creates proxy class code\r
6778         *\r
6779         * @return   string PHP/NuSOAP code for the proxy class\r
6780         * @access   private\r
6781         */\r
6782         function _getProxyClassCode($r) {\r
6783                 $this->debug("in getProxy endpointType=$this->endpointType");\r
6784                 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));\r
6785                 if ($this->endpointType != 'wsdl') {\r
6786                         $evalStr = 'A proxy can only be created for a WSDL client';\r
6787                         $this->setError($evalStr);\r
6788                         $evalStr = "echo \"$evalStr\";";\r
6789                         return $evalStr;\r
6790                 }\r
6791                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {\r
6792                         $this->loadWSDL();\r
6793                         if ($this->getError()) {\r
6794                                 return "echo \"" . $this->getError() . "\";";\r
6795                         }\r
6796                 }\r
6797                 $evalStr = '';\r
6798                 foreach ($this->operations as $operation => $opData) {\r
6799                         if ($operation != '') {\r
6800                                 // create param string and param comment string\r
6801                                 if (sizeof($opData['input']['parts']) > 0) {\r
6802                                         $paramStr = '';\r
6803                                         $paramArrayStr = '';\r
6804                                         $paramCommentStr = '';\r
6805                                         foreach ($opData['input']['parts'] as $name => $type) {\r
6806                                                 $paramStr .= "\$$name, ";\r
6807                                                 $paramArrayStr .= "'$name' => \$$name, ";\r
6808                                                 $paramCommentStr .= "$type \$$name, ";\r
6809                                         }\r
6810                                         $paramStr = substr($paramStr, 0, strlen($paramStr)-2);\r
6811                                         $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);\r
6812                                         $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);\r
6813                                 } else {\r
6814                                         $paramStr = '';\r
6815                                         $paramArrayStr = '';\r
6816                                         $paramCommentStr = 'void';\r
6817                                 }\r
6818                                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];\r
6819                                 $evalStr .= "// $paramCommentStr\r
6820         function " . str_replace('.', '__', $operation) . "($paramStr) {\r
6821                 \$params = array($paramArrayStr);\r
6822                 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');\r
6823         }\r
6824         ";\r
6825                                 unset($paramStr);\r
6826                                 unset($paramCommentStr);\r
6827                         }\r
6828                 }\r
6829                 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {\r
6830         '.$evalStr.'\r
6831 }';\r
6832                 return $evalStr;\r
6833         }\r
6834 \r
6835         /**\r
6836         * dynamically creates proxy class code\r
6837         *\r
6838         * @return   string PHP/NuSOAP code for the proxy class\r
6839         * @access   public\r
6840         */\r
6841         function getProxyClassCode() {\r
6842                 $r = rand();\r
6843                 return $this->_getProxyClassCode($r);\r
6844         }\r
6845 \r
6846         /**\r
6847         * gets the HTTP body for the current request.\r
6848         *\r
6849         * @param string $soapmsg The SOAP payload\r
6850         * @return string The HTTP body, which includes the SOAP payload\r
6851         * @access private\r
6852         */\r
6853         function getHTTPBody($soapmsg) {\r
6854                 return $soapmsg;\r
6855         }\r
6856         \r
6857         /**\r
6858         * gets the HTTP content type for the current request.\r
6859         *\r
6860         * Note: getHTTPBody must be called before this.\r
6861         *\r
6862         * @return string the HTTP content type for the current request.\r
6863         * @access private\r
6864         */\r
6865         function getHTTPContentType() {\r
6866                 return 'text/xml';\r
6867         }\r
6868         \r
6869         /**\r
6870         * gets the HTTP content type charset for the current request.\r
6871         * returns false for non-text content types.\r
6872         *\r
6873         * Note: getHTTPBody must be called before this.\r
6874         *\r
6875         * @return string the HTTP content type charset for the current request.\r
6876         * @access private\r
6877         */\r
6878         function getHTTPContentTypeCharset() {\r
6879                 return $this->soap_defencoding;\r
6880         }\r
6881 \r
6882         /*\r
6883         * whether or not parser should decode utf8 element content\r
6884     *\r
6885     * @return   always returns true\r
6886     * @access   public\r
6887     */\r
6888     function decodeUTF8($bool){\r
6889                 $this->decode_utf8 = $bool;\r
6890                 return true;\r
6891     }\r
6892 \r
6893         /**\r
6894          * adds a new Cookie into $this->cookies array\r
6895          *\r
6896          * @param       string $name Cookie Name\r
6897          * @param       string $value Cookie Value\r
6898          * @return      boolean if cookie-set was successful returns true, else false\r
6899          * @access      public\r
6900          */\r
6901         function setCookie($name, $value) {\r
6902                 if (strlen($name) == 0) {\r
6903                         return false;\r
6904                 }\r
6905                 $this->cookies[] = array('name' => $name, 'value' => $value);\r
6906                 return true;\r
6907         }\r
6908 \r
6909         /**\r
6910          * gets all Cookies\r
6911          *\r
6912          * @return   array with all internal cookies\r
6913          * @access   public\r
6914          */\r
6915         function getCookies() {\r
6916                 return $this->cookies;\r
6917         }\r
6918 \r
6919         /**\r
6920          * checks all Cookies and delete those which are expired\r
6921          *\r
6922          * @return   boolean always return true\r
6923          * @access   private\r
6924          */\r
6925         function checkCookies() {\r
6926                 if (sizeof($this->cookies) == 0) {\r
6927                         return true;\r
6928                 }\r
6929                 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');\r
6930                 $curr_cookies = $this->cookies;\r
6931                 $this->cookies = array();\r
6932                 foreach ($curr_cookies as $cookie) {\r
6933                         if (! is_array($cookie)) {\r
6934                                 $this->debug('Remove cookie that is not an array');\r
6935                                 continue;\r
6936                         }\r
6937                         if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {\r
6938                                 if (strtotime($cookie['expires']) > time()) {\r
6939                                         $this->cookies[] = $cookie;\r
6940                                 } else {\r
6941                                         $this->debug('Remove expired cookie ' . $cookie['name']);\r
6942                                 }\r
6943                         } else {\r
6944                                 $this->cookies[] = $cookie;\r
6945                         }\r
6946                 }\r
6947                 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');\r
6948                 return true;\r
6949         }\r
6950 \r
6951         /**\r
6952          * updates the current cookies with a new set\r
6953          *\r
6954          * @param       array $cookies new cookies with which to update current ones\r
6955          * @return      boolean always return true\r
6956          * @access      private\r
6957          */\r
6958         function UpdateCookies($cookies) {\r
6959                 if (sizeof($this->cookies) == 0) {\r
6960                         // no existing cookies: take whatever is new\r
6961                         if (sizeof($cookies) > 0) {\r
6962                                 $this->debug('Setting new cookie(s)');\r
6963                                 $this->cookies = $cookies;\r
6964                         }\r
6965                         return true;\r
6966                 }\r
6967                 if (sizeof($cookies) == 0) {\r
6968                         // no new cookies: keep what we've got\r
6969                         return true;\r
6970                 }\r
6971                 // merge\r
6972                 foreach ($cookies as $newCookie) {\r
6973                         if (!is_array($newCookie)) {\r
6974                                 continue;\r
6975                         }\r
6976                         if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {\r
6977                                 continue;\r
6978                         }\r
6979                         $newName = $newCookie['name'];\r
6980 \r
6981                         $found = false;\r
6982                         for ($i = 0; $i < count($this->cookies); $i++) {\r
6983                                 $cookie = $this->cookies[$i];\r
6984                                 if (!is_array($cookie)) {\r
6985                                         continue;\r
6986                                 }\r
6987                                 if (!isset($cookie['name'])) {\r
6988                                         continue;\r
6989                                 }\r
6990                                 if ($newName != $cookie['name']) {\r
6991                                         continue;\r
6992                                 }\r
6993                                 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';\r
6994                                 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';\r
6995                                 if ($newDomain != $domain) {\r
6996                                         continue;\r
6997                                 }\r
6998                                 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';\r
6999                                 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';\r
7000                                 if ($newPath != $path) {\r
7001                                         continue;\r
7002                                 }\r
7003                                 $this->cookies[$i] = $newCookie;\r
7004                                 $found = true;\r
7005                                 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);\r
7006                                 break;\r
7007                         }\r
7008                         if (! $found) {\r
7009                                 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);\r
7010                                 $this->cookies[] = $newCookie;\r
7011                         }\r
7012                 }\r
7013                 return true;\r
7014         }\r
7015 }\r
7016 \r
7017 if (!extension_loaded('soap')) {\r
7018         /**\r
7019          *      For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.\r
7020          */\r
7021         class soapclient extends nusoap_client {\r
7022         }\r
7023 }\r
7024 ?>\r