Edgewall Software

Ticket #2756: nusoap12.php

File nusoap12.php, 133.8 KB (added by anonymous, 6 years ago)

Smallest file

Line 
1<?php
2
3/*
4
5NuSOAP - Web Services Toolkit for PHP
6
7Copyright (c) 2002 NuSphere Corporation
8
9This library is free software; you can redistribute it and/or
10modify it under the terms of the GNU Lesser General Public
11License as published by the Free Software Foundation; either
12version 2.1 of the License, or (at your option) any later version.
13
14This library is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public
20License along with this library; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
23If you have any questions or comments, please email:
24
25Dietrich Ayala
26dietrich@ganx4.com
27http://dietrich.ganx4.com/nusoap
28
29NuSphere Corporation
30http://www.nusphere.com
31
32*/
33
34/* load classes
35
36// necessary classes
37require_once('class.soapclient.php');
38require_once('class.soap_val.php');
39require_once('class.soap_parser.php');
40require_once('class.soap_fault.php');
41
42// transport classes
43require_once('class.soap_transport_http.php');
44
45// optional add-on classes
46require_once('class.xmlschema.php');
47require_once('class.wsdl.php');
48
49// server class
50require_once('class.soap_server.php');*/
51
52/**
53*
54* nusoap_base
55*
56* @author   Dietrich Ayala <dietrich@ganx4.com>
57* @version  v 0.6.3
58* @access   public
59*/
60class nusoap_base {
61
62        var $title = 'NuSOAP';
63        var $version = '0.6.3';
64        var $error_str = false;
65    var $debug_str = '';
66        // toggles automatic encoding of special characters
67        var $charencoding = true;
68
69    /**
70        *  set schema version
71        *
72        * @var      XMLSchemaVersion
73        * @access   public
74        */
75        var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
76       
77    /**
78        *  set default encoding
79        *
80        * @var      soap_defencoding
81        * @access   public
82        */
83        //var $soap_defencoding = 'UTF-8';
84    var $soap_defencoding = 'ISO-8859-1';
85
86        /**
87        *  load namespace uris into an array of uri => prefix
88        *
89        * @var      namespaces
90        * @access   public
91        */
92        var $namespaces = array(
93                'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
94                'xsd' => 'http://www.w3.org/2001/XMLSchema',
95                'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
96                'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
97                'si' => 'http://soapinterop.org/xsd');
98        /**
99        * load types into typemap array
100        * is this legacy yet?
101        * no, this is used by the xmlschema class to verify type => namespace mappings.
102        * @var      typemap
103        * @access   public
104        */
105        var $typemap = array(
106        'http://www.w3.org/2001/XMLSchema' => array(
107                'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
108                'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
109                'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
110                // derived datatypes
111                'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
112                'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
113                'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
114                'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
115        'http://www.w3.org/1999/XMLSchema' => array(
116                'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
117                'float'=>'double','dateTime'=>'string',
118                'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
119        'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
120        'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
121    'http://xml.apache.org/xml-soap' => array('Map')
122        );
123
124        /**
125        *  entities to convert
126        *
127        * @var      xmlEntities
128        * @access   public
129        */
130        var $xmlEntities = array('quot' => '"','amp' => '&',
131                'lt' => '<','gt' => '>','apos' => "'");
132
133        /**
134        * adds debug data to the class level debug string
135        *
136        * @param    string $string debug data
137        * @access   private
138        */
139        function debug($string){
140                $this->debug_str .= get_class($this).": $string\n";
141        }
142
143        /**
144        * returns error string if present
145        *
146        * @return   boolean $string error string
147        * @access   public
148        */
149        function getError(){
150                if($this->error_str != ''){
151                        return $this->error_str;
152                }
153                return false;
154        }
155
156        /**
157        * sets error string
158        *
159        * @return   boolean $string error string
160        * @access   private
161        */
162        function setError($str){
163                $this->error_str = $str;
164        }
165
166        /**
167        * serializes PHP values in accordance w/ section 5. Type information is
168        * not serialized if $use == 'literal'.
169        *
170        * @return       string
171    * @access   public
172        */
173        function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
174        if(is_object($val) && get_class($val) == 'soapval'){
175                return $val->serialize($use);
176        }
177                $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
178                // if no name, use item
179                $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
180                // if name has ns, add ns prefix to name
181                $xmlns = '';
182        if($name_ns){
183                        $prefix = 'nu'.rand(1000,9999);
184                        $name = $prefix.':'.$name;
185                        $xmlns .= " xmlns:$prefix=\"$name_ns\"";
186                }
187                // if type is prefixed, create type prefix
188                if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
189                        // need to fix this. shouldn't default to xsd if no ns specified
190                    // w/o checking against typemap
191                        $type_prefix = 'xsd';
192                } elseif($type_ns){
193                        $type_prefix = 'ns'.rand(1000,9999);
194                        $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
195                }
196                // serialize attributes if present
197                if($attributes){
198                        foreach($attributes as $k => $v){
199                                $atts .= " $k=\"$v\"";
200                        }
201                }
202        // serialize if an xsd built-in primitive type
203        if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
204                if ($use == 'literal') {
205                        return "<$name$xmlns>$val</$name>";
206                } else {
207                        return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>";
208                }
209        }
210                // detect type and serialize
211                $xml = '';
212                $atts = '';
213                switch(true) {
214                        case ($type == '' && is_null($val)):
215                                if ($use == 'literal') {
216                                        // TODO: depends on nillable
217                                        $xml .= "<$name$xmlns/>";
218                                } else {
219                                        $xml .= "<$name$xmlns xsi:type=\"xsd:nil\"/>";
220                                }
221                                break;
222                        case (is_bool($val) || $type == 'boolean'):
223                                if(!$val){
224                                $val = 0;
225                                }
226                                if ($use == 'literal') {
227                                        $xml .= "<$name$xmlns $atts>$val</$name>";
228                                } else {
229                                        $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
230                                }
231                                break;
232                        case (is_int($val) || is_long($val) || $type == 'int'):
233                                if ($use == 'literal') {
234                                        $xml .= "<$name$xmlns $atts>$val</$name>";
235                                } else {
236                                        $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
237                                }
238                                break;
239                        case (is_float($val)|| is_double($val) || $type == 'float'):
240                                if ($use == 'literal') {
241                                        $xml .= "<$name$xmlns $atts>$val</$name>";
242                                } else {
243                                        $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
244                                }
245                                break;
246                        case (is_string($val) || $type == 'string'):
247                                if($this->charencoding){
248                                $val = htmlspecialchars($val, ENT_QUOTES);
249                            }
250                                if ($use == 'literal') {
251                                        $xml .= "<$name$xmlns $atts>$val</$name>";
252                                } else {
253                                        $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
254                                }
255                                break;
256                        case is_object($val):
257                                $name = get_class($val);
258                                foreach(get_object_vars($val) as $k => $v){
259                                        $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
260                                }
261                                $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
262                                break;
263                        break;
264                        case (is_array($val) || $type):
265                                // detect if struct or array
266                $keyList = array_keys($val);
267                                $valueType = 'arraySimple';
268                                foreach($keyList as $keyListValue){
269                                        if(!is_int($keyListValue)){
270                                                $valueType = 'arrayStruct';
271                                                break;
272                                        }
273                                }
274                if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
275                                        $i = 0;
276                                        if(is_array($val) && count($val)> 0){
277                                                foreach($val as $v){
278                                if(is_object($v) && get_class($v) == 'soapval'){
279                                        $tt = $v->type;
280                                } else {
281                                                                $tt = gettype($v);
282                                }
283                                                        $array_types[$tt] = 1;
284                                                        $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
285                                                        if(is_array($v) && is_numeric(key($v))){
286                                                                $i += sizeof($v);
287                                                        } else {
288                                                                ++$i;
289                                                        }
290                                                }
291                                                if(count($array_types) > 1){
292                                                        $array_typename = 'xsd:ur-type';
293                                                } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
294                                                        $array_typename = 'xsd:'.$tt;
295                                                } elseif($tt == 'array' || $tt == 'Array'){
296                                                        $array_typename = 'SOAP-ENC:Array';
297                                                } else {
298                                                        $array_typename = $tt;
299                                                }
300                                                if(isset($array_types['array'])){
301                                                        $array_type = $i.",".$i;
302                                                } else {
303                                                        $array_type = $i;
304                                                }
305                                                if ($use == 'literal') {
306                                                        $xml = "<$name $atts>".$xml."</$name>";
307                                                } else {
308                                                        $xml = "<$name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"$atts>".$xml."</$name>";
309                                                }
310                                        // empty array
311                                        } else {
312                                                if ($use == 'literal') {
313                                                        $xml = "<$name $atts>".$xml."</$name>";;
314                                                } else {
315                                                        $xml = "<$name xsi:type=\"SOAP-ENC:Array\" $atts>".$xml."</$name>";;
316                                                }
317                                        }
318                                } else {
319                                        // got a struct
320                                        if(isset($type) && isset($type_prefix)){
321                                                $type_str = " xsi:type=\"$type_prefix:$type\"";
322                                        } else {
323                                                $type_str = '';
324                                        }
325                                        if ($use == 'literal') {
326                                                $xml .= "<$name$xmlns $atts>";
327                                        } else {
328                                                $xml .= "<$name$xmlns$type_str$atts>";
329                                        }
330                                        foreach($val as $k => $v){
331                                                $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
332                                        }
333                                        $xml .= "</$name>";
334                                }
335                                break;
336                        default:
337                                $xml .= 'not detected, got '.gettype($val).' for '.$val;
338                                break;
339                }
340                return $xml;
341        }
342
343    /**
344    * serialize message
345    *
346    * @param string body
347    * @param string headers
348    * @param array namespaces
349    * @param string style
350    * @return string message
351    * @access public
352    */
353    function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc'){
354        // serialize namespaces
355    $ns_string = '';
356        foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
357                $ns_string .= "  xmlns:$k=\"$v\"";
358        }
359        if($style == 'rpc') {
360                $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
361        }
362
363        // serialize headers
364        if($headers){
365                $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
366        }
367        // serialize envelope
368        return
369        '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
370        '<SOAP-ENV:Envelope'.$ns_string.">".
371        $headers.
372        "<SOAP-ENV:Body>".
373                $body.
374        "</SOAP-ENV:Body>".
375        "</SOAP-ENV:Envelope>";
376    }
377
378    function formatDump($str){
379                $str = htmlspecialchars($str);
380                return nl2br($str);
381    }
382
383    /**
384    * returns the local part of a prefixed string
385    * returns the original string, if not prefixed
386    *
387    * @param string
388    * @return string
389    * @access public
390    */
391        function getLocalPart($str){
392                if($sstr = strrchr($str,':')){
393                        // get unqualified name
394                        return substr( $sstr, 1 );
395                } else {
396                        return $str;
397                }
398        }
399
400        /**
401    * returns the prefix part of a prefixed string
402    * returns false, if not prefixed
403    *
404    * @param string
405    * @return mixed
406    * @access public
407    */
408        function getPrefix($str){
409                if($pos = strrpos($str,':')){
410                        // get prefix
411                        return substr($str,0,$pos);
412                }
413                return false;
414        }
415
416    function varDump($data) {
417                ob_start();
418                var_dump($data);
419                $ret_val = ob_get_contents();
420                ob_end_clean();
421                return $ret_val;
422        }
423}
424
425// XML Schema Datatype Helper Functions
426
427//xsd:dateTime helpers
428
429/**
430* convert unix timestamp to ISO 8601 compliant date string
431*
432* @param    string $timestamp Unix time stamp
433* @access   public
434*/
435function timestamp_to_iso8601($timestamp,$utc=true){
436        $datestr = date('Y-m-d\TH:i:sO',$timestamp);
437        if($utc){
438                $eregStr =
439                '([0-9]{4})-'.  // centuries & years CCYY-
440                '([0-9]{2})-'.  // months MM-
441                '([0-9]{2})'.   // days DD
442                'T'.                    // separator T
443                '([0-9]{2}):'.  // hours hh:
444                '([0-9]{2}):'.  // minutes mm:
445                '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
446                '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
447
448                if(ereg($eregStr,$datestr,$regs)){
449                        return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
450                }
451                return false;
452        } else {
453                return $datestr;
454        }
455}
456
457/**
458* convert ISO 8601 compliant date string to unix timestamp
459*
460* @param    string $datestr ISO 8601 compliant date string
461* @access   public
462*/
463function iso8601_to_timestamp($datestr){
464        $eregStr =
465        '([0-9]{4})-'.  // centuries & years CCYY-
466        '([0-9]{2})-'.  // months MM-
467        '([0-9]{2})'.   // days DD
468        'T'.                    // separator T
469        '([0-9]{2}):'.  // hours hh:
470        '([0-9]{2}):'.  // minutes mm:
471        '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
472        '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
473        if(ereg($eregStr,$datestr,$regs)){
474                // not utc
475                if($regs[8] != 'Z'){
476                        $op = substr($regs[8],0,1);
477                        $h = substr($regs[8],1,2);
478                        $m = substr($regs[8],strlen($regs[8])-2,2);
479                        if($op == '-'){
480                                $regs[4] = $regs[4] + $h;
481                                $regs[5] = $regs[5] + $m;
482                        } elseif($op == '+'){
483                                $regs[4] = $regs[4] - $h;
484                                $regs[5] = $regs[5] - $m;
485                        }
486                }
487                return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
488        } else {
489                return false;
490        }
491}
492
493
494
495?><?php
496
497
498
499/**
500* soap_fault class, allows for creation of faults
501* mainly used for returning faults from deployed functions
502* in a server instance.
503* @author   Dietrich Ayala <dietrich@ganx4.com>
504* @version  v 0.6.3
505* @access public
506*/
507class soap_fault extends nusoap_base {
508
509        var $faultcode;
510        var $faultactor;
511        var $faultstring;
512        var $faultdetail;
513
514        /**
515        * constructor
516    *
517    * @param string $faultcode (client | server)
518    * @param string $faultactor only used when msg routed between multiple actors
519    * @param string $faultstring human readable error message
520    * @param string $faultdetail
521        */
522        function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
523                $this->faultcode = $faultcode;
524                $this->faultactor = $faultactor;
525                $this->faultstring = $faultstring;
526                $this->faultdetail = $faultdetail;
527        }
528
529        /**
530        * serialize a fault
531        *
532        * @access   public
533        */
534        function serialize(){
535                $ns_string = '';
536                foreach($this->namespaces as $k => $v){
537                        $ns_string .= "\n  xmlns:$k=\"$v\"";
538                }
539                $return_msg =
540                        '<?xml version="1.0"?'.">\n".
541                        '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
542                                '<SOAP-ENV:Body>'.
543                                '<SOAP-ENV:Fault>'.
544                                        '<faultcode>'.$this->faultcode.'</faultcode>'.
545                                        '<faultactor>'.$this->faultactor.'</faultactor>'.
546                                        '<faultstring>'.$this->faultstring.'</faultstring>'.
547                                        '<detail>'.$this->serialize_val($this->faultdetail).'</detail>'.
548                                '</SOAP-ENV:Fault>'.
549                                '</SOAP-ENV:Body>'.
550                        '</SOAP-ENV:Envelope>';
551                return $return_msg;
552        }
553}
554
555
556
557?><?php
558
559
560
561/**
562* parses an XML Schema, allows access to it's data, other utility methods
563* no validation... yet.
564* very experimental and limited. As is discussed on XML-DEV, I'm one of the people
565* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
566* tutorials I refer to :)
567*
568* @author   Dietrich Ayala <dietrich@ganx4.com>
569* @version  v 0.6.3
570* @access   public
571*/
572class XMLSchema extends nusoap_base  {
573       
574        // files
575        var $schema = '';
576        var $xml = '';
577        // define internal arrays of bindings, ports, operations, messages, etc.
578        var $complexTypes = array();
579        // target namespace
580        var $schemaTargetNamespace = '';
581        // parser vars
582        var $parser;
583        var $position;
584        var $depth = 0;
585        var $depth_array = array();
586   
587        /**
588        * constructor
589        *
590        * @param    string $schema schema document URI
591        * @param    string $xml xml document URI
592        * @access   public
593        */
594        function XMLSchema($schema='',$xml=''){
595
596                $this->debug('xmlschema class instantiated, inside constructor');
597                // files
598                $this->schema = $schema;
599                $this->xml = $xml;
600
601                // parse schema file
602                if($schema != ''){
603                        $this->debug('initial schema file: '.$schema);
604                        $this->parseFile($schema);
605                }
606
607                // parse xml file
608                if($xml != ''){
609                        $this->debug('initial xml file: '.$xml);
610                        $this->parseFile($xml);
611                }
612
613        }
614
615    /**
616    * parse an XML file
617    *
618    * @param string $xml, path/URL to XML file
619    * @param string $type, (schema | xml)
620        * @return boolean
621    * @access public
622    */
623        function parseFile($xml,$type){
624                // parse xml file
625                if($xml != ""){
626                        $this->debug('parsing $xml');
627                        $xmlStr = @join("",@file($xml));
628                        if($xmlStr == ""){
629                                $this->setError('No file at the specified URL: '.$xml);
630                        return false;
631                        } else {
632                                $this->parseString($xmlStr,$type);
633                        return true;
634                        }
635                }
636                return false;
637        }
638
639        /**
640        * parse an XML string
641        *
642        * @param    string $xml path or URL
643    * @param string $type, (schema|xml)
644        * @access   private
645        */
646        function parseString($xml,$type){
647                // parse xml string
648                if($xml != ""){
649
650                // Create an XML parser.
651                $this->parser = xml_parser_create();
652                // Set the options for parsing the XML data.
653                xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
654
655                // Set the object for the parser.
656                xml_set_object($this->parser, $this);
657
658                // Set the element handlers for the parser.
659                        if($type == "schema"){
660                        xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
661                        xml_set_character_data_handler($this->parser,'schemaCharacterData');
662                        } elseif($type == "xml"){
663                                xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
664                        xml_set_character_data_handler($this->parser,'xmlCharacterData');
665                        }
666
667                    // Parse the XML file.
668                    if(!xml_parse($this->parser,$xml,true)){
669                        // Display an error message.
670                                $errstr = sprintf('XML error on line %d: %s',
671                                xml_get_current_line_number($this->parser),
672                                xml_error_string(xml_get_error_code($this->parser))
673                                );
674                                $this->debug('XML parse error: '.$errstr);
675                                $this->setError('Parser error: '.$errstr);
676                }
677           
678                        xml_parser_free($this->parser);
679                } else{
680                        $this->debug('no xml passed to parseString()!!');
681                        $this->setError('no xml passed to parseString()!!');
682                }
683        }
684
685        /**
686        * start-element handler
687        *
688        * @param    string $parser XML parser object
689        * @param    string $name element name
690        * @param    string $attrs associative array of attributes
691        * @access   private
692        */
693        function schemaStartElement($parser, $name, $attrs) {
694               
695                // position in the total number of elements, starting from 0
696                $pos = $this->position++;
697                $depth = $this->depth++;
698                // set self as current value for this depth
699                $this->depth_array[$depth] = $pos;
700
701                // get element prefix
702                if($prefix = $this->getPrefix($name)){
703                        // get unqualified name
704                        $name = $this->getLocalPart($name);
705                } else {
706                $prefix = '';
707        }
708               
709        // loop thru attributes, expanding, and registering namespace declarations
710        if(count($attrs) > 0){
711                foreach($attrs as $k => $v){
712                // if ns declarations, add to class level array of valid namespaces
713                                if(ereg("^xmlns",$k)){
714                        //$this->xdebug("$k: $v");
715                        //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
716                        if($ns_prefix = substr(strrchr($k,':'),1)){
717                                                $this->namespaces[$ns_prefix] = $v;
718                                        } else {
719                                                $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
720                                        }
721                                        if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){
722                                                $this->XMLSchemaVersion = $v;
723                                                $this->namespaces['xsi'] = $v.'-instance';
724                                        }
725                                }
726                }
727                foreach($attrs as $k => $v){
728                // expand each attribute
729                $k = strpos($k,':') ? $this->expandQname($k) : $k;
730                $v = strpos($v,':') ? $this->expandQname($v) : $v;
731                        $eAttrs[$k] = $v;
732                }
733                $attrs = $eAttrs;
734        } else {
735                $attrs = array();
736        }
737                // find status, register data
738                switch($name){
739                        case ('all'|'choice'|'sequence'):
740                                //$this->complexTypes[$this->currentComplexType]['compositor'] = 'all';
741                                $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
742                                if($name == 'all'){
743                                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
744                                }
745                        break;
746                        case 'attribute':
747                //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
748                if(isset($attrs['name'])){
749                                        $this->attributes[$attrs['name']] = $attrs;
750                                        $aname = $attrs['name'];
751                                } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
752                        $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
753                                } elseif(isset($attrs['ref'])){
754                                        $aname = $attrs['ref'];
755                    $this->attributes[$attrs['ref']] = $attrs;
756                                }
757               
758                                if(isset($this->currentComplexType)){
759                                        $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
760                                } elseif(isset($this->currentElement)){
761                                        $this->elements[$this->currentElement]['attrs'][$aname] = $attrs;
762                                }
763                                // arrayType attribute
764                                if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
765                                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
766                        $prefix = $this->getPrefix($aname);
767                                        if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
768                                                $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
769                                        } else {
770                                                $v = '';
771                                        }
772                    if(strpos($v,'[,]')){
773                        $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
774                    }
775                    $v = substr($v,0,strpos($v,'[')); // clip the []
776                    if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
777                        $v = $this->XMLSchemaVersion.':'.$v;
778                    }
779                    $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
780                                }
781                        break;
782                        case 'complexType':
783                                if(isset($attrs['name'])){
784                                        $this->currentElement = false;
785                                        $this->currentComplexType = $attrs['name'];
786                                        $this->complexTypes[$this->currentComplexType] = $attrs;
787                                        $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
788                                        if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
789                                                $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
790                                        } else {
791                                                $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
792                                        }
793                                        $this->xdebug('processing complexType '.$attrs['name']);
794                                }
795                        break;
796                        case 'element':
797                                if(isset($attrs['type'])){
798                                        $this->xdebug("processing element ".$attrs['name']);
799                                        $this->currentElement = $attrs['name'];
800                                        $this->elements[ $attrs['name'] ] = $attrs;
801                                        $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
802                                        $ename = $attrs['name'];
803                                } elseif(isset($attrs['ref'])){
804                                        $ename = $attrs['ref'];
805                                } else {
806                                        $this->xdebug('adding complexType '.$attrs['name']);
807                                        $this->currentComplexType = $attrs['name'];
808                                        $this->complexTypes[ $attrs['name'] ] = $attrs;
809                                        $this->complexTypes[ $attrs['name'] ]['element'] = 1;
810                                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
811                                }
812                                if(isset($ename) && $this->currentComplexType){
813                                        $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
814                                }
815                        break;
816                        case 'restriction':
817                                $this->xdebug("in restriction for ct: $this->currentComplexType and ce: $this->currentElement");
818                                if($this->currentElement){
819                                        $this->elements[$this->currentElement]['type'] = $attrs['base'];
820                                } elseif($this->currentComplexType){
821                                        $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
822                                        if(strstr($attrs['base'],':') == ':Array'){
823                                                $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
824                                        }
825                                }
826                        break;
827                        case 'schema':
828                                $this->schema = $attrs;
829                                $this->schema['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
830                        break;
831                        case 'simpleType':
832                                $this->currentElement = $attrs['name'];
833                                $this->elements[ $attrs['name'] ] = $attrs;
834                                $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
835                        break;
836                }
837        }
838
839        /**
840        * end-element handler
841        *
842        * @param    string $parser XML parser object
843        * @param    string $name element name
844        * @access   private
845        */
846        function schemaEndElement($parser, $name) {
847                // position of current element is equal to the last value left in depth_array for my depth
848                if(isset($this->depth_array[$this->depth])){
849                $pos = $this->depth_array[$this->depth];
850        }
851                // bring depth down a notch
852                $this->depth--;
853                // move on...
854                if($name == 'complexType'){
855                        $this->currentComplexType = false;
856                        $this->currentElement = false;
857                }
858                if($name == 'element'){
859                        $this->currentElement = false;
860                }
861        }
862
863        /**
864        * element content handler
865        *
866        * @param    string $parser XML parser object
867        * @param    string $data element content
868        * @access   private
869        */
870        function schemaCharacterData($parser, $data){
871                $pos = $this->depth_array[$this->depth];
872                $this->message[$pos]['cdata'] .= $data;
873        }
874
875        /**
876        * serialize the schema
877        *
878        * @access   public
879        */
880        function serializeSchema(){
881
882                $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
883                $xml = '';
884                // complex types
885                foreach($this->complexTypes as $typeName => $attrs){
886                        $contentStr = '';
887                        // serialize child elements
888                        if(count($attrs['elements']) > 0){
889                                foreach($attrs['elements'] as $element => $eParts){
890                                        if(isset($eParts['ref'])){
891                                                $contentStr .= "<element ref=\"$element\"/>";
892                                        } else {
893                                                $contentStr .= "<element name=\"$element\" type=\"$eParts[type]\"/>";
894                                        }
895                                }
896                        }
897                        // attributes
898                        if(count($attrs['attrs']) >= 1){
899                                foreach($attrs['attrs'] as $attr => $aParts){
900                                        $contentStr .= '<attribute ref="'.$aParts['ref'].'"';
901                                        if(isset($aParts['wsdl:arrayType'])){
902                                                $contentStr .= ' wsdl:arrayType="'.$aParts['wsdl:arrayType'].'"';
903                                        }
904                                        $contentStr .= '/>';
905                                }
906                        }
907                        // if restriction
908                        if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
909                                $contentStr = "<$schemaPrefix:restriction base=\"".$attrs['restrictionBase']."\">".$contentStr."</$schemaPrefix:restriction>";
910                        }
911                        // "all" compositor obviates complex/simple content
912                        if(isset($attrs['compositor']) && $attrs['compositor'] == 'all'){
913                                $contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>";
914                        }
915                        // complex or simple content
916                        elseif( count($attrs['elements']) > 0 || count($attrs['attrs']) > 0){
917                                $contentStr = "<$schemaPrefix:complexContent>".$contentStr."</$schemaPrefix:complexContent>";
918                        }
919                        // compositors
920                        if(isset($attrs['compositor']) && $attrs['compositor'] != '' && $attrs['compositor'] != 'all'){
921                                $contentStr = "<$schemaPrefix:$attrs[compositor]>".$contentStr."</$schemaPrefix:$attrs[compositor]>";
922                        }
923                        // finalize complex type
924                        if($contentStr != ''){
925                                $contentStr = "<$schemaPrefix:complexType name=\"$typeName\">".$contentStr."</$schemaPrefix:complexType>";
926                        } else {
927                                $contentStr = "<$schemaPrefix:complexType name=\"$typeName\"/>";
928                        }
929                        $xml .= $contentStr;
930                }
931                // elements
932                if(isset($this->elements) && count($this->elements) > 0){
933                        foreach($this->elements as $element => $eParts){
934                                $xml .= "<$schemaPrefix:element name=\"$element\" type=\"".$eParts['type']."\"/>";
935                        }
936                }
937                // attributes
938                if(isset($this->attributes) && count($this->attributes) > 0){
939                        foreach($this->attributes as $attr => $aParts){
940                                $xml .= "<$schemaPrefix:attribute name=\"$attr\" type=\"".$aParts['type']."\"/>";
941                        }
942                }
943                // finish 'er up
944                $xml = "<$schemaPrefix:schema xmlns=\"$this->XMLSchemaVersion\" targetNamespace=\"$this->schemaTargetNamespace\">".$xml."</$schemaPrefix:schema>";
945                return $xml;
946        }
947
948        /**
949        * expands a qualified name
950        *
951        * @param    string $string qname
952        * @return       string expanded qname
953        * @access   private
954        */
955        function expandQname($qname){
956                // get element prefix
957                if(strpos($qname,':') && !ereg('^http://',$qname)){
958                        // get unqualified name
959                        $name = substr(strstr($qname,':'),1);
960                        // get ns prefix
961                        $prefix = substr($qname,0,strpos($qname,':'));
962                        if(isset($this->namespaces[$prefix])){
963                                return $this->namespaces[$prefix].':'.$name;
964                        } else {
965                                return $qname;
966                        }
967                } else {
968                        return $qname;
969                }
970        }
971
972        /**
973        * adds debug data to the clas level debug string
974        *
975        * @param    string $string debug data
976        * @access   private
977        */
978        function xdebug($string){
979                $this->debug(' xmlschema: '.$string);
980        }
981
982    /**
983    * get the PHP type of a user defined type in the schema
984    * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
985    * returns false if no type exists, or not w/ the given namespace
986    * else returns a string that is either a native php type, or 'struct'
987    *
988    * @param string $type, name of defined type
989    * @param string $ns, namespace of type
990    * @return mixed
991    * @access public
992    */
993        function getPHPType($type,$ns){
994                global $typemap;
995                if(isset($typemap[$ns][$type])){
996                        //print "found type '$type' and ns $ns in typemap<br>";
997                        return $typemap[$ns][$type];
998                } elseif(isset($this->complexTypes[$type])){
999                        //print "getting type '$type' and ns $ns from complexTypes array<br>";
1000                        return $this->complexTypes[$type]['phpType'];
1001                }
1002                return false;
1003        }
1004
1005    /**
1006    * returns the local part of a prefixed string
1007    * returns the original string, if not prefixed
1008    *
1009    * @param string
1010    * @return string
1011    * @access public
1012    */
1013        function getLocalPart($str){
1014                if($sstr = strrchr($str,':')){
1015                        // get unqualified name
1016                        return substr( $sstr, 1 );
1017                } else {
1018                        return $str;
1019                }
1020        }
1021
1022        /**
1023    * returns the prefix part of a prefixed string
1024    * returns false, if not prefixed
1025    *
1026    * @param string
1027    * @return mixed
1028    * @access public
1029    */
1030        function getPrefix($str){
1031                if($pos = strrpos($str,':')){
1032                        // get prefix
1033                        return substr($str,0,$pos);
1034                }
1035                return false;
1036        }
1037
1038        /**
1039    * pass it a prefix, it returns a namespace
1040        * returns false if no namespace registered with the given prefix
1041    *
1042    * @param string
1043    * @return mixed
1044    * @access public
1045    */
1046        function getNamespaceFromPrefix($prefix){
1047                if(isset($this->namespaces[$prefix])){
1048                        return $this->namespaces[$prefix];
1049                }
1050                //$this->setError("No namespace registered for prefix '$prefix'");
1051                return false;
1052        }
1053
1054        /**
1055    * returns the prefix for a given namespace (or prefix)
1056    * or false if no prefixes registered for the given namespace
1057    *
1058    * @param string
1059    * @return mixed
1060    * @access public
1061    */
1062        function getPrefixFromNamespace($ns){
1063                foreach($this->namespaces as $p => $n){
1064                        if($ns == $n || $ns == $p){
1065                            $this->usedNamespaces[$p] = $n;
1066                                return $p;
1067                        }
1068                }
1069                return false;
1070        }
1071
1072        /**
1073    * returns an array of information about a given type
1074    * returns false if no type exists by the given name
1075    *
1076        *        typeDef = array(
1077        *        'elements' => array(), // refs to elements array
1078        *       'restrictionBase' => '',
1079        *       'phpType' => '',
1080        *       'order' => '(sequence|all)',
1081        *       'attrs' => array() // refs to attributes array
1082        *       )
1083    *
1084    * @param string
1085    * @return mixed
1086    * @access public
1087    */
1088        function getTypeDef($type){
1089                if(isset($this->complexTypes[$type])){
1090                        return $this->complexTypes[$type];
1091                } elseif(isset($this->elements[$type])){
1092                        return $this->elements[$type];
1093                } elseif(isset($this->attributes[$type])){
1094                        return $this->attributes[$type];
1095                }
1096                return false;
1097        }
1098
1099        /**
1100    * returns a sample serialization of a given type, or false if no type by the given name
1101    *
1102    * @param string $type, name of type
1103    * @return mixed
1104    * @access public
1105    */
1106    function serializeTypeDef($type){
1107        //print "in sTD() for type $type<br>";
1108        if($typeDef = $this->getTypeDef($type)){
1109                $str .= '<'.$type;
1110            if(is_array($typeDef['attrs'])){
1111                foreach($attrs as $attName => $data){
1112                    $str .= " $attName=\"{type = ".$data['type']."}\"";
1113                }
1114            }
1115            $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1116            if(count($typeDef['elements']) > 0){
1117                $str .= ">";
1118                foreach($typeDef['elements'] as $element => $eData){
1119                    $str .= $this->serializeTypeDef($element);
1120                }
1121                $str .= "</$type>";
1122            } elseif($typeDef['typeClass'] == 'element') {
1123                $str .= "></$type>";
1124            } else {
1125                $str .= "/>";
1126            }
1127                        return $str;
1128        }
1129        return false;
1130    }
1131
1132    /**
1133    * returns HTML form elements that allow a user
1134    * to enter values for creating an instance of the given type.
1135    *
1136    * @param string $name, name for type instance
1137    * @param string $type, name of type
1138    * @return string
1139    * @access public
1140        */
1141        function typeToForm($name,$type){
1142                // get typedef
1143                if($typeDef = $this->getTypeDef($type)){
1144                        // if struct
1145                        if($typeDef['phpType'] == 'struct'){
1146                                $buffer .= '<table>';
1147                                foreach($typeDef['elements'] as $child => $childDef){
1148                                        $buffer .= "
1149                                        <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1150                                        <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1151                                }
1152                                $buffer .= '</table>';
1153                        // if array
1154                        } elseif($typeDef['phpType'] == 'array'){
1155                                $buffer .= '<table>';
1156                                for($i=0;$i < 3; $i++){
1157                                        $buffer .= "
1158                                        <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1159                                        <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1160                                }
1161                                $buffer .= '</table>';
1162                        // if scalar
1163                        } else {
1164                                $buffer .= "<input type='text' name='parameters[$name]'>";
1165                        }
1166                } else {
1167                        $buffer .= "<input type='text' name='parameters[$name]'>";
1168                }
1169                return $buffer;
1170        }
1171       
1172        /**
1173        * adds an XML Schema complex type to the WSDL types
1174        *
1175        * example: array
1176        *
1177        * addType(
1178        *       'ArrayOfstring',
1179        *       'complexType',
1180        *       'array',
1181        *       '',
1182        *       'SOAP-ENC:Array',
1183        *       array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
1184        *       'xsd:string'
1185        * );
1186        *
1187        * example: PHP associative array ( SOAP Struct )
1188        *
1189        * addType(
1190        *       'SOAPStruct',
1191        *       'complexType',
1192        *       'struct',
1193        *       'all',
1194        *       array('myVar'=> array('name'=>'myVar','type'=>'string')
1195        * );
1196        *
1197        * @param name
1198        * @param typeClass (complexType|simpleType|attribute)
1199        * @param phpType: currently supported are array and struct (php assoc array)
1200        * @param compositor (all|sequence|choice)
1201        * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1202        * @param elements = array ( name = array(name=>'',type=>'') )
1203        * @param attrs = array(
1204        *       array(
1205        *               'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
1206        *               "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
1207        *       )
1208        * )
1209        * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
1210        *
1211        */
1212        function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1213                $this->complexTypes[$name] = array(
1214            'name'              => $name,
1215            'typeClass' => $typeClass,
1216            'phpType'   => $phpType,
1217                'compositor'=> $compositor,
1218            'restrictionBase' => $restrictionBase,
1219                'elements'      => $elements,
1220            'attrs'             => $attrs,
1221            'arrayType' => $arrayType
1222                );
1223        }
1224}
1225
1226
1227
1228?><?php
1229
1230
1231
1232/**
1233* for creating serializable abstractions of native PHP types
1234* NOTE: this is only really used when WSDL is not available.
1235*
1236* @author   Dietrich Ayala <dietrich@ganx4.com>
1237* @version  v 0.6.3
1238* @access   public
1239*/
1240class soapval extends nusoap_base {
1241        /**
1242        * constructor
1243        *
1244        * @param    string $name optional name
1245        * @param    string $type optional type name
1246        * @param        mixed $value optional value
1247        * @param        string $namespace optional namespace of value
1248        * @param        string $type_namespace optional namespace of type
1249        * @param        array $attributes associative array of attributes to add to element serialization
1250        * @access   public
1251        */
1252        function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
1253                $this->name = $name;
1254                $this->value = $value;
1255                $this->type = $type;
1256                $this->element_ns = $element_ns;
1257                $this->type_ns = $type_ns;
1258                $this->attributes = $attributes;
1259    }
1260
1261        /**
1262        * return serialized value
1263        *
1264        * @return       string XML data
1265        * @access   private
1266        */
1267        function serialize($use='encoded') {
1268                return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
1269    }
1270
1271        /**
1272        * decodes a soapval object into a PHP native type
1273        *
1274        * @param        object $soapval optional SOAPx4 soapval object, else uses self
1275        * @return       mixed
1276        * @access   public
1277        */
1278        function decode(){
1279                return $this->value;
1280        }
1281}
1282
1283
1284
1285?><?php
1286
1287
1288
1289/**
1290* transport class for sending/receiving data via HTTP and HTTPS
1291* NOTE: PHP must be compiled with the CURL extension for HTTPS support
1292*
1293* @author   Dietrich Ayala <dietrich@ganx4.com>
1294* @version  v 0.6.3
1295* @access public
1296*/
1297class soap_transport_http extends nusoap_base {
1298
1299        var $username = '';
1300        var $password = '';
1301        var $url = '';
1302    var $proxyhost = '';
1303    var $proxyport = '';
1304        var $scheme = '';
1305        var $request_method = 'POST';
1306        var $protocol_version = '1.0';
1307        var $encoding = '';
1308        var $outgoing_headers = array();
1309        var $incoming_headers = array();
1310        var $outgoing_payload = '';
1311        var $incoming_payload = '';
1312        var $useSOAPAction = true;
1313       
1314        /**
1315        * constructor
1316        */
1317        function soap_transport_http($url){
1318                $this->url = $url;
1319                $u = parse_url($url);
1320                foreach($u as $k => $v){
1321                        $this->debug("$k = $v");
1322                        $this->$k = $v;
1323                }
1324                if(isset($u['query']) && $u['query'] != ''){
1325            $this->path .= '?' . $u['query'];
1326                }
1327                if(!isset($u['port']) && $u['scheme'] == 'http'){
1328                        $this->port = 80;
1329                }
1330        }
1331       
1332        function connect($timeout){
1333               
1334                // proxy
1335                if($this->proxyhost != '' && $this->proxyport != ''){
1336                        $host = $this->proxyhost;
1337                        $port = $this->proxyport;
1338                        $this->debug("using http proxy: $host, $port");
1339                } else {
1340                        $host = $this->host;
1341                        $port = $this->port;
1342                }
1343                // ssl
1344                if($this->scheme == 'https'){
1345                        $host = 'ssl://'.$host;
1346                        $port = 443;
1347                }
1348               
1349                $this->debug("connection params: $host, $port");
1350                // timeout
1351                if($timeout > 0){
1352                        $fp = fsockopen($host, $port, $this->errno, $this->error_str, $timeout);
1353                } else {
1354                        $fp = fsockopen($host, $port, $this->errno, $this->error_str);
1355                }
1356               
1357                // test pointer
1358                if(!$fp) {
1359                        $this->debug('Couldn\'t open socket connection to server '.$this->url.', Error: '.$this->error_str);
1360                        $this->setError('Couldn\'t open socket connection to server: '.$this->url.', Error: '.$this->error_str);
1361                        return false;
1362                }
1363                return $fp;
1364        }
1365       
1366        /**
1367        * send the SOAP message via HTTP
1368        *
1369        * @param    string $data message data
1370        * @param    integer $timeout set timeout in seconds
1371        * @return       string data
1372        * @access   public
1373        */
1374        function send($data, $timeout=0) {
1375                $this->debug('entered send() with data of length: '.strlen($data));
1376                // get connnection
1377                if(!$fp = $this->connect($timeout)){
1378                        return false;
1379                }
1380                $this->debug('socket connected');
1381               
1382                // start building outgoing payload:
1383                // swap url for path if going through a proxy
1384                if($this->proxyhost != '' && $this->proxyport != ''){
1385                        $this->outgoing_payload = "$this->request_method $this->url ".strtoupper($this->scheme)."/$this->protocol_version\r\n";
1386                } else {
1387                        $this->outgoing_payload = "$this->request_method $this->path ".strtoupper($this->scheme)."/$this->protocol_version\r\n";
1388                }
1389                // make payload
1390                $this->outgoing_payload .=
1391                        "User-Agent: $this->title/$this->version\r\n".
1392                        "Host: ".$this->host."\r\n";
1393                // http auth
1394                $credentials = '';
1395                if($this->username != '') {
1396                        $this->debug('setting http auth credentials');
1397                        $this->outgoing_payload .= 'Authorization: Basic '.base64_encode("$this->username:$this->password")."\r\n";
1398                }
1399                // set content type
1400                $this->outgoing_payload .= 'Content-Type: text/xml; charset='.$this->soap_defencoding."\r\nContent-Length: ".strlen($data)."\r\n";
1401                // http encoding
1402                if($this->encoding != '' && function_exists('gzdeflate')){
1403                        $this->outgoing_payload .= "Accept-Encoding: $this->encoding\r\n".
1404                        "Connection: close\r\n";
1405                        set_magic_quotes_runtime(0);
1406                }
1407                // set soapaction
1408                if($this->useSOAPAction){
1409                        $this->outgoing_payload .= "SOAPAction: \"$this->soapaction\""."\r\n";
1410                }
1411                $this->outgoing_payload .= "\r\n";
1412                // add data
1413                $this->outgoing_payload .= $data;
1414               
1415                // send payload
1416                if(!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
1417                        $this->setError('couldn\'t write message data to socket');
1418                        $this->debug('Write error');
1419                }
1420                $this->debug('wrote data to socket');
1421               
1422                // get response
1423            $this->incoming_payload = '';
1424                //$strlen = 0;
1425                while( $data = fread($fp, 32768) ){
1426                        $this->incoming_payload .= $data;
1427                        //$strlen += strlen($data);
1428            }
1429                $this->debug('received '.strlen($this->incoming_payload).' bytes of data from server');
1430               
1431                // close filepointer
1432                fclose($fp);
1433                $this->debug('closed socket');
1434               
1435                // connection was closed unexpectedly
1436                if($this->incoming_payload == ''){
1437                        $this->setError('no response from server');
1438                        return false;
1439                }
1440               
1441                $this->debug('received incoming payload: '.strlen($this->incoming_payload));
1442                $data = $this->incoming_payload."\r\n\r\n\r\n\r\n";
1443               
1444                // remove 100 header
1445                if(ereg('^HTTP/1.1 100',$data)){
1446                        if($pos = strpos($data,"\r\n\r\n") ){
1447                                $data = ltrim(substr($data,$pos));
1448                        } elseif($pos = strpos($data,"\n\n") ){
1449                                $data = ltrim(substr($data,$pos));
1450                        }
1451                }//
1452               
1453                // separate content from HTTP headers
1454                if( $pos = strpos($data,"\r\n\r\n") ){
1455                        $lb = "\r\n";
1456                } elseif( $pos = strpos($data,"\n\n") ){
1457                        $lb = "\n";
1458                } else {
1459                        $this->setError('no proper separation of headers and document');
1460                        return false;
1461                }
1462                $header_data = trim(substr($data,0,$pos));
1463                $header_array = explode($lb,$header_data);
1464                $data = ltrim(substr($data,$pos));
1465                $this->debug('found proper separation of headers and document');
1466                $this->debug('cleaned data, stringlen: '.strlen($data));
1467                // clean headers
1468                foreach($header_array as $header_line){
1469                        $arr = explode(':',$header_line);
1470                        if(count($arr) >= 2){
1471                                $headers[trim($arr[0])] = trim($arr[1]);
1472                        }
1473                }
1474                //print "headers: <pre>$header_data</pre><br>";
1475                //print "data: <pre>$data</pre><br>";
1476               
1477                // decode transfer-encoding
1478                if(isset($headers['Transfer-Encoding']) && $headers['Transfer-Encoding'] == 'chunked'){
1479                        //$timer->setMarker('starting to decode chunked content');
1480                        if(!$data = $this->decodeChunked($data)){
1481                                $this->setError('Decoding of chunked data failed');
1482                                return false;
1483                        }
1484                        //$timer->setMarker('finished decoding of chunked content');
1485                        //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
1486                }
1487               
1488                // decode content-encoding
1489                if(isset($headers['Content-Encoding']) && $headers['Content-Encoding'] != ''){
1490                        if($headers['Content-Encoding'] == 'deflate' || $headers['Content-Encoding'] == 'gzip'){
1491                        // if decoding works, use it. else assume data wasn't gzencoded
1492                        if(function_exists('gzinflate')){
1493                                        //$timer->setMarker('starting decoding of gzip/deflated content');
1494                                        if($headers['Content-Encoding'] == 'deflate' && $degzdata = @gzinflate($data)){
1495                                        $data = $degzdata;
1496                                        } elseif($headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){
1497                                                $data = $degzdata;
1498                                        } else {
1499                                                $this->setError('Errors occurred when trying to decode the data');
1500                                        }
1501                                        //$timer->setMarker('finished decoding of gzip/deflated content');
1502                                        //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
1503                        } else {
1504                                        $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
1505                                }
1506                        }
1507                }
1508               
1509                if(strlen($data) == 0){
1510                        $this->debug('no data after headers!');
1511                        $this->setError('no data present after HTTP headers');
1512                        return false;
1513                }
1514                $this->debug('end of send()');
1515                return $data;
1516        }
1517
1518
1519        /**
1520        * send the SOAP message via HTTPS 1.0 using CURL
1521        *
1522        * @param    string $msg message data
1523        * @param    integer $timeout set timeout in seconds
1524        * @return       string data
1525        * @access   public
1526        */
1527        function sendHTTPS($data, $timeout=0) {
1528                //global $t;
1529                //$t->setMarker('inside sendHTTPS()');
1530                $this->debug('entered sendHTTPS() with data of length: '.strlen($data));
1531                // init CURL
1532                $ch = curl_init();
1533                //$t->setMarker('got curl handle');
1534                // set proxy
1535                if($this->proxyhost && $this->proxyport){
1536                        $host = $this->proxyhost;
1537                        $port = $this->proxyport;
1538                } else {
1539                        $host = $this->host;
1540                        $port = $this->port;
1541                }
1542                // set url
1543                $hostURL = ($port != '') ? "https://$host:$port" : "https://$host";
1544                // add path
1545                $hostURL .= $this->path;
1546                curl_setopt($ch, CURLOPT_URL, $hostURL);
1547                // set other options
1548                curl_setopt($ch, CURLOPT_HEADER, 1);
1549                curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
1550                // encode
1551                if(function_exists('gzinflate')){
1552                        curl_setopt($ch, CURLOPT_ENCODING, 'deflate');
1553                }
1554                // persistent connection
1555                //curl_setopt($ch, CURL_HTTP_VERSION_1_1, true);
1556               
1557                // set timeout
1558                if($timeout != 0){
1559                        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1560                }
1561               
1562                $credentials = '';
1563                if($this->username != '') {
1564                        $credentials = 'Authorization: Basic '.base64_encode("$this->username:$this->password").'\r\n';
1565                }
1566               
1567                if($this->encoding != ''){
1568                        if(function_exists('gzdeflate')){
1569                                $encoding_headers = "Accept-Encoding: $this->encoding\r\n".
1570                                "Connection: close\r\n";
1571                                set_magic_quotes_runtime(0);
1572                        }
1573                }
1574               
1575                if($this->proxyhost && $this->proxyport){
1576                        $this->outgoing_payload = "POST $this->url HTTP/$this->protocol_version\r\n";
1577                } else {
1578                        $this->outgoing_payload = "POST $this->path HTTP/$this->protocol_version\r\n";
1579                }
1580               
1581                $this->outgoing_payload .=
1582                        "User-Agent: $this->title v$this->version\r\n".
1583                        "Host: ".$this->host."\r\n".
1584                        $encoding_headers.
1585                        $credentials.
1586                        "Content-Type: text/xml; charset=\"$this->soap_defencoding\"\r\n".
1587                        "Content-Length: ".strlen($data)."\r\n".
1588                        "SOAPAction: \"$this->soapaction\""."\r\n\r\n".
1589                        $data;
1590
1591                // set payload
1592                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
1593                //$t->setMarker('set curl options, executing...');
1594                // send and receive
1595                $this->incoming_payload = curl_exec($ch);
1596                //$t->setMarker('executed transfer');
1597                $data = $this->incoming_payload;
1598
1599        $cErr = curl_error($ch);
1600
1601                if($cErr != ''){
1602                $err = 'cURL ERROR: '.curl_errno($ch).': '.$cErr.'<br>';
1603                        foreach(curl_getinfo($ch) as $k => $v){
1604                                $err .= "$k: $v<br>";
1605                        }
1606                        $this->setError($err);
1607                        curl_close($ch);
1608                return false;
1609                } else {
1610                        //echo '<pre>';
1611                        //var_dump(curl_getinfo($ch));
1612                        //echo '</pre>';
1613                }
1614                // close curl
1615                curl_close($ch);
1616                //$t->setMarker('closed curl');
1617               
1618                // remove 100 header
1619                if(ereg('^HTTP/1.1 100',$data)){
1620                        if($pos = strpos($data,"\r\n\r\n") ){
1621                                $data = ltrim(substr($data,$pos));
1622                        } elseif($pos = strpos($data,"\n\n") ){
1623                                $data = ltrim(substr($data,$pos));
1624                        }
1625                }//
1626               
1627                // separate content from HTTP headers
1628                if( $pos = strpos($data,"\r\n\r\n") ){
1629                        $lb = "\r\n";
1630                } elseif( $pos = strpos($data,"\n\n") ){
1631                        $lb = "\n";
1632                } else {
1633                        $this->setError('no proper separation of headers and document');
1634                        return false;
1635                }
1636                $header_data = trim(substr($data,0,$pos));
1637                $header_array = explode($lb,$header_data);
1638                $data = ltrim(substr($data,$pos));
1639                $this->debug('found proper separation of headers and document');
1640                $this->debug('cleaned data, stringlen: '.strlen($data));
1641                // clean headers
1642                foreach($header_array as $header_line){
1643                        $arr = explode(':',$header_line);
1644                        $headers[trim($arr[0])] = trim($arr[1]);
1645                }
1646                if(strlen($data) == 0){
1647                        $this->debug('no data after headers!');
1648                        $this->setError('no data present after HTTP headers.');
1649                        return false;
1650                }
1651               
1652                // decode transfer-encoding
1653                if($headers['Transfer-Encoding'] == 'chunked'){
1654                        if(!$data = $this->decodeChunked($data)){
1655                                $this->setError('Decoding of chunked data failed');
1656                                return false;
1657                        }
1658                }
1659                // decode content-encoding
1660                if($headers['Content-Encoding'] != ''){
1661                        if($headers['Content-Encoding'] == 'deflate' || $headers['Content-Encoding'] == 'gzip'){
1662                        // if decoding works, use it. else assume data wasn't gzencoded
1663                        if(function_exists('gzinflate')){
1664                                        if($headers['Content-Encoding'] == 'deflate' && $degzdata = @gzinflate($data)){
1665                                        $data = $degzdata;
1666                                        } elseif($headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){
1667                                                $data = $degzdata;
1668                                        } else {
1669                                                $this->setError('Errors occurred when trying to decode the data');
1670                                        }
1671                        } else {
1672                                        $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
1673                                }
1674                        }
1675                }
1676                // set decoded payload
1677                $this->incoming_payload = $header_data."\r\n\r\n".$data;
1678                return $data;
1679        }
1680       
1681        /**
1682        * if authenticating, set user credentials here
1683        *
1684        * @param    string $user
1685        * @param    string $pass
1686        * @access   public
1687        */
1688        function setCredentials($username, $password) {
1689                $this->username = $username;
1690                $this->password = $password;
1691        }
1692       
1693        /**
1694        * set the soapaction value
1695        *
1696        * @param    string $soapaction
1697        * @access   public
1698        */
1699        function setSOAPAction($soapaction) {
1700                $this->soapaction = $soapaction;
1701        }
1702       
1703        /**
1704        * use http encoding
1705        *
1706        * @param    string $enc encoding style. supported values: gzip, deflate, or both
1707        * @access   public
1708        */
1709        function setEncoding($enc='gzip, deflate'){
1710                $this->encoding = $enc;
1711                $this->protocol_version = '1.1';
1712        }
1713       
1714        /**
1715        * set proxy info here
1716        *
1717        * @param    string $proxyhost
1718        * @param    string $proxyport
1719        * @access   public
1720        */
1721        function setProxy($proxyhost, $proxyport) {
1722                $this->proxyhost = $proxyhost;
1723                $this->proxyport = $proxyport;
1724        }
1725       
1726        /**
1727        * decode a string that is encoded w/ "chunked' transfer encoding
1728        * as defined in RFC2068 19.4.6
1729        *
1730        * @param    string $buffer
1731        * @returns      string
1732        * @access   public
1733        */
1734        function decodeChunked($buffer){
1735                // length := 0
1736                $length = 0;
1737                $new = '';
1738               
1739                // read chunk-size, chunk-extension (if any) and CRLF
1740                // get the position of the linebreak
1741                $chunkend = strpos($buffer,"\r\n") + 2;
1742                $temp = substr($buffer,0,$chunkend);
1743                $chunk_size = hexdec( trim($temp) );
1744                $chunkstart = $chunkend;
1745                // while (chunk-size > 0) {
1746                while ($chunk_size > 0) {
1747                       
1748                        $chunkend = strpos( $buffer, "\r\n", $chunkstart + $chunk_size);
1749                       
1750                        // Just in case we got a broken connection
1751                        if ($chunkend == FALSE) {
1752                            $chunk = substr($buffer,$chunkstart);
1753                                // append chunk-data to entity-body
1754                        $new .= $chunk;
1755                            $length += strlen($chunk);
1756                            break;
1757                        }
1758                       
1759                        // read chunk-data and CRLF
1760                        $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
1761                        // append chunk-data to entity-body
1762                        $new .= $chunk;
1763                        // length := length + chunk-size
1764                        $length += strlen($chunk);
1765                        // read chunk-size and CRLF
1766                        $chunkstart = $chunkend + 2;
1767                       
1768                        $chunkend = strpos($buffer,"\r\n",$chunkstart)+2;
1769                        if ($chunkend == FALSE) {
1770                                break; //Just in case we got a broken connection
1771                        }
1772                        $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
1773                        $chunk_size = hexdec( trim($temp) );
1774                        $chunkstart = $chunkend;
1775                }
1776        // Update headers
1777        //$this->Header['content-length'] = $length;
1778        //unset($this->Header['transfer-encoding']);
1779                return $new;
1780        }
1781       
1782}
1783
1784
1785
1786?><?php
1787
1788
1789
1790/**
1791*
1792* soap_server allows the user to create a SOAP server
1793* that is capable of receiving messages and returning responses
1794*
1795* NOTE: WSDL functionality is experimental
1796*
1797* @author   Dietrich Ayala <dietrich@ganx4.com>
1798* @version  v 0.6.3
1799* @access   public
1800*/
1801class soap_server extends nusoap_base {
1802
1803        var $service = ''; // service name
1804    var $operations = array(); // assoc array of operations => opData
1805    var $responseHeaders = false;
1806        var $headers = '';
1807        var $request = '';
1808        var $charset_encoding = 'UTF-8';
1809        var $fault = false;
1810        var $result = 'successful';
1811        var $wsdl = false;
1812        var $externalWSDLURL = false;
1813    var $debug_flag = true;
1814       
1815        /**
1816        * constructor
1817    * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
1818        *
1819    * @param string $wsdl path or URL to a WSDL file
1820        * @access   public
1821        */
1822        function soap_server($wsdl=false){
1823
1824                // turn on debugging?
1825                global $debug;
1826                if(isset($debug)){
1827                        $this->debug_flag = 1;
1828                }
1829
1830                // wsdl
1831                if($wsdl){
1832                        $this->wsdl = new wsdl($wsdl);
1833                        $this->externalWSDLURL = $wsdl;
1834                        if($err = $this->wsdl->getError()){
1835                                die('WSDL ERROR: '.$err);
1836                        }
1837                }
1838        }
1839
1840        /**
1841        * processes request and returns response
1842        *
1843        * @param    string $data usually is the value of $HTTP_RAW_POST_DATA
1844        * @access   public
1845        */
1846        function service($data){
1847                // print wsdl
1848                global $QUERY_STRING;
1849                if(isset($_SERVER['QUERY_STRING'])){
1850                        $qs = $_SERVER['QUERY_STRING'];
1851                } elseif(isset($GLOBALS['QUERY_STRING'])){
1852                        $qs = $GLOBALS['QUERY_STRING'];
1853                } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
1854                        $qs = $QUERY_STRING;
1855                }
1856                // gen wsdl
1857                if(isset($qs) && ereg('wsdl', $qs) ){
1858                        if($this->externalWSDLURL){
1859                                header('Location: '.$this->externalWSDLURL);
1860                                exit();
1861                        } else {
1862                                header("Content-Type: text/xml\r\n");
1863                                print $this->wsdl->serialize();
1864                                exit();
1865                        }
1866                }
1867               
1868                // print web interface
1869                if($data == '' && $this->wsdl){
1870                        print $this->webDescription();
1871                } else {
1872                       
1873                        // $response is the serialized response message
1874                        $response = $this->parse_request($data);
1875                        $this->debug('server sending...');
1876                        $payload = $response;
1877            // add debug data if in debug mode
1878                        if(isset($this->debug_flag) && $this->debug_flag == 1){
1879                $payload .= "<!--\n".str_replace('--','- -',$this->debug_str)."\n-->";
1880            }
1881                        // print headers
1882                        if($this->fault){
1883                                $header[] = "HTTP/1.0 500 Internal Server Error\r\n";
1884                                $header[] = "Status: 500 Internal Server Error\r\n";
1885                        } else {
1886                                $header[] = "Status: 200 OK\r\n";
1887                        }
1888                        $header[] = "Server: $this->title Server v$this->version\r\n";
1889                        $header[] = "Connection: Close\r\n";
1890                        $header[] = "Content-Type: text/xml; charset=$this->charset_encoding\r\n";
1891                        $header[] = "Content-Length: ".strlen($payload)."\r\n\r\n";
1892                        reset($header);
1893                        foreach($header as $hdr){
1894                                header($hdr);
1895                        }
1896                        $this->response = join("\r\n",$header).$payload;
1897                        print $payload;
1898                }
1899        }
1900
1901        /**
1902        * parses request and posts response
1903        *
1904        * @param    string $data XML string
1905        * @return       string XML response msg
1906        * @access   private
1907        */
1908        function parse_request($data='') {
1909                $this->debug('entering parseRequest() on '.date('H:i Y-m-d'));
1910        $dump = '';
1911                // get headers
1912                if(function_exists('getallheaders')){
1913                        $this->headers = getallheaders();
1914                        foreach($this->headers as $k=>$v){
1915                                $dump .= "$k: $v\r\n";
1916                                $this->debug("$k: $v");
1917                        }
1918                        // get SOAPAction header
1919                        if(isset($this->headers['SOAPAction'])){
1920                                $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']);
1921                        }
1922                        // get the character encoding of the incoming request
1923                        if(strpos($this->headers['Content-Type'],'=')){
1924                                $enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1));
1925                                if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
1926                                        $this->xml_encoding = $enc;
1927                                } else {
1928                                        $this->xml_encoding = 'us-ascii';
1929                                }
1930                        }
1931                        $this->debug('got encoding: '.$this->charset_encoding);
1932                } elseif(is_array($_SERVER)){
1933                        $this->headers['User-Agent'] = $_SERVER['HTTP_USER_AGENT'];
1934                        $this->SOAPAction = isset($_SERVER['SOAPAction']) ? $_SERVER['SOAPAction'] : '';
1935                }
1936                $this->request = $dump."\r\n\r\n".$data;
1937                // parse response, get soap parser obj
1938                $parser = new soap_parser($data,$this->charset_encoding);
1939                // if fault occurred during message parsing
1940                if($err = $parser->getError()){
1941                        // parser debug
1942                        $this->debug("parser debug: \n".$parser->debug_str);
1943                        $this->result = 'fault: error in msg parsing: '.$err;
1944                        $this->fault('Server',"error in msg parsing:\n".$err);
1945                        // return soapresp
1946                        return $this->fault->serialize();
1947                // else successfully parsed request into soapval object
1948                } else {
1949                        // get/set methodname
1950                        $this->methodname = $parser->root_struct_name;
1951                        $this->debug('method name: '.$this->methodname);
1952                        // does method exist?
1953                        if(!function_exists($this->methodname)){
1954                                // "method not found" fault here
1955                                $this->debug("method '$this->methodname' not found!");
1956                                $this->debug("parser debug: \n".$parser->debug_str);
1957                                $this->result = 'fault: method not found';
1958                                $this->fault('Server',"method '$this->methodname' not defined in service '$this->service'");
1959                                return $this->fault->serialize();
1960                        }
1961                        if($this->wsdl){
1962                                if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){
1963                                //if(
1964                                $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service");
1965                                        return $this->fault->serialize();
1966                            }
1967                        }
1968                        $this->debug("method '$this->methodname' exists");
1969                        // evaluate message, getting back parameters
1970                        $this->debug('calling parser->get_response()');
1971                        $request_data = $parser->get_response();
1972                        // parser debug
1973                        $this->debug("parser debug: \n".$parser->debug_str);
1974                        // verify that request parameters match the method's signature
1975                        if($this->verify_method($this->methodname,$request_data)){
1976                                // if there are parameters to pass
1977                    $this->debug('params var dump '.$this->varDump($request_data));
1978                                if($request_data){
1979                                        $this->debug("calling '$this->methodname' with params");
1980                                        if (! function_exists('call_user_func_array')) {
1981                                                $this->debug('calling method using eval()');
1982                                                $funcCall = $this->methodname.'(';
1983                                                foreach($request_data as $param) {
1984                                                        $funcCall .= "\"$param\",";
1985                                                }
1986                                                $funcCall = substr($funcCall, 0, -1).')';
1987                                                $this->debug('function call:<br>'.$funcCall);
1988                                                @eval("\$method_response = $funcCall;");
1989                                        } else {
1990                                                $this->debug('calling method using call_user_func_array()');
1991                                                $method_response = call_user_func_array("$this->methodname",$request_data);
1992                                        }
1993                        $this->debug('response var dump'.$this->varDump($method_response));
1994                                } else {
1995                                        // call method w/ no parameters
1996                                        $this->debug("calling $this->methodname w/ no params");
1997                                        $m = $this->methodname;
1998                                        $method_response = @$m();
1999                                }
2000                                $this->debug("done calling method: $this->methodname, received $method_response of type".gettype($method_response));
2001                                // if we got nothing back. this might be ok (echoVoid)
2002                                if(isset($method_response) && $method_response != '' || is_bool($method_response)) {
2003                                        // if fault
2004                                        if(get_class($method_response) == 'soap_fault'){
2005                                                $this->debug('got a fault object from method');
2006                                                $this->fault = $method_response;
2007                                                return $method_response->serialize();
2008                                        // if return val is soapval object
2009                                        } elseif(get_class($method_response) == 'soapval'){
2010                                                $this->debug('got a soapval object from method');
2011                                                $return_val = $method_response->serialize();
2012                                        // returned other
2013                                        } else {
2014                                                $this->debug('got a(n) '.gettype($method_response).' from method');
2015                                                $this->debug('serializing return value');
2016                                                if($this->wsdl){
2017                                                        // weak attempt at supporting multiple output params
2018                                                        if(sizeof($this->opData['output']['parts']) > 1){
2019                                                        $opParams = $method_response;
2020                                                    } else {
2021                                                        $opParams = array($method_response);
2022                                                    }
2023                                                    $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
2024                                                } else {
2025                                                    $return_val = $this->serialize_val($method_response);
2026                                                }
2027                                        }
2028                                        $this->debug('return val:'.$this->varDump($return_val));
2029                                } else {
2030                                        $return_val = '';
2031                                        $this->debug('got no response from method');
2032                                }
2033                                $this->debug('serializing response');
2034                                $payload = '<'.$this->methodname."Response>".$return_val.'</'.$this->methodname."Response>";
2035                                $this->result = 'successful';
2036                                if($this->wsdl){
2037                                        //if($this->debug_flag){
2038                                $this->debug("WSDL debug data:\n".$this->wsdl->debug_str);
2039                        //      }
2040                                        // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
2041                                        return $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style']);
2042                                } else {
2043                                        return $this->serializeEnvelope($payload,$this->responseHeaders);
2044                                }
2045                        } else {
2046                                // debug
2047                                $this->debug('ERROR: request not verified against method signature');
2048                                $this->result = 'fault: request failed validation against method signature';
2049                                // return fault
2050                                $this->fault('Server',"Operation '$this->methodname' not defined in service.");
2051                                return $this->fault->serialize();
2052                        }
2053                }
2054        }
2055
2056        /**
2057        * takes the value that was created by parsing the request
2058        * and compares to the method's signature, if available.
2059        *
2060        * @param        mixed
2061        * @return       boolean
2062        * @access   private
2063        */
2064        function verify_method($operation,$request){
2065                if(isset($this->wsdl) && is_object($this->wsdl)){
2066                        if($this->wsdl->getOperationData($operation)){
2067                                return true;
2068                        }
2069            } elseif(isset($this->operations[$operation])){
2070                        return true;
2071                }
2072                return false;
2073        }
2074
2075        /**
2076        * add a method to the dispatch map
2077        *
2078        * @param    string $methodname
2079        * @param    string $in array of input values
2080        * @param    string $out array of output values
2081        * @access   public
2082        */
2083        function add_to_map($methodname,$in,$out){
2084                        $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
2085        }
2086
2087        /**
2088        * register a service with the server
2089        *
2090        * @param    string $methodname
2091        * @param    string $in assoc array of input values: key = param name, value = param type
2092        * @param    string $out assoc array of output values: key = param name, value = param type
2093        * @param        string $namespace
2094        * @param        string $soapaction
2095        * @param        string $style (rpc|literal)
2096        * @access   public
2097        */
2098        function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false){
2099                if($this->externalWSDLURL){
2100                        die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
2101                }
2102            if(false == $in) {
2103                }
2104                if(false == $out) {
2105                }
2106                if(false == $namespace) {
2107                }
2108                if(false == $soapaction) {
2109                        global $SERVER_NAME, $SCRIPT_NAME;
2110                        $soapaction = "http://$SERVER_NAME$SCRIPT_NAME";
2111                }
2112                if(false == $style) {
2113                        $style = "rpc";
2114                }
2115                if(false == $use) {
2116                        $use = "encoded";
2117                }
2118               
2119                $this->operations[$name] = array(
2120            'name' => $name,
2121            'in' => $in,
2122            'out' => $out,
2123            'namespace' => $namespace,
2124            'soapaction' => $soapaction,
2125            'style' => $style);
2126        if($this->wsdl){
2127                $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use);
2128            }
2129                return true;
2130        }
2131
2132        /**
2133        * create a fault. this also acts as a flag to the server that a fault has occured.
2134        *
2135        * @param        string faultcode
2136        * @param        string faultactor
2137        * @param        string faultstring
2138        * @param        string faultdetail
2139        * @access   public
2140        */
2141        function fault($faultcode,$faultactor,$faultstring='',$faultdetail=''){
2142                $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
2143        }
2144
2145    /**
2146    * prints html description of services
2147    *
2148    * @access private
2149    */
2150    function webDescription(){
2151                $b = '
2152                <html><head><title>NuSOAP: '.$this->wsdl->serviceName.'</title>
2153                <style type="text/css">
2154                    body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
2155                    p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
2156                    pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
2157                    ul      { margin-top: 10px; margin-left: 20px; }
2158                    li      { list-style-type: none; margin-top: 10px; color: #000000; }
2159                    .content{
2160                        margin-left: 0px; padding-bottom: 2em; }
2161                    .nav {
2162                        padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
2163                        margin-top: 10px; margin-left: 0px; color: #000000;
2164                        background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
2165                    .title {
2166                        font-family: arial; font-size: 26px; color: #ffffff;
2167                        background-color: #999999; width: 105%; margin-left: 0px;
2168                        padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
2169                    .hidden {
2170                        position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
2171                        font-family: arial; overflow: hidden; width: 600;
2172                        padding: 20px; font-size: 10px; background-color: #999999;
2173                        layer-background-color:#FFFFFF; }
2174                    a,a:active  { color: charcoal; font-weight: bold; }
2175                    a:visited   { color: #666666; font-weight: bold; }
2176                    a:hover     { color: cc3300; font-weight: bold; }
2177                </style>
2178                <script language="JavaScript" type="text/javascript">
2179                <!--
2180                // POP-UP CAPTIONS...
2181                function lib_bwcheck(){ //Browsercheck (needed)
2182                    this.ver=navigator.appVersion
2183                    this.agent=navigator.userAgent
2184                    this.dom=document.getElementById?1:0
2185                    this.opera5=this.agent.indexOf("Opera 5")>-1
2186                    this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
2187                    this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
2188                    this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
2189                    this.ie=this.ie4||this.ie5||this.ie6
2190                    this.mac=this.agent.indexOf("Mac")>-1
2191                    this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
2192                    this.ns4=(document.layers && !this.dom)?1:0;
2193                    this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
2194                    return this
2195                }
2196                var bw = new lib_bwcheck()
2197                //Makes crossbrowser object.
2198                function makeObj(obj){
2199                    this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
2200                    if(!this.evnt) return false
2201                    this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
2202                    this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
2203                    this.writeIt=b_writeIt;
2204                    return this
2205                }
2206                // A unit of measure that will be added when setting the position of a layer.
2207                //var px = bw.ns4||window.opera?"":"px";
2208                function b_writeIt(text){
2209                    if (bw.ns4){this.wref.write(text);this.wref.close()}
2210                    else this.wref.innerHTML = text
2211                }
2212                //Shows the messages
2213                var oDesc;
2214                function popup(divid){
2215                    if(oDesc = new makeObj(divid)){
2216                        oDesc.css.visibility = "visible"
2217                    }
2218                }
2219                function popout(){ // Hides message
2220                    if(oDesc) oDesc.css.visibility = "hidden"
2221                }
2222                //-->
2223                </script>
2224                </head>
2225                <body>
2226                <div class=content>
2227                        <br><br>
2228                        <div class=title>'.$this->wsdl->serviceName.'</div>
2229                        <div class=nav>
2230                                <p>View the <a href="'.$GLOBALS['PHP_SELF'].'?wsdl">WSDL</a> for the service.
2231                                Click on an operation name to view it&apos;s details.</p>
2232                                <ul>';
2233                                foreach($this->wsdl->getOperations() as $op => $data){
2234                                    $b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>";
2235                                    // create hidden div
2236                                    $b .= "<div id='$op' class='hidden'>
2237                                    <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
2238                                    foreach($data as $donnie => $marie){ // loop through opdata
2239                                                if($donnie == 'input' || $donnie == 'output'){ // show input/output data
2240                                                    $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
2241                                                    foreach($marie as $captain => $tenille){ // loop through data
2242                                                                if($captain == 'parts'){ // loop thru parts
2243                                                                    $b .= "&nbsp;&nbsp;$captain:<br>";
2244                                                        //if(is_array($tenille)){
2245                                                                        foreach($tenille as $joanie => $chachi){
2246                                                                                        $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
2247                                                                        }
2248                                                                //}
2249                                                                } else {
2250                                                                    $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
2251                                                                }
2252                                                    }
2253                                                } else {
2254                                                    $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
2255                                                }
2256                                    }
2257                                        $b .= '</div>';
2258                                }
2259                                $b .= '
2260                                <ul>
2261                        </div>
2262                </div></body></html>';
2263                return $b;
2264    }
2265
2266    /**
2267    * sets up wsdl object
2268    * this acts as a flag to enable internal WSDL generation
2269    * NOTE: NOT FUNCTIONAL
2270    *
2271    * @param string $serviceName, name of the service
2272    * @param string $namespace, tns namespace
2273    */
2274    function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http')
2275    {
2276                $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
2277                $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
2278        if(false == $namespace) {
2279            $namespace = "http://$SERVER_NAME/soap/$serviceName";
2280        }
2281       
2282        if(false == $endpoint) {
2283            $endpoint = "http://$SERVER_NAME$SCRIPT_NAME";
2284        }
2285       
2286                $this->wsdl = new wsdl;
2287                $this->wsdl->serviceName = $serviceName;
2288        $this->wsdl->endpoint = $endpoint;
2289                $this->wsdl->namespaces['tns'] = $namespace;
2290                $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
2291                $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
2292        $this->wsdl->bindings[$serviceName.'Binding'] = array(
2293                'name'=>$serviceName.'Binding',
2294            'style'=>$style,
2295            'transport'=>$transport,
2296            'portType'=>$serviceName.'PortType');
2297        $this->wsdl->ports[$serviceName.'Port'] = array(
2298                'binding'=>$serviceName.'Binding',
2299            'location'=>$endpoint,
2300            'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
2301    }
2302}
2303
2304
2305
2306?><?php
2307
2308
2309
2310/**
2311* parses a WSDL file, allows access to it's data, other utility methods
2312*
2313* @author   Dietrich Ayala <dietrich@ganx4.com>
2314* @version  v 0.6.3
2315* @access public
2316*/
2317class wsdl extends XMLSchema {
2318    var $wsdl; 
2319    // define internal arrays of bindings, ports, operations, messages, etc.
2320    var $message = array();
2321    var $complexTypes = array();
2322    var $messages = array();
2323    var $currentMessage;
2324    var $currentOperation;
2325    var $portTypes = array();
2326    var $currentPortType;
2327    var $bindings = array();
2328    var $currentBinding;
2329    var $ports = array();
2330    var $currentPort;
2331    var $opData = array();
2332    var $status = '';
2333    var $documentation = false;
2334    var $endpoint = ''; 
2335    // array of wsdl docs to import
2336    var $import = array(); 
2337    // parser vars
2338    var $parser;
2339    var $position = 0;
2340    var $depth = 0;
2341    var $depth_array = array();
2342        var $usedNamespaces = array();
2343        // for getting wsdl
2344        var $proxyhost = '';
2345    var $proxyport = '';
2346   
2347    /**
2348     * constructor
2349     *
2350     * @param string $wsdl WSDL document URL
2351     * @access public
2352     */
2353    function wsdl($wsdl = '',$proxyhost=false,$proxyport=false){
2354        $this->wsdl = $wsdl;
2355        $this->proxyhost = $proxyhost;
2356        $this->proxyport = $proxyport;
2357       
2358        // parse wsdl file
2359        if ($wsdl != "") {
2360            $this->debug('initial wsdl file: ' . $wsdl);
2361            $this->parseWSDL($wsdl);
2362        } 
2363        // imports
2364        if (sizeof($this->import) > 0) {
2365            foreach($this->import as $ns => $url) {
2366                $this->debug('importing wsdl from ' . $url);
2367                $this->parseWSDL($url);
2368            } 
2369        } 
2370    } 
2371
2372    /**
2373     * parses the wsdl document
2374     *
2375     * @param string $wsdl path or URL
2376     * @access private
2377     */
2378    function parseWSDL($wsdl = '')
2379    {
2380        if ($wsdl == '') {
2381            $this->debug('no wsdl passed to parseWSDL()!!');
2382            $this->setError('no wsdl passed to parseWSDL()!!');
2383            return false;
2384        } 
2385
2386        $this->debug('getting ' . $wsdl);
2387       
2388        // parse $wsdl for url format
2389        $wsdl_props = parse_url($wsdl);
2390
2391        if (isset($wsdl_props['host'])) {
2392               
2393                // get wsdl
2394                $tr = new soap_transport_http($wsdl);
2395                        $tr->request_method = 'GET';
2396                        $tr->useSOAPAction = false;
2397                        if($this->proxyhost && $this->proxyport){
2398                                $tr->setProxy($this->proxyhost,$this->proxyport);
2399                        }
2400                        if (isset($wsdl_props['user'])) {
2401                $tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']);
2402            }
2403                        $wsdl_string = $tr->send('');
2404                        // catch errors
2405                        if($err = $tr->getError() ){
2406                                $this->debug('HTTP ERROR: '.$err);
2407                    $this->setError('HTTP ERROR: '.$err);
2408                    return false;
2409                        }
2410                        unset($tr);
2411            /* $wsdl seems to be a valid url, not a file path, do an fsockopen/HTTP GET
2412            $fsockopen_timeout = 30;
2413            // check if a port value is supplied in url
2414            if (isset($wsdl_props['port'])) {
2415                // yes
2416                $wsdl_url_port = $wsdl_props['port'];
2417            } else {
2418                // no, assign port number, based on url protocol (scheme)
2419                switch ($wsdl_props['scheme']) {
2420                    case ('https') :
2421                    case ('ssl') :
2422                    case ('tls') :
2423                        $wsdl_url_port = 443;
2424                        break;
2425                    case ('http') :
2426                    default :
2427                        $wsdl_url_port = 80;
2428                }
2429            }
2430            // FIXME: should implement SSL/TLS support here if CURL is available
2431            if ($fp = fsockopen($wsdl_props['host'], $wsdl_url_port, $fsockopen_errnum, $fsockopen_errstr, $fsockopen_timeout)) {
2432                // perform HTTP GET for WSDL file
2433                // 10.9.02 - added poulter fix for doing this properly
2434                $sHeader = "GET " . $wsdl_props['path'];
2435                if (isset($wsdl_props['query'])) {
2436                    $sHeader .= "?" . $wsdl_props['query'];
2437                }
2438                $sHeader .= " HTTP/1.0\r\n";
2439
2440                if (isset($wsdl_props['user'])) {
2441                    $base64auth = base64_encode($wsdl_props['user'] . ":" . $wsdl_props['pass']);
2442                    $sHeader .= "Authorization: Basic $base64auth\r\n";
2443                }
2444                                $sHeader .= "Host: " . $wsdl_props['host'] . ( isset($wsdl_props['port']) ? ":".$wsdl_props['port'] : "" ) . "\r\n\r\n";
2445                fputs($fp, $sHeader);
2446
2447                while (fgets($fp, 1024) != "\r\n") {
2448                    // do nothing, just read/skip past HTTP headers
2449                    // FIXME: should actually detect HTTP response code, and act accordingly if error
2450                    // HTTP headers end with extra CRLF before content body
2451                }
2452                // read in WSDL just like regular fopen()
2453                $wsdl_string = '';
2454                while ($data = fread($fp, 32768)) {
2455                    $wsdl_string .= $data;
2456                }
2457                fclose($fp);
2458            } else {
2459                $this->setError('bad path to WSDL file.');
2460                return false;
2461            }
2462            */
2463        } else {
2464            // $wsdl seems to be a non-url file path, do the regular fopen
2465            if ($fp = @fopen($wsdl, 'r')) {
2466                $wsdl_string = '';
2467                while ($data = fread($fp, 32768)) {
2468                    $wsdl_string .= $data;
2469                } 
2470                fclose($fp);
2471            } else {
2472                $this->setError('bad path to WSDL file.');
2473                return false;
2474            } 
2475        }
2476        // end new code added
2477        // Create an XML parser.
2478        $this->parser = xml_parser_create(); 
2479        // Set the options for parsing the XML data.
2480        // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2481        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
2482        // Set the object for the parser.
2483        xml_set_object($this->parser, $this); 
2484        // Set the element handlers for the parser.
2485        xml_set_element_handler($this->parser, 'start_element', 'end_element');
2486        xml_set_character_data_handler($this->parser, 'character_data');
2487        // Parse the XML file.
2488        if (!xml_parse($this->parser, $wsdl_string, true)) {
2489            // Display an error message.
2490            $errstr = sprintf(
2491                                'XML error on line %d: %s',
2492                xml_get_current_line_number($this->parser),
2493                xml_error_string(xml_get_error_code($this->parser))
2494                );
2495            $this->debug('XML parse error: ' . $errstr);
2496            $this->setError('Parser error: ' . $errstr);
2497            return false;
2498        } 
2499                // free the parser
2500        xml_parser_free($this->parser);
2501                // catch wsdl parse errors
2502                if($this->getError()){
2503                        return false;
2504                }
2505        // add new data to operation data
2506        foreach($this->bindings as $binding => $bindingData) {
2507            if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
2508                foreach($bindingData['operations'] as $operation => $data) {
2509                    $this->debug('post-parse data gathering for ' . $operation);
2510                    $this->bindings[$binding]['operations'][$operation]['input'] = 
2511                                                isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
2512                                                array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
2513                                                $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
2514                    $this->bindings[$binding]['operations'][$operation]['output'] = 
2515                                                isset($this->bindings[$binding]['operations'][$operation]['output']) ?
2516                                                array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
2517                                                $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
2518                    if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
2519                                                $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
2520                                        }
2521                                        if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
2522                                $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
2523                    }
2524                                        if (isset($bindingData['style'])) {
2525                        $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
2526                    }
2527                    $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
2528                    $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
2529                    $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
2530                } 
2531            } 
2532        }
2533        return true;
2534    } 
2535
2536    /**
2537     * start-element handler
2538     *
2539     * @param string $parser XML parser object
2540     * @param string $name element name
2541     * @param string $attrs associative array of attributes
2542     * @access private
2543     */
2544    function start_element($parser, $name, $attrs)
2545    {
2546        if ($this->status == 'schema' || ereg('schema$', $name)) {
2547            // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
2548            $this->status = 'schema';
2549            $this->schemaStartElement($parser, $name, $attrs);
2550        } else {
2551            // position in the total number of elements, starting from 0
2552            $pos = $this->position++;
2553            $depth = $this->depth++; 
2554            // set self as current value for this depth
2555            $this->depth_array[$depth] = $pos;
2556            $this->message[$pos] = array('cdata' => ''); 
2557            // get element prefix
2558            if (ereg(':', $name)) {
2559                // get ns prefix
2560                $prefix = substr($name, 0, strpos($name, ':')); 
2561                // get ns
2562                $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 
2563                // get unqualified name
2564                $name = substr(strstr($name, ':'), 1);
2565            } 
2566
2567            if (count($attrs) > 0) {
2568                foreach($attrs as $k => $v) {
2569                    // if ns declarations, add to class level array of valid namespaces
2570                    if (ereg("^xmlns", $k)) {
2571                        if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
2572                            $this->namespaces[$ns_prefix] = $v;
2573                        } else {
2574                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
2575                        } 
2576                        if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema') {
2577                            $this->XMLSchemaVersion = $v;
2578                            $this->namespaces['xsi'] = $v . '-instance';
2579                        } 
2580                    } // 
2581                    // expand each attribute
2582                    $k = strpos($k, ':') ? $this->expandQname($k) : $k;
2583                    if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
2584                        $v = strpos($v, ':') ? $this->expandQname($v) : $v;
2585                    } 
2586                    $eAttrs[$k] = $v;
2587                } 
2588                $attrs = $eAttrs;
2589            } else {
2590                $attrs = array();
2591            } 
2592            // find status, register data
2593            switch ($this->status) {
2594                case 'message':
2595                    if ($name == 'part') {
2596                        if (isset($attrs['type'])) {
2597                                    $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
2598                                    $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
2599                                } 
2600                                    if (isset($attrs['element'])) {
2601                                        $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
2602                                    } 
2603                                } 
2604                                break;
2605                            case 'portType':
2606                                switch ($name) {
2607                                    case 'operation':
2608                                        $this->currentPortOperation = $attrs['name'];
2609                                        $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
2610                                        if (isset($attrs['parameterOrder'])) {
2611                                                $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
2612                                                } 
2613                                                break;
2614                                            case 'documentation':
2615                                                $this->documentation = true;
2616                                                break; 
2617                                            // merge input/output data
2618                                            default:
2619                                                $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
2620                                                $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
2621                                                break;
2622                                        } 
2623                                break;
2624                                case 'binding':
2625                                    switch ($name) {
2626                                        case 'binding': 
2627                                            // get ns prefix
2628                                            if (isset($attrs['style'])) {
2629                                            $this->bindings[$this->currentBinding]['prefix'] = $prefix;
2630                                                } 
2631                                                $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
2632                                                break;
2633                                                case 'header':
2634                                                    $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
2635                                                    break;
2636                                                case 'operation':
2637                                                    if (isset($attrs['soapAction'])) {
2638                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
2639                                                    } 
2640                                                    if (isset($attrs['style'])) {
2641                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
2642                                                    } 
2643                                                    if (isset($attrs['name'])) {
2644                                                        $this->currentOperation = $attrs['name'];
2645                                                        $this->debug("current binding operation: $this->currentOperation");
2646                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
2647                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
2648                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
2649                                                    } 
2650                                                    break;
2651                                                case 'input':
2652                                                    $this->opStatus = 'input';
2653                                                    break;
2654                                                case 'output':
2655                                                    $this->opStatus = 'output';
2656                                                    break;
2657                                                case 'body':
2658                                                    if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
2659                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
2660                                                    } else {
2661                                                        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
2662                                                    } 
2663                                                    break;
2664                                        } 
2665                                        break;
2666                                case 'service':
2667                                        switch ($name) {
2668                                            case 'port':
2669                                                $this->currentPort = $attrs['name'];
2670                                                $this->debug('current port: ' . $this->currentPort);
2671                                                $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
2672                                       
2673                                                break;
2674                                            case 'address':
2675                                                $this->ports[$this->currentPort]['location'] = $attrs['location'];
2676                                                $this->ports[$this->currentPort]['bindingType'] = $namespace;
2677                                                $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
2678                                                $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
2679                                                break;
2680                                        } 
2681                                        break;
2682                        } 
2683                // set status
2684                switch ($name) {
2685                        case "import":
2686                            if (isset($attrs['location'])) {
2687                                $this->import[$attrs['namespace']] = $attrs['location'];
2688                                } 
2689                                break;
2690                        case 'types':
2691                                $this->status = 'schema';
2692                                break;
2693                        case 'message':
2694                                $this->status = 'message';
2695                                $this->messages[$attrs['name']] = array();
2696                                $this->currentMessage = $attrs['name'];
2697                                break;
2698                        case 'portType':
2699                                $this->status = 'portType';
2700                                $this->portTypes[$attrs['name']] = array();
2701                                $this->currentPortType = $attrs['name'];
2702                                break;
2703                        case "binding":
2704                                if (isset($attrs['name'])) {
2705                                // get binding name
2706                                        if (strpos($attrs['name'], ':')) {
2707                                        $this->currentBinding = $this->getLocalPart($attrs['name']);
2708                                        } else {
2709                                        $this->currentBinding = $attrs['name'];
2710                                        } 
2711                                        $this->status = 'binding';
2712                                        $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
2713                                        $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
2714                                } 
2715                                break;
2716                        case 'service':
2717                                $this->serviceName = $attrs['name'];
2718                                $this->status = 'service';
2719                                $this->debug('current service: ' . $this->serviceName);
2720                                break;
2721                        case 'definitions':
2722                                foreach ($attrs as $name => $value) {
2723                                        $this->wsdl_info[$name] = $value;
2724                                } 
2725                                break;
2726                        } 
2727                } 
2728        } 
2729
2730        /**
2731        * end-element handler
2732        *
2733        * @param string $parser XML parser object
2734        * @param string $name element name
2735        * @access private
2736        */
2737        function end_element($parser, $name){ 
2738                // unset schema status
2739                if (ereg('types$', $name) || ereg('schema$', $name)) {
2740                        $this->status = "";
2741                } 
2742                if ($this->status == 'schema') {
2743                        $this->schemaEndElement($parser, $name);
2744                } else {
2745                        // bring depth down a notch
2746                        $this->depth--;
2747                } 
2748                // end documentation
2749                if ($this->documentation) {
2750                        $this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
2751                        $this->documentation = false;
2752                } 
2753        } 
2754
2755        /**
2756         * element content handler
2757         *
2758         * @param string $parser XML parser object
2759         * @param string $data element content
2760         * @access private
2761         */
2762        function character_data($parser, $data)
2763        {
2764                $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
2765                if (isset($this->message[$pos]['cdata'])) {
2766                        $this->message[$pos]['cdata'] .= $data;
2767                } 
2768                if ($this->documentation) {
2769                        $this->documentation .= $data;
2770                } 
2771        } 
2772       
2773        function getBindingData($binding)
2774        {
2775                if (is_array($this->bindings[$binding])) {
2776                        return $this->bindings[$binding];
2777                } 
2778        }
2779       
2780        /**
2781         * returns an assoc array of operation names => operation data
2782         * NOTE: currently only supports multiple services of differing binding types
2783         * This method needs some work
2784         *
2785         * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported)
2786         * @return array
2787         * @access public
2788         */
2789        function getOperations($bindingType = 'soap')
2790        {
2791                if ($bindingType == 'soap') {
2792                        $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
2793                }
2794                // loop thru ports
2795                foreach($this->ports as $port => $portData) {
2796                        // binding type of port matches parameter
2797                        if ($portData['bindingType'] == $bindingType) {
2798                                // get binding
2799                                return $this->bindings[ $portData['binding'] ]['operations'];
2800                        }
2801                } 
2802                return array();
2803        } 
2804       
2805        /**
2806         * returns an associative array of data necessary for calling an operation
2807         *
2808         * @param string $operation , name of operation
2809         * @param string $bindingType , type of binding eg: soap
2810         * @return array
2811         * @access public
2812         */
2813        function getOperationData($operation, $bindingType = 'soap')
2814        {
2815                if ($bindingType == 'soap') {
2816                        $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
2817                }
2818                // loop thru ports
2819                foreach($this->ports as $port => $portData) {
2820                        // binding type of port matches parameter
2821                        if ($portData['bindingType'] == $bindingType) {
2822                                // get binding
2823                                //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
2824                                foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
2825                                        if ($operation == $bOperation) {
2826                                                $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
2827                                            return $opData;
2828                                        } 
2829                                } 
2830                        }
2831                } 
2832        }
2833       
2834        /**
2835        * serialize the parsed wsdl
2836        *
2837        * @return string , serialization of WSDL
2838        * @access public
2839        */
2840        function serialize()
2841        {
2842                $xml = '<?xml version="1.0"?><definitions';
2843                foreach($this->namespaces as $k => $v) {
2844                        $xml .= " xmlns:$k=\"$v\"";
2845                } 
2846                // 10.9.02 - add poulter fix for wsdl and tns declarations
2847                if (isset($this->namespaces['wsdl'])) {
2848                        $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
2849                } 
2850                if (isset($this->namespaces['tns'])) {
2851                        $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
2852                } 
2853                $xml .= '>'; 
2854                // imports
2855                if (sizeof($this->import) > 0) {
2856                        foreach($this->import as $ns => $url) {
2857                                $xml .= '<import location="' . $url . '" namespace="' . $ns . '" />';
2858                        } 
2859                } 
2860                // types
2861                if (count($this->complexTypes)>=1) {
2862                        $xml .= '<types>';
2863                        $xml .= $this->serializeSchema();
2864                        $xml .= '</types>';
2865                } 
2866                // messages
2867                if (count($this->messages) >= 1) {
2868                        foreach($this->messages as $msgName => $msgParts) {
2869                                $xml .= '<message name="' . $msgName . '">';
2870                                foreach($msgParts as $partName => $partType) {
2871                                        // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
2872                                        if (strpos($partType, ':')) {
2873                                            $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
2874                                        } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
2875                                            // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
2876                                            $typePrefix = 'xsd';
2877                                        } else {
2878                                            foreach($this->typemap as $ns => $types) {
2879                                                if (isset($types[$partType])) {
2880                                                    $typePrefix = $this->getPrefixFromNamespace($ns);
2881                                                } 
2882                                            } 
2883                                            if (!isset($typePrefix)) {
2884                                                die("$partType has no namespace!");
2885                                            } 
2886                                        } 
2887                                        $xml .= '<part name="' . $partName . '" type="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
2888                                } 
2889                                $xml .= '</message>';
2890                        } 
2891                } 
2892                // bindings & porttypes
2893                if (count($this->bindings) >= 1) {
2894                        $binding_xml = '';
2895                        $portType_xml = '';
2896                        foreach($this->bindings as $bindingName => $attrs) {
2897                                $binding_xml .= '<binding name="' . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
2898                                $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
2899                                $portType_xml .= '<portType name="' . $attrs['portType'] . '">';
2900                                foreach($attrs['operations'] as $opName => $opParts) {
2901                                        $binding_xml .= '<operation name="' . $opName . '">';
2902                                        $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $attrs['style'] . '"/>';
2903                                        $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '" encodingStyle="' . $opParts['input']['encodingStyle'] . '"/></input>';
2904                                        $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '" encodingStyle="' . $opParts['output']['encodingStyle'] . '"/></output>';
2905                                        $binding_xml .= '</operation>';
2906                                        $portType_xml .= '<operation name="' . $opParts['name'] . '"';
2907                                        if (isset($opParts['parameterOrder'])) {
2908                                            $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
2909                                        } 
2910                                        $portType_xml .= '>';
2911                                        $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
2912                                        $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
2913                                        $portType_xml .= '</operation>';
2914                                } 
2915                                $portType_xml .= '</portType>';
2916                                $binding_xml .= '</binding>';
2917                        } 
2918                        $xml .= $portType_xml . $binding_xml;
2919                } 
2920                // services
2921                $xml .= '<service name="' . $this->serviceName . '">';
2922                if (count($this->ports) >= 1) {
2923                        foreach($this->ports as $pName => $attrs) {
2924                                $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
2925                                $xml .= '<soap:address location="' . $attrs['location'] . '"/>';
2926                                $xml .= '</port>';
2927                        } 
2928                } 
2929                $xml .= '</service>';
2930                return $xml . '</definitions>';
2931        } 
2932       
2933        /**
2934         * serialize a PHP value according to a WSDL message definition
2935         *
2936         * TODO
2937         * - multi-ref serialization
2938         * - validate PHP values against type definitions, return errors if invalid
2939         *
2940         * @param string $ type name
2941         * @param mixed $ param value
2942         * @return mixed new param or false if initial value didn't validate
2943         */
2944        function serializeRPCParameters($operation, $direction, $parameters)
2945        {
2946                $this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion); 
2947               
2948                if ($direction != 'input' && $direction != 'output') {
2949                        $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
2950                        $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
2951                        return false;
2952                } 
2953                if (!$opData = $this->getOperationData($operation)) {
2954                        $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
2955                        $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
2956                        return false;
2957                }
2958                $this->debug($this->varDump($opData));
2959                // set input params
2960                $xml = '';
2961                if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
2962                       
2963                        $use = $opData[$direction]['use'];
2964                        $this->debug("use=$use");
2965                        $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
2966                        foreach($opData[$direction]['parts'] as $name => $type) {
2967                                $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
2968                                // NOTE: add error handling here
2969                                // if serializeType returns false, then catch global error and fault
2970                                if (isset($parameters[$name])) {
2971                                        $this->debug('calling serializeType w/ named param');
2972                                        $xml .= $this->serializeType($name, $type, $parameters[$name], $use);
2973                                } elseif(is_array($parameters)) {
2974                                        $this->debug('calling serializeType w/ unnamed param');
2975                                        $xml .= $this->serializeType($name, $type, array_shift($parameters), $use);
2976                                } else {
2977                                        $this->debug('no parameters passed.');
2978                                }
2979                        }
2980                }
2981                return $xml;
2982        } 
2983       
2984        /**
2985         * serializes a PHP value according a given type definition
2986         *
2987         * @param string $name , name of type (part)
2988         * @param string $type , type of type, heh (type or element)
2989         * @param mixed $value , a native PHP value (parameter value)
2990         * @param string $use , use for part (encoded|literal)
2991         * @return string serialization
2992         * @access public
2993         */
2994        function serializeType($name, $type, $value, $use='encoded')
2995        {
2996                $this->debug("in serializeType: $name, $type, $value, $use");
2997                $xml = '';
2998                if (strpos($type, ':')) {
2999                        $uqType = substr($type, strrpos($type, ':') + 1);
3000                        $ns = substr($type, 0, strrpos($type, ':'));
3001                        $this->debug("got a prefixed type: $uqType, $ns");
3002                       
3003                        if($ns == $this->XMLSchemaVersion ||
3004                                           ($this->getNamespaceFromPrefix($ns)) == $this->XMLSchemaVersion){
3005                               
3006                        if ($uqType == 'boolean' && !$value) {
3007                                        $value = 0;
3008                                } elseif ($uqType == 'boolean') {
3009                                        $value = 1;
3010                                } 
3011                                if ($this->charencoding && $uqType == 'string' && gettype($value) == 'string') {
3012                                        $value = htmlspecialchars($value);
3013                                } 
3014                                // it's a scalar
3015                                if ($use == 'literal') {
3016                                        return "<$name>$value</$name>";
3017                                } else {
3018                                        return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\">$value</$name>";
3019                                }
3020                        } 
3021                } else {
3022                        $uqType = $type;
3023                }
3024                if(!$typeDef = $this->getTypeDef($uqType)){
3025                        $this->setError("$uqType is not a supported type.");
3026                        return false;
3027                } else {
3028                        //foreach($typeDef as $k => $v) {
3029                                //$this->debug("typedef, $k: $v");
3030                        //}
3031                }
3032                $phpType = $typeDef['phpType'];
3033                $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 
3034                // if php type == struct, map value to the <all> element names
3035                if ($phpType == 'struct') {
3036                        if (isset($typeDef['element']) && $typeDef['element']) {
3037                                $elementName = $uqType;
3038                                // TODO: use elementFormDefault="qualified|unqualified" to determine
3039                                // how to scope the namespace
3040                                $elementNS = " xmlns=\"$ns\"";
3041                        } else {
3042                                $elementName = $name;
3043                                $elementNS = '';
3044                        }
3045                        if ($use == 'literal') {
3046                                $xml = "<$elementName$elementNS>";
3047                        } else {
3048                                $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
3049                        }
3050                       
3051                        if (isset($this->complexTypes[$uqType]['elements']) && is_array($this->complexTypes[$uqType]['elements'])) {
3052                       
3053                        //if (is_array($this->complexTypes[$uqType]['elements'])) {
3054                                // toggle whether all elements are present - ideally should validate against schema
3055                                if(count($this->complexTypes[$uqType]['elements']) != count($value)){
3056                                        $optionals = true;
3057                                }
3058                                foreach($this->complexTypes[$uqType]['elements'] as $eName => $attrs) {
3059                                        // if user took advantage of a minOccurs=0, then only serialize named parameters
3060                                        if(isset($optionals) && !isset($value[$eName])){
3061                                                // do nothing
3062                                        } else {
3063                                                // get value
3064                                                if (isset($value[$eName])) {
3065                                                    $v = $value[$eName];
3066                                                } elseif (is_array($value)) {
3067                                                    $v = array_shift($value);
3068                                                }
3069                                                // serialize schema-defined type
3070                                                if (!isset($attrs['type'])) {
3071                                                    $xml .= $this->serializeType($eName, $attrs['name'], $v, $use);
3072                                                // serialize generic type
3073                                                } else {
3074                                                    $this->debug("calling serialize_val() for $eName, $v, " . $this->getLocalPart($attrs['type']), false, $use);
3075                                                    $xml .= $this->serialize_val($v, $eName, $this->getLocalPart($attrs['type']), null, $this->getNamespaceFromPrefix($this->getPrefix($attrs['type'])), false, $use);
3076                                                }
3077                                        }
3078                                } 
3079                        }
3080                        $xml .= "</$elementName>";
3081                } elseif ($phpType == 'array') {
3082                        $rows = sizeof($value);
3083                        if (isset($typeDef['multidimensional'])) {
3084                                $nv = array();
3085                                foreach($value as $v) {
3086                                        $cols = ',' . sizeof($v);
3087                                        $nv = array_merge($nv, $v);
3088                                } 
3089                                $value = $nv;
3090                        } else {
3091                                $cols = '';
3092                        } 
3093                        if (is_array($value) && sizeof($value) >= 1) {
3094                                $contents = '';
3095                                foreach($value as $k => $v) {
3096                                        $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
3097                                        //if (strpos($typeDef['arrayType'], ':') ) {
3098                                        if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
3099                                            $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
3100                                        } else {
3101                                            $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
3102                                        } 
3103                                }
3104                                $this->debug('contents: '.$this->varDump($contents));
3105                        } else {
3106                                $contents = null;
3107                        }
3108                        if ($use == 'literal') {
3109                                $xml = "<$name>"
3110                                        .$contents
3111                                        ."</$name>";
3112                        } else {
3113                                $xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
3114                                        $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
3115                                        .':arrayType="'
3116                                        .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
3117                                        .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
3118                                        .$contents
3119                                        ."</$name>";
3120                        }
3121                }
3122                $this->debug('returning: '.$this->varDump($xml));
3123                return $xml;
3124        }
3125       
3126        /**
3127        * register a service with the server
3128        *
3129        * @param string $methodname
3130        * @param string $in assoc array of input values: key = param name, value = param type
3131        * @param string $out assoc array of output values: key = param name, value = param type
3132        * @param string $namespace
3133        * @param string $soapaction
3134        * @param string $style (rpc|literal)
3135        * @access public
3136        */
3137        function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '')
3138        {
3139        if ($style == 'rpc' && $use == 'encoded') {
3140                $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
3141        } else {
3142                $encodingStyle = '';
3143        } 
3144        // get binding
3145        $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
3146        array(
3147        'name' => $name,
3148        'binding' => $this->serviceName . 'Binding',
3149        'endpoint' => $this->endpoint,
3150        'soapAction' => $soapaction,
3151        'style' => $style,
3152        'input' => array(
3153                'use' => $use,
3154                'namespace' => $namespace,
3155                'encodingStyle' => $encodingStyle,
3156                'message' => $name . 'Request',
3157                'parts' => $in),
3158        'output' => array(
3159                'use' => $use,
3160                'namespace' => $namespace,
3161                'encodingStyle' => $encodingStyle,
3162                'message' => $name . 'Response',
3163                'parts' => $out),
3164        'namespace' => $namespace,
3165        'transport' => 'http://schemas.xmlsoap.org/soap/http',
3166        'documentation' => $documentation); 
3167        // add portTypes
3168        // add messages
3169                if($in)
3170                {
3171                        foreach($in as $pName => $pType)
3172                        {
3173                                if(strpos($pType,':')) {
3174                                        $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
3175                                }
3176                                $this->messages[$name.'Request'][$pName] = $pType;
3177                        }
3178                }
3179               
3180                if($out)
3181                {
3182                        foreach($out as $pName => $pType)
3183                        {
3184                                if(strpos($pType,':')) {
3185                                        $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
3186                                }
3187                                $this->messages[$name.'Response'][$pName] = $pType;
3188                        }
3189                }
3190        return true;
3191        } 
3192} 
3193
3194
3195
3196?><?php
3197
3198
3199
3200/**
3201*
3202* soap_parser class parses SOAP XML messages into native PHP values
3203*
3204* @author   Dietrich Ayala <dietrich@ganx4.com>
3205* @version  v 0.6.3
3206* @access   public
3207*/
3208class soap_parser extends nusoap_base {
3209
3210        var $xml = '';
3211        var $xml_encoding = '';
3212        var $method = '';
3213        var $root_struct = '';
3214        var $root_struct_name = '';
3215        var $root_header = '';
3216    var $document = '';
3217        // determines where in the message we are (envelope,header,body,method)
3218        var $status = '';
3219        var $position = 0;
3220        var $depth = 0;
3221        var $default_namespace = '';
3222        var $namespaces = array();
3223        var $message = array();
3224    var $parent = '';
3225        var $fault = false;
3226        var $fault_code = '';
3227        var $fault_str = '';
3228        var $fault_detail = '';
3229        var $depth_array = array();
3230        var $debug_flag = true;
3231        var $soapresponse = NULL;
3232        var $responseHeaders = '';
3233        var $body_position = 0;
3234        // for multiref parsing:
3235        // array of id => pos
3236        var $ids = array();
3237        // array of id => hrefs => pos
3238        var $multirefs = array();
3239
3240        /**
3241        * constructor
3242        *
3243        * @param    string $xml SOAP message
3244        * @param    string $encoding character encoding scheme of message
3245        * @access   public
3246        */
3247        function soap_parser($xml,$encoding='UTF-8',$method=''){
3248                $this->xml = $xml;
3249                $this->xml_encoding = $encoding;
3250                $this->method = $method;
3251
3252                // Check whether content has been read.
3253                if(!empty($xml)){
3254                        $this->debug('Entering soap_parser()');
3255                        // Create an XML parser.
3256                        $this->parser = xml_parser_create($this->xml_encoding);
3257                        // Set the options for parsing the XML data.
3258                        //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
3259                        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
3260                        // Set the object for the parser.
3261                        xml_set_object($this->parser, $this);
3262                        // Set the element handlers for the parser.
3263                        xml_set_element_handler($this->parser, 'start_element','end_element');
3264                        xml_set_character_data_handler($this->parser,'character_data');
3265
3266                        // Parse the XML file.
3267                        if(!xml_parse($this->parser,$xml,true)){
3268                            // Display an error message.
3269                            $err = sprintf('XML error on line %d: %s',
3270                            xml_get_current_line_number($this->parser),
3271                            xml_error_string(xml_get_error_code($this->parser)));
3272                                $this->debug('parse error: '.$err);
3273                                $this->errstr = $err;
3274                        } else {
3275                                $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
3276                                // get final value
3277                                $this->soapresponse = $this->message[$this->root_struct]['result'];
3278                                // get header value
3279                                if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
3280                                        $this->responseHeaders = $this->message[$this->root_header]['result'];
3281                                }
3282                                // resolve hrefs/ids
3283                                if(sizeof($this->multirefs) > 0){
3284                                        foreach($this->multirefs as $id => $hrefs){
3285                                                $this->debug('resolving multirefs for id: '.$id);
3286                                                $idVal = $this->buildVal($this->ids[$id]);
3287                                                foreach($hrefs as $refPos => $ref){
3288                                                        $this->debug('resolving href at pos '.$refPos);
3289                                                        $this->multirefs[$id][$refPos] = $idVal;
3290                                                }
3291                                        }
3292                                }
3293                        }
3294                        xml_parser_free($this->parser);
3295                } else {
3296                        $this->debug('xml was empty, didn\'t parse!');
3297                        $this->errstr = 'xml was empty, didn\'t parse!';
3298                }
3299        }
3300
3301        /**
3302        * start-element handler
3303        *
3304        * @param    string $parser XML parser object
3305        * @param    string $name element name
3306        * @param    string $attrs associative array of attributes
3307        * @access   private
3308        */
3309        function start_element($parser, $name, $attrs) {
3310                // position in a total number of elements, starting from 0
3311                // update class level pos
3312                $pos = $this->position++;
3313                // and set mine
3314                $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
3315                // depth = how many levels removed from root?
3316                // set mine as current global depth and increment global depth value
3317                $this->message[$pos]['depth'] = $this->depth++;
3318
3319                // else add self as child to whoever the current parent is
3320                if($pos != 0){
3321                        $this->message[$this->parent]['children'] .= '|'.$pos;
3322                }
3323                // set my parent
3324                $this->message[$pos]['parent'] = $this->parent;
3325                // set self as current parent
3326                $this->parent = $pos;
3327                // set self as current value for this depth
3328                $this->depth_array[$this->depth] = $pos;
3329                // get element prefix
3330                if(strpos($name,':')){
3331                        // get ns prefix
3332                        $prefix = substr($name,0,strpos($name,':'));
3333                        // get unqualified name
3334                        $name = substr(strstr($name,':'),1);
3335                }
3336                // set status
3337                if($name == 'Envelope'){
3338                        $this->status = 'envelope';
3339                } elseif($name == 'Header'){
3340                        $this->root_header = $pos;
3341                        $this->status = 'header';
3342                } elseif($name == 'Body'){
3343                        $this->status = 'body';
3344                        $this->body_position = $pos;
3345                // set method
3346                } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
3347                        $this->status = 'method';
3348                        $this->root_struct_name = $name;
3349                        $this->root_struct = $pos;
3350                        $this->message[$pos]['type'] = 'struct';
3351                        $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
3352                }
3353                // set my status
3354                $this->message[$pos]['status'] = $this->status;
3355                // set name
3356                $this->message[$pos]['name'] = htmlspecialchars($name);
3357                // set attrs
3358                $this->message[$pos]['attrs'] = $attrs;
3359
3360                // loop through atts, logging ns and type declarations
3361        $attstr = '';
3362                foreach($attrs as $key => $value){
3363                $key_prefix = $this->getPrefix($key);
3364                        $key_localpart = $this->getLocalPart($key);
3365                        // if ns declarations, add to class level array of valid namespaces
3366            if($key_prefix == 'xmlns'){
3367                                if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
3368                                        $this->XMLSchemaVersion = $value;
3369                                        $this->namespaces['xsd'] = $this->XMLSchemaVersion;
3370                                        $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
3371                                }
3372                $this->namespaces[$key_localpart] = $value;
3373                                // set method namespace
3374                                if($name == $this->root_struct_name){
3375                                        $this->methodNamespace = $value;
3376                                }
3377                        // if it's a type declaration, set type
3378            } elseif($key_localpart == 'type'){
3379                $value_prefix = $this->getPrefix($value);
3380                $value_localpart = $this->getLocalPart($value);
3381                                $this->message[$pos]['type'] = $value_localpart;
3382                                $this->message[$pos]['typePrefix'] = $value_prefix;
3383                if(isset($this->namespaces[$value_prefix])){
3384                        $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
3385                } else if(isset($attrs['xmlns:'.$value_prefix])) {
3386                                        $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
3387                }
3388                                // should do something here with the namespace of specified type?
3389                        } elseif($key_localpart == 'arrayType'){
3390                                $this->message[$pos]['type'] = 'array';
3391                                /* do arrayType ereg here
3392                                [1]    arrayTypeValue    ::=    atype asize
3393                                [2]    atype    ::=    QName rank*
3394                                [3]    rank    ::=    '[' (',')* ']'
3395                                [4]    asize    ::=    '[' length~ ']'
3396                                [5]    length    ::=    nextDimension* Digit+
3397                                [6]    nextDimension    ::=    Digit+ ','
3398                                */
3399                                $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
3400                                if(ereg($expr,$value,$regs)){
3401                                        $this->message[$pos]['typePrefix'] = $regs[1];
3402                                        $this->message[$pos]['arraySize'] = $regs[3];
3403                                        $this->message[$pos]['arrayCols'] = $regs[4];
3404                                }
3405                        }
3406                        // log id
3407                        if($key == 'id'){
3408                                $this->ids[$value] = $pos;
3409                        }
3410                        // root
3411                        if($key_localpart == 'root' && $value == 1){
3412                                $this->status = 'method';
3413                                $this->root_struct_name = $name;
3414                                $this->root_struct = $pos;
3415                                $this->debug("found root struct $this->root_struct_name, pos $pos");
3416                        }
3417            // for doclit
3418            $attstr .= " $key=\"$value\"";
3419                }
3420        // get namespace - must be done after namespace atts are processed
3421                if(isset($prefix)){
3422                        $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
3423                        $this->default_namespace = $this->namespaces[$prefix];
3424                } else {
3425                        $this->message[$pos]['namespace'] = $this->default_namespace;
3426                }
3427        if($this->status == 'header'){
3428                $this->responseHeaders .= "<$name$attstr>";
3429        } elseif($this->root_struct_name != ''){
3430                $this->document .= "<$name$attstr>";
3431        }
3432        }
3433
3434        /**
3435        * end-element handler
3436        *
3437        * @param    string $parser XML parser object
3438        * @param    string $name element name
3439        * @access   private
3440        */
3441        function end_element($parser, $name) {
3442                // position of current element is equal to the last value left in depth_array for my depth
3443                $pos = $this->depth_array[$this->depth--];
3444
3445        // get element prefix
3446                if(strpos($name,':')){
3447                        // get ns prefix
3448                        $prefix = substr($name,0,strpos($name,':'));
3449                        // get unqualified name
3450                        $name = substr(strstr($name,':'),1);
3451                }
3452
3453                // build to native type
3454                if(isset($this->body_position) && $pos > $this->body_position){
3455                        // deal w/ multirefs
3456                        if(isset($this->message[$pos]['attrs']['href'])){
3457                                // get id
3458                                $id = substr($this->message[$pos]['attrs']['href'],1);
3459                                // add placeholder to href array
3460                                $this->multirefs[$id][$pos] = "placeholder";
3461                                // add set a reference to it as the result value
3462                                $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
3463            // build complex values
3464                        } elseif($this->message[$pos]['children'] != ""){
3465                                $this->message[$pos]['result'] = $this->buildVal($pos);
3466                        } else {
3467                $this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
3468                                if(is_numeric($this->message[$pos]['cdata']) ){
3469                        if( strpos($this->message[$pos]['cdata'],'.') ){
3470                                $this->message[$pos]['result'] = doubleval($this->message[$pos]['cdata']);
3471                    } else {
3472                        $this->message[$pos]['result'] = intval($this->message[$pos]['cdata']);
3473                    }
3474                } else {
3475                        $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
3476                }
3477                        }
3478                }
3479
3480                // switch status
3481                if($pos == $this->root_struct){
3482                        $this->status = 'body';
3483                } elseif($name == 'Body'){
3484                        $this->status = 'header';
3485                 } elseif($name == 'Header'){
3486                        $this->status = 'envelope';
3487                } elseif($name == 'Envelope'){
3488                        //
3489                }
3490                // set parent back to my parent
3491                $this->parent = $this->message[$pos]['parent'];
3492        // for doclit
3493        if($this->status == 'header'){
3494                $this->responseHeaders .= "</$name>";
3495        } elseif($pos >= $this->root_struct){
3496                $this->document .= "</$name>";
3497        }
3498        }
3499
3500        /**
3501        * element content handler
3502        *
3503        * @param    string $parser XML parser object
3504        * @param    string $data element content
3505        * @access   private
3506        */
3507        function character_data($parser, $data){
3508                $pos = $this->depth_array[$this->depth];
3509                if ($this->xml_encoding=='UTF-8'){
3510                        $data = utf8_decode($data);
3511                }
3512        $this->message[$pos]['cdata'] .= $data;
3513        // for doclit
3514        if($this->status == 'header'){
3515                $this->responseHeaders .= $data;
3516        } else {
3517                $this->document .= $data;
3518        }
3519        }
3520
3521        /**
3522        * get the parsed message
3523        *
3524        * @return       mixed
3525        * @access   public
3526        */
3527        function get_response(){
3528                return $this->soapresponse;
3529        }
3530
3531        /**
3532        * get the parsed headers
3533        *
3534        * @return       string XML or empty if no headers
3535        * @access   public
3536        */
3537        function getHeaders(){
3538            return $this->responseHeaders;
3539        }
3540
3541        /**
3542        * decodes entities
3543        *
3544        * @param    string $text string to translate
3545        * @access   private
3546        */
3547        function decode_entities($text){
3548                foreach($this->entities as $entity => $encoded){
3549                        $text = str_replace($encoded,$entity,$text);
3550                }
3551                return $text;
3552        }
3553
3554        /**
3555        * builds response structures for compound values (arrays/structs)
3556        *
3557        * @param    string $pos position in node tree
3558        * @access   private
3559        */
3560        function buildVal($pos){
3561                if(!isset($this->message[$pos]['type'])){
3562                        $this->message[$pos]['type'] = '';
3563                }
3564                $this->debug('inside buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
3565                // if there are children...
3566                if($this->message[$pos]['children'] != ''){
3567                        $children = explode('|',$this->message[$pos]['children']);
3568                        array_shift($children); // knock off empty
3569                        // md array
3570                        if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
3571                $r=0; // rowcount
3572                $c=0; // colcount
3573                foreach($children as $child_pos){
3574                                        $this->debug("got an MD array element: $r, $c");
3575                                        $params[$r][] = $this->message[$child_pos]['result'];
3576                                    $c++;
3577                                    if($c == $this->message[$pos]['arrayCols']){
3578                                        $c = 0;
3579                                                $r++;
3580                                    }
3581                }
3582            // array
3583                        } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
3584                $this->debug('adding array '.$this->message[$pos]['name']);
3585                foreach($children as $child_pos){
3586                        $params[] = &$this->message[$child_pos]['result'];
3587                }
3588            // apache Map type: java hashtable
3589            } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
3590                foreach($children as $child_pos){
3591                        $kv = explode("|",$this->message[$child_pos]['children']);
3592                        $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
3593                }
3594            // generic compound type
3595            //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
3596            } else {
3597                // is array or struct? better way to do this probably
3598                foreach($children as $child_pos){
3599                        if(isset($keys) && isset($keys[$this->message[$child_pos]['name']])){
3600                                $struct = 1;
3601                                break;
3602                        }
3603                        $keys[$this->message[$child_pos]['name']] = 1;
3604                }
3605                //
3606                foreach($children as $child_pos){
3607                        if(isset($struct)){
3608                                $params[] = &$this->message[$child_pos]['result'];
3609                        } else {
3610                                        $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
3611                        }
3612                }
3613                        }
3614                        return is_array($params) ? $params : array();
3615                } else {
3616                $this->debug('no children');
3617            if(strpos($this->message[$pos]['cdata'],'&')){
3618                        return  strtr($this->message[$pos]['cdata'],array_flip($this->entities));
3619            } else {
3620                return $this->message[$pos]['cdata'];
3621            }
3622                }
3623        }
3624}
3625
3626
3627
3628?><?php
3629
3630
3631
3632/**
3633*
3634* soapclient higher level class for easy usage.
3635*
3636* usage:
3637*
3638* // instantiate client with server info
3639* $soapclient = new soapclient( string path [ ,boolean wsdl] );
3640*
3641* // call method, get results
3642* echo $soapclient->call( string methodname [ ,array parameters] );
3643*
3644* // bye bye client
3645* unset($soapclient);
3646*
3647* @author   Dietrich Ayala <dietrich@ganx4.com>
3648* @version  v 0.6.3
3649* @access   public
3650*/
3651class soapclient extends nusoap_base  {
3652
3653        var $username = '';
3654        var $password = '';
3655        var $requestHeaders = false;
3656        var $responseHeaders;
3657        var $endpoint;
3658        var $error_str = false;
3659    var $proxyhost = '';
3660    var $proxyport = '';
3661    var $xml_encoding = '';
3662        var $http_encoding = false;
3663        var $timeout = 0;
3664        var $endpointType = '';
3665        var $persistentConnection = false;
3666        var $defaultRpcParams = false;
3667       
3668        /**
3669        * fault related variables
3670        *
3671        * @var      fault
3672        * @var      faultcode
3673        * @var      faultstring
3674        * @var      faultdetail
3675        * @access   public
3676        */
3677        var $fault, $faultcode, $faultstring, $faultdetail;
3678
3679        /**
3680        * constructor
3681        *
3682        * @param    string $endpoint SOAP server or WSDL URL
3683        * @param    bool $wsdl optional, set to true if using WSDL
3684        * @param        int $portName optional portName in WSDL document
3685        * @access   public
3686        */
3687        function soapclient($endpoint,$wsdl = false){
3688                $this->endpoint = $endpoint;
3689
3690                // make values
3691                if($wsdl){
3692                        $this->endpointType = 'wsdl';
3693                        $this->wsdlFile = $this->endpoint;
3694                       
3695                        // instantiate wsdl object and parse wsdl file
3696                        $this->debug('instantiating wsdl class with doc: '.$endpoint);
3697                        $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport);
3698                        $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
3699                        $this->wsdl->debug_str = '';
3700                        // catch errors
3701                        if($errstr = $this->wsdl->getError()){
3702                                $this->debug('got wsdl error: '.$errstr);
3703                                $this->setError('wsdl error: '.$errstr);
3704                        } elseif($this->operations = $this->wsdl->getOperations()){
3705                                $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
3706                        } else {
3707                                $this->debug( 'getOperations returned false');
3708                                $this->setError('no operations defined in the WSDL document!');
3709                        }
3710                }
3711        }
3712
3713        /**
3714        * calls method, returns PHP native type
3715        *
3716        * @param    string $method SOAP server URL or path
3717        * @param    array $params array of parameters, can be associative or not
3718        * @param        string $namespace optional method namespace
3719        * @param        string $soapAction optional SOAPAction value
3720        * @param        boolean $headers optional array of soapval objects for headers
3721        * @param        boolean $rpcParams optional treat params as RPC for use="literal"
3722        *                   This can be used on a per-call basis to overrider defaultRpcParams.
3723        * @return       mixed
3724        * @access   public
3725        */
3726        function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null){
3727                $this->operation = $operation;
3728                $this->fault = false;
3729                $this->error_str = '';
3730                $this->request = '';
3731                $this->response = '';
3732                $this->faultstring = '';
3733                $this->faultcode = '';
3734                $this->opData = array();
3735               
3736                $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $rpcParams");
3737                $this->debug("endpointType: $this->endpointType");
3738                // if wsdl, get operation data and process parameters
3739                if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
3740
3741                        $this->opData = $opData;
3742                        foreach($opData as $key => $value){
3743                                $this->debug("$key -> $value");
3744                        }
3745                        $soapAction = $opData['soapAction'];
3746                        $this->endpoint = $opData['endpoint'];
3747                        $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     'http://testuri.org';
3748                        $style = $opData['style'];
3749                        // add ns to ns array
3750                        if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
3751                                $this->wsdl->namespaces['nu'] = $namespace;
3752            }
3753                        // serialize payload
3754                       
3755                        if($opData['input']['use'] == 'literal') {
3756                                if (is_null($rpcParams)) {
3757                                        $rpcParams = $this->defaultRpcParams;
3758                                }
3759                                if ($rpcParams) {
3760                                        $this->debug("serializing literal params for operation $operation");
3761                                        $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
3762                                        $defaultNamespace = $this->wsdl->wsdl_info['targetNamespace'];
3763                                } else {
3764                                        $this->debug("serializing literal document for operation $operation");
3765                                        $payload = is_array($params) ? array_shift($params) : $params;
3766                                }
3767                        } else {
3768                                $this->debug("serializing encoded params for operation $operation");
3769                                $payload = "<".$this->wsdl->getPrefixFromNamespace($namespace).":$operation>".
3770                                $this->wsdl->serializeRPCParameters($operation,'input',$params).
3771                                '</'.$this->wsdl->getPrefixFromNamespace($namespace).":$operation>";
3772                        }
3773                        $this->debug('payload size: '.strlen($payload));
3774                        // serialize envelope
3775                        $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$this->wsdl->usedNamespaces,$style);
3776                        $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
3777                        $this->wsdl->debug_str = '';
3778                } elseif($this->endpointType == 'wsdl') {
3779                        $this->setError( 'operation '.$operation.' not present.');
3780                        $this->debug("operation '$operation' not present.");
3781                        $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
3782                        return false;
3783                // no wsdl
3784                } else {
3785                        // make message
3786                        if(!isset($style)){
3787                                $style = 'rpc';
3788                        }
3789            if($namespace == ''){
3790                $namespace = 'http://testuri.org';
3791                $this->wsdl->namespaces['ns1'] = $namespace;
3792            }
3793                        // serialize envelope
3794                        $payload = '';
3795                        foreach($params as $k => $v){
3796                                $payload .= $this->serialize_val($v,$k);
3797                        }
3798                        $payload = "<ns1:$operation xmlns:ns1=\"$namespace\">\n".$payload."</ns1:$operation>\n";
3799                        $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders);
3800                }
3801                $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace");
3802                // send
3803                $this->debug('sending msg (len: '.strlen($soapmsg).") w/ soapaction '$soapAction'...");
3804                $return = $this->send($soapmsg,$soapAction,$this->timeout);
3805                if($errstr = $this->getError()){
3806                        $this->debug('Error: '.$errstr);
3807                        return false;
3808                } else {
3809                        $this->return = $return;
3810                        $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
3811                       
3812                        // fault?
3813                        if(is_array($return) && isset($return['faultcode'])){
3814                                $this->debug('got fault');
3815                                $this->setError($return['faultcode'].': '.$return['faultstring']);
3816                                $this->fault = true;
3817                                foreach($return as $k => $v){
3818                                        $this->$k = $v;
3819                                        $this->debug("$k = $v<br>");
3820                                }
3821                                return $return;
3822                        } else {
3823                                // array of return values
3824                                if(is_array($return)){
3825                                        // multiple 'out' parameters
3826                                        if(sizeof($return) > 1){
3827                                                return $return;
3828                                        }
3829                                        // single 'out' parameter
3830                                        return array_shift($return);
3831                                // nothing returned (ie, echoVoid)
3832                                } else {
3833                                        return "";
3834                                }
3835                        }
3836                }
3837        }
3838
3839        /**
3840        * get available data pertaining to an operation
3841        *
3842        * @param    string $operation operation name
3843        * @return       array array of data pertaining to the operation
3844        * @access   public
3845        */
3846        function getOperationData($operation){
3847                if(isset($this->operations[$operation])){
3848                        return $this->operations[$operation];
3849                }
3850                $this->debug("No data for operation: $operation");
3851        }
3852
3853    /**
3854    * send the SOAP message
3855    *
3856    * Note: if the operation has multiple return values
3857    * the return value of this method will be an array
3858    * of those values.
3859    *
3860        * @param    string $msg a SOAPx4 soapmsg object
3861        * @param    string $soapaction SOAPAction value
3862        * @param    integer $timeout set timeout in seconds
3863        * @return       mixed native PHP types.
3864        * @access   private
3865        */
3866        function send($msg, $soapaction = '', $timeout=0) {
3867                // detect transport
3868                switch(true){
3869                        // http(s)
3870                        case ereg('^http',$this->endpoint):
3871                                $this->debug('transporting via HTTP');
3872                                if($this->persistentConnection && is_object($this->persistentConnection)){
3873                                        $http =& $this->persistentConnection;
3874                                } else {
3875                                        $http = new soap_transport_http($this->endpoint);
3876                                        // pass encoding into transport layer, so appropriate http headers are sent
3877                                        $http->soap_defencoding = $this->soap_defencoding;
3878                                }
3879                                $http->setSOAPAction($soapaction);
3880                                if($this->proxyhost && $this->proxyport){
3881                                        $http->setProxy($this->proxyhost,$this->proxyport);
3882                                }
3883                if($this->username != '' && $this->password != '') {
3884                                        $http->setCredentials($this->username,$this->password);
3885                                }
3886                                if($this->http_encoding != ''){
3887                                        $http->setEncoding($this->http_encoding);
3888                                }
3889                                $this->debug('sending message, length: '.strlen($msg));
3890                                if(ereg('^http:',$this->endpoint)){
3891                                //if(strpos($this->endpoint,'http:')){
3892                                        $response = $http->send($msg,$timeout);
3893                                } elseif(ereg('^https',$this->endpoint)){
3894                                //} elseif(strpos($this->endpoint,'https:')){
3895                                        //if(phpversion() == '4.3.0-dev'){
3896                                                //$response = $http->send($msg,$timeout);
3897                                //$this->request = $http->outgoing_payload;
3898                                                //$this->response = $http->incoming_payload;
3899                                        //} else
3900                                        if (extension_loaded('curl')) {
3901                                                $response = $http->sendHTTPS($msg,$timeout);
3902                                        } else {
3903                                                $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
3904                                        }                                                               
3905                                } else {
3906                                        $this->setError('no http/s in endpoint url');
3907                                }
3908                                $this->request = $http->outgoing_payload;
3909                                $this->response = $http->incoming_payload;
3910                                $this->debug("transport debug data...\n".$http->debug_str);
3911                                // save transport object if using persistent connections
3912                                if($this->persistentConnection && !is_object($this->persistentConnection)){
3913                                        $this->persistentConnection = $http;
3914                                }
3915                                if($err = $http->getError()){
3916                                        $this->setError('HTTP Error: '.$err);
3917                                        return false;
3918                                } elseif($this->getError()){
3919                                        return false;
3920                                } else {
3921                                        $this->debug('got response, length: '.strlen($response));
3922                                        return $this->parseResponse($response);
3923                                }
3924                        break;
3925                        default:
3926                                $this->setError('no transport found, or selected transport is not yet supported!');
3927                        return false;
3928                        break;
3929                }
3930        }
3931
3932        /**
3933        * processes SOAP message returned from server
3934        *
3935        * @param        string unprocessed response data from server
3936        * @return       mixed value of the message, decoded into a PHP type
3937        * @access   private
3938        */
3939    function parseResponse($data) {
3940                $this->debug('Entering parseResponse(), about to create soap_parser instance');
3941                $parser = new soap_parser($data,$this->xml_encoding,$this->operation);
3942                // if parse errors
3943                if($errstr = $parser->getError()){
3944                        $this->setError( $errstr);
3945                        // destroy the parser object
3946                        unset($parser);
3947                        return false;
3948                } else {
3949                        // get SOAP headers
3950                        $this->responseHeaders = $parser->getHeaders();
3951                        // get decoded message
3952                        $return = $parser->get_response();
3953                        // add parser debug data to our debug
3954                        $this->debug($parser->debug_str);
3955            // add document for doclit support
3956            $this->document = $parser->document;
3957                        // destroy the parser object
3958                        unset($parser);
3959                        // return decode message
3960                        return $return;
3961                }
3962         }
3963
3964        /**
3965        * set the SOAP headers
3966        *
3967        * @param        $headers string XML
3968        * @access   public
3969        */
3970        function setHeaders($headers){
3971                $this->requestHeaders = $headers;
3972        }
3973
3974        /**
3975        * get the response headers
3976        *
3977        * @return       mixed object SOAPx4 soapval object or empty if no headers
3978        * @access   public
3979        */
3980        function getHeaders(){
3981            if($this->responseHeaders != '') {
3982                        return $this->responseHeaders;
3983            }
3984        }
3985
3986        /**
3987        * set proxy info here
3988        *
3989        * @param    string $proxyhost
3990        * @param    string $proxyport
3991        * @access   public
3992        */
3993        function setHTTPProxy($proxyhost, $proxyport) {
3994                $this->proxyhost = $proxyhost;
3995                $this->proxyport = $proxyport;
3996        }
3997
3998        /**
3999        * if authenticating, set user credentials here
4000        *
4001        * @param    string $username
4002        * @param    string $password
4003        * @access   public
4004        */
4005        function setCredentials($username, $password) {
4006                $this->username = $username;
4007                $this->password = $password;
4008        }
4009       
4010        /**
4011        * use HTTP encoding
4012        *
4013        * @param    string $enc
4014        * @access   public
4015        */
4016        function setHTTPEncoding($enc='gzip, deflate'){
4017                $this->http_encoding = $enc;
4018        }
4019       
4020        /**
4021        * use HTTP persistent connections if possible
4022        *
4023        * @access   public
4024        */
4025        function useHTTPPersistentConnection(){
4026                $this->persistentConnection = true;
4027        }
4028       
4029        /**
4030        * gets the default RPC parameter setting.
4031        * If true, default is that call params are like RPC even for document style.
4032        * Each call() can override this value.
4033        *
4034        * @access public
4035        */
4036        function getDefaultRpcParams() {
4037                return $this->defaultRpcParams;
4038        }
4039
4040        /**
4041        * sets the default RPC parameter setting.
4042        * If true, default is that call params are like RPC even for document style
4043        * Each call() can override this value.
4044        *
4045        * @param    boolean $rpcParams
4046        * @access public
4047        */
4048        function setDefaultRpcParams($rpcParams) {
4049                $this->defaultRpcParams = $rpcParams;
4050        }
4051       
4052        /**
4053        * dynamically creates proxy class, allowing user to directly call methods from wsdl
4054        *
4055        * @return   object soap_proxy object
4056        * @access   public
4057        */
4058        function getProxy(){
4059                $evalStr = '';
4060                foreach($this->operations as $operation => $opData){
4061                        if($operation != ''){
4062                                // create param string
4063                                $paramStr = '';
4064                                if(sizeof($opData['input']['parts']) > 0){
4065                                        foreach($opData['input']['parts'] as $name => $type){
4066                                                $paramStr .= "\$$name,";
4067                                        }
4068                                        $paramStr = substr($paramStr,0,strlen($paramStr)-1);
4069                                }
4070                                $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
4071                                $evalStr .= "function $operation ($paramStr){
4072                                        // load params into array
4073                                        \$params = array($paramStr);
4074                                        return \$this->call('$operation',\$params,'".$opData['namespace']."','".$opData['soapAction']."');
4075                                }";
4076                                unset($paramStr);
4077                        }
4078                }
4079                $r = rand();
4080                $evalStr = 'class soap_proxy_'.$r.' extends soapclient {
4081                                '.$evalStr.'
4082                        }';
4083                //print "proxy class:<pre>$evalStr</pre>";
4084                // eval the class
4085                eval($evalStr);
4086                // instantiate proxy object
4087                eval("\$proxy = new soap_proxy_$r('');");
4088                // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
4089                $proxy->endpointType = 'wsdl';
4090                $proxy->wsdlFile = $this->wsdlFile;
4091                $proxy->wsdl = $this->wsdl;
4092                $proxy->operations = $this->operations;
4093                $proxy->defaultRpcParams = $this->defaultRpcParams;
4094                return $proxy;
4095        }
4096}
4097
4098?>