Edgewall Software

Ticket #2756: nusoap15.2.php

File nusoap15.2.php, 137.8 KB (added by anonymous, 6 years ago)

This one has a lot of 0x0D's added when I check with bin compare

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