Encore d'autres
[auf_bulletin.git] / lodel-0.9 / scripts / nusoap.php
1 <?php
2
3 /* Modified by Ghislain Picard 01/10/04 */
4
5 /*
6 $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
7
8 NuSOAP - Web Services Toolkit for PHP
9
10 Copyright (c) 2002 NuSphere Corporation
11
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 2.1 of the License, or (at your option) any later version.
16
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
26 If you have any questions or comments, please email:
27
28 Dietrich Ayala
29 dietrich@ganx4.com
30 http://dietrich.ganx4.com/nusoap
31
32 NuSphere Corporation
33 http://www.nusphere.com
34
35 */
36
37 /* load classes
38
39 // necessary classes
40 require_once('class.soapclient.php');
41 require_once('class.soap_val.php');
42 require_once('class.soap_parser.php');
43 require_once('class.soap_fault.php');
44
45 // transport classes
46 require_once('class.soap_transport_http.php');
47
48 // optional add-on classes
49 require_once('class.xmlschema.php');
50 require_once('class.wsdl.php');
51
52 // server class
53 require_once('class.soap_server.php');*/
54
55 /**
56 *
57 * nusoap_base
58 *
59 * @author Dietrich Ayala <dietrich@ganx4.com>
60 * @version $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
61 * @access public
62 */
63 class nusoap_base {
64
65 var $title = 'NuSOAP';
66 var $version = '0.6.8';
67 var $revision = '$Revision: 4994 $';
68 var $error_str = '';
69 var $debug_str = '';
70 // toggles automatic encoding of special characters as entities
71 // (should always be true, I think)
72 var $charencoding = true;
73
74 /**
75 * set schema version
76 *
77 * @var XMLSchemaVersion
78 * @access public
79 */
80 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
81
82 /**
83 * set charset encoding for outgoing messages
84 *
85 * @var soap_defencoding
86 * @access public
87 */
88 //var $soap_defencoding = 'UTF-8';
89 var $soap_defencoding = 'utf-8';
90
91 /**
92 * load namespace uris into an array of uri => prefix
93 *
94 * @var namespaces
95 * @access public
96 */
97 var $namespaces = array(
98 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
99 'xsd' => 'http://www.w3.org/2001/XMLSchema',
100 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
101 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
102 'si' => 'http://soapinterop.org/xsd');
103 var $usedNamespaces = array();
104
105 /**
106 * load types into typemap array
107 * is this legacy yet?
108 * no, this is used by the xmlschema class to verify type => namespace mappings.
109 * @var typemap
110 * @access public
111 */
112 var $typemap = array(
113 'http://www.w3.org/2001/XMLSchema' => array(
114 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
115 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
116 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
117 // abstract "any" types
118 'anyType'=>'string','anySimpleType'=>'string',
119 // derived datatypes
120 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
121 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
122 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
123 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
124 'http://www.w3.org/1999/XMLSchema' => array(
125 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
126 'float'=>'double','dateTime'=>'string',
127 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
128 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
129 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
130 'http://xml.apache.org/xml-soap' => array('Map')
131 );
132
133 /**
134 * entities to convert
135 *
136 * @var xmlEntities
137 * @access public
138 */
139 var $xmlEntities = array('quot' => '"','amp' => '&',
140 'lt' => '<','gt' => '>','apos' => "'");
141
142 /**
143 * adds debug data to the instance debug string with formatting
144 *
145 * @param string $string debug data
146 * @access private
147 */
148 function debug($string){
149 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
150 }
151
152 /**
153 * adds debug data to the instance debug string without formatting
154 *
155 * @param string $string debug data
156 * @access private
157 */
158 function appendDebug($string){
159 // it would be nice to use a memory stream here to use
160 // memory more efficiently
161 $this->debug_str .= $string;
162 }
163
164 /**
165 * clears the current debug data for this instance
166 *
167 * @access public
168 */
169 function clearDebug() {
170 // it would be nice to use a memory stream here to use
171 // memory more efficiently
172 $this->debug_str = '';
173 }
174
175 /**
176 * gets the current debug data for this instance
177 *
178 * @return debug data
179 * @access public
180 */
181 function &getDebug() {
182 // it would be nice to use a memory stream here to use
183 // memory more efficiently
184 return $this->debug_str;
185 }
186
187 /**
188 * gets the current debug data for this instance as an XML comment
189 * this may change the contents of the debug data
190 *
191 * @return debug data as an XML comment
192 * @access public
193 */
194 function &getDebugAsXMLComment() {
195 // it would be nice to use a memory stream here to use
196 // memory more efficiently
197 while (strpos($this->debug_str, '--')) {
198 $this->debug_str = str_replace('--', '- -', $this->debug_str);
199 }
200 return "<!--\n" . $this->debug_str . "\n-->";
201 }
202
203 /**
204 * expands entities, e.g. changes '<' to '&lt;'.
205 *
206 * @param string $val The string in which to expand entities.
207 * @access private
208 */
209 function expandEntities($val) {
210 if ($this->charencoding) {
211 $val = str_replace('&', '&amp;', $val);
212 $val = str_replace("'", '&apos;', $val);
213 $val = str_replace('"', '&quot;', $val);
214 $val = str_replace('<', '&lt;', $val);
215 $val = str_replace('>', '&gt;', $val);
216 }
217 return $val;
218 }
219
220 /**
221 * returns error string if present
222 *
223 * @return mixed error string or false
224 * @access public
225 */
226 function getError(){
227 if($this->error_str != ''){
228 return $this->error_str;
229 }
230 return false;
231 }
232
233 /**
234 * sets error string
235 *
236 * @return boolean $string error string
237 * @access private
238 */
239 function setError($str){
240 $this->error_str = $str;
241 }
242
243 /**
244 * detect if array is a simple array or a struct (associative array)
245 *
246 * @param $val The PHP array
247 * @return string (arraySimple|arrayStruct)
248 * @access private
249 */
250 function isArraySimpleOrStruct($val) {
251 $keyList = array_keys($val);
252 foreach ($keyList as $keyListValue) {
253 if (!is_int($keyListValue)) {
254 return 'arrayStruct';
255 }
256 }
257 return 'arraySimple';
258 }
259
260 /**
261 * serializes PHP values in accordance w/ section 5. Type information is
262 * not serialized if $use == 'literal'.
263 *
264 * @return string
265 * @access public
266 */
267 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
268 if(is_object($val) &&
269 (get_class($val) == 'soapval') ||
270 (gettype($val) == 'object' && get_class($val) == 'servooattachment') ) {
271 return $val->serialize($use);
272 }
273 $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
274 // if no name, use item
275 $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
276 // if name has ns, add ns prefix to name
277 $xmlns = '';
278 if($name_ns) {
279 $prefix = 'nu'.rand(1000,9999);
280 $name = $prefix.':'.$name;
281 $xmlns .= " xmlns:$prefix=\"$name_ns\"";
282 }
283 // if type is prefixed, create type prefix
284 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
285 // need to fix this. shouldn't default to xsd if no ns specified
286 // w/o checking against typemap
287 $type_prefix = 'xsd';
288 } elseif($type_ns){
289 $type_prefix = 'ns'.rand(1000,9999);
290 $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
291 }
292 // serialize attributes if present
293 $atts = '';
294 if($attributes){
295 foreach($attributes as $k => $v){
296 $atts .= " $k=\"$v\"";
297 }
298 }
299 // serialize if an xsd built-in primitive type
300 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
301 if (is_bool($val)) {
302 if ($type == 'boolean') {
303 $val = $val ? 'true' : 'false';
304 } elseif (! $val) {
305 $val = 0;
306 }
307 } else if (is_string($val)) {
308 $val = $this->expandEntities($val);
309 }
310 if ($use == 'literal') {
311 return "<$name$xmlns>$val</$name>";
312 } else {
313 return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>";
314 }
315 }
316 // detect type and serialize
317 $xml = '';
318 switch(true) {
319 case ($type == '' && is_null($val)):
320 if ($use == 'literal') {
321 // TODO: depends on nillable
322 $xml .= "<$name$xmlns/>";
323 } else {
324 $xml .= "<$name$xmlns xsi:nil=\"true\"/>";
325 }
326 break;
327 case (is_bool($val) || $type == 'boolean'):
328 if ($type == 'boolean') {
329 $val = $val ? 'true' : 'false';
330 } elseif (! $val) {
331 $val = 0;
332 }
333 if ($use == 'literal') {
334 $xml .= "<$name$xmlns $atts>$val</$name>";
335 } else {
336 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
337 }
338 break;
339 case (is_int($val) || is_long($val) || $type == 'int'):
340 if ($use == 'literal') {
341 $xml .= "<$name$xmlns $atts>$val</$name>";
342 } else {
343 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
344 }
345 break;
346 case (is_float($val)|| is_double($val) || $type == 'float'):
347 if ($use == 'literal') {
348 $xml .= "<$name$xmlns $atts>$val</$name>";
349 } else {
350 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
351 }
352 break;
353 case (is_string($val) || $type == 'string'):
354 $val = $this->expandEntities($val);
355 if ($use == 'literal') {
356 $xml .= "<$name$xmlns $atts>$val</$name>";
357 } else {
358 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
359 }
360 break;
361 case is_object($val):
362 $name = get_class($val);
363 foreach(get_object_vars($val) as $k => $v){
364 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
365 }
366 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
367 break;
368 break;
369 case (is_array($val) || $type):
370 // detect if struct or array
371 $valueType = $this->isArraySimpleOrStruct($val);
372 if($valueType=='arraySimple' || preg_match('^ArrayOf',$type)){
373 $i = 0;
374 if(is_array($val) && count($val)> 0){
375 foreach($val as $v){
376 if(is_object($v) && get_class($v) == 'soapval'){
377 $tt_ns = $v->type_ns;
378 $tt = $v->type;
379 } elseif (is_array($v)) {
380 $tt = $this->isArraySimpleOrStruct($v);
381 } else {
382 $tt = gettype($v);
383 }
384 $array_types[$tt] = 1;
385 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
386 ++$i;
387 }
388 if(count($array_types) > 1){
389 $array_typename = 'xsd:ur-type';
390 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
391 if ($tt == 'integer') {
392 $tt = 'int';
393 }
394 $array_typename = 'xsd:'.$tt;
395 } elseif(isset($tt) && $tt == 'arraySimple'){
396 $array_typename = 'SOAP-ENC:Array';
397 } elseif(isset($tt) && $tt == 'arrayStruct'){
398 $array_typename = 'unnamed_struct_use_soapval';
399 } else {
400 // if type is prefixed, create type prefix
401 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
402 $array_typename = 'xsd:' . $tt;
403 } elseif ($tt_ns) {
404 $tt_prefix = 'ns' . rand(1000, 9999);
405 $array_typename = "$tt_prefix:$tt";
406 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
407 } else {
408 $array_typename = $tt;
409 }
410 }
411 $array_type = $i;
412 if ($use == 'literal') {
413 $type_str = '';
414 } else if (isset($type) && isset($type_prefix)) {
415 $type_str = " xsi:type=\"$type_prefix:$type\"";
416 } else {
417 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
418 }
419 // empty array
420 } else {
421 if ($use == 'literal') {
422 $type_str = '';
423 } else if (isset($type) && isset($type_prefix)) {
424 $type_str = " xsi:type=\"$type_prefix:$type\"";
425 } else {
426 $type_str = " xsi:type=\"SOAP-ENC:Array\"";
427 }
428 }
429 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
430 } else {
431 // got a struct
432 if(isset($type) && isset($type_prefix)){
433 $type_str = " xsi:type=\"$type_prefix:$type\"";
434 } else {
435 $type_str = '';
436 }
437 if ($use == 'literal') {
438 $xml .= "<$name$xmlns $atts>";
439 } else {
440 $xml .= "<$name$xmlns$type_str$atts>";
441 }
442 foreach($val as $k => $v){
443 // Apache Map
444 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
445 $xml .= '<item>';
446 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
447 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
448 $xml .= '</item>';
449 } else {
450 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
451 }
452 }
453 $xml .= "</$name>";
454 }
455 break;
456 default:
457 $xml .= 'not detected, got '.gettype($val).' for '.$val;
458 break;
459 }
460 return $xml;
461 }
462
463 /**
464 * serialize message
465 *
466 * @param string body
467 * @param string headers optional
468 * @param array namespaces optional
469 * @param string style optional (rpc|document)
470 * @param string use optional (encoded|literal)
471 * @return string message
472 * @access public
473 */
474 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded'){
475 // TODO: add an option to automatically run utf8_encode on $body and $headers
476 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
477 // one to send arbitrary UTF-8 characters, not just characters that map to utf-8
478
479 // serialize namespaces
480 $ns_string = '';
481 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
482 $ns_string .= " xmlns:$k=\"$v\"";
483 }
484 if($style == 'rpc' && $use == 'encoded') {
485 $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
486 }
487
488 // serialize headers
489 if($headers){
490 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
491 }
492 // serialize envelope
493 return
494 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
495 '<SOAP-ENV:Envelope'.$ns_string.">".
496 $headers.
497 "<SOAP-ENV:Body>".
498 $body.
499 "</SOAP-ENV:Body>".
500 "</SOAP-ENV:Envelope>";
501 }
502
503 function formatDump($str){
504 $str = htmlspecialchars($str);
505 return nl2br($str);
506 }
507
508 /**
509 * contracts a qualified name
510 *
511 * @param string $string qname
512 * @return string contracted qname
513 * @access private
514 */
515 function contractQname($qname){
516 // get element namespace
517 //$this->xdebug("Contract $qname");
518 if (strrpos($qname, ':')) {
519 // get unqualified name
520 $name = substr($qname, strrpos($qname, ':') + 1);
521 // get ns
522 $ns = substr($qname, 0, strrpos($qname, ':'));
523 $p = $this->getPrefixFromNamespace($ns);
524 if ($p) {
525 return $p . ':' . $name;
526 }
527 return $qname;
528 } else {
529 return $qname;
530 }
531 }
532
533 /**
534 * expands a qualified name
535 *
536 * @param string $string qname
537 * @return string expanded qname
538 * @access private
539 */
540 function expandQname($qname){
541 // get element prefix
542 if(strpos($qname,':') && !preg_match('^http://',$qname)){
543 // get unqualified name
544 $name = substr(strstr($qname,':'),1);
545 // get ns prefix
546 $prefix = substr($qname,0,strpos($qname,':'));
547 if(isset($this->namespaces[$prefix])){
548 return $this->namespaces[$prefix].':'.$name;
549 } else {
550 return $qname;
551 }
552 } else {
553 return $qname;
554 }
555 }
556
557 /**
558 * returns the local part of a prefixed string
559 * returns the original string, if not prefixed
560 *
561 * @param string
562 * @return string
563 * @access public
564 */
565 function getLocalPart($str){
566 if($sstr = strrchr($str,':')){
567 // get unqualified name
568 return substr( $sstr, 1 );
569 } else {
570 return $str;
571 }
572 }
573
574 /**
575 * returns the prefix part of a prefixed string
576 * returns false, if not prefixed
577 *
578 * @param string
579 * @return mixed
580 * @access public
581 */
582 function getPrefix($str){
583 if($pos = strrpos($str,':')){
584 // get prefix
585 return substr($str,0,$pos);
586 }
587 return false;
588 }
589
590 /**
591 * pass it a prefix, it returns a namespace
592 * returns false if no namespace registered with the given prefix
593 *
594 * @param string
595 * @return mixed
596 * @access public
597 */
598 function getNamespaceFromPrefix($prefix){
599 if (isset($this->namespaces[$prefix])) {
600 return $this->namespaces[$prefix];
601 }
602 //$this->setError("No namespace registered for prefix '$prefix'");
603 return false;
604 }
605
606 /**
607 * returns the prefix for a given namespace (or prefix)
608 * or false if no prefixes registered for the given namespace
609 *
610 * @param string
611 * @return mixed
612 * @access public
613 */
614 function getPrefixFromNamespace($ns) {
615 foreach ($this->namespaces as $p => $n) {
616 if ($ns == $n || $ns == $p) {
617 $this->usedNamespaces[$p] = $n;
618 return $p;
619 }
620 }
621 return false;
622 }
623
624 /**
625 * returns the time in ODBC canonical form with microseconds
626 *
627 * @return string
628 * @access public
629 */
630 function getmicrotime() {
631 if (function_exists('gettimeofday')) {
632 $tod = gettimeofday();
633 $sec = $tod['sec'];
634 $usec = $tod['usec'];
635 } else {
636 $sec = time();
637 $usec = 0;
638 }
639 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
640 }
641
642 function varDump($data) {
643 ob_start();
644 var_dump($data);
645 $ret_val = ob_get_contents();
646 ob_end_clean();
647 return $ret_val;
648 }
649 }
650
651 // XML Schema Datatype Helper Functions
652
653 //xsd:dateTime helpers
654
655 /**
656 * convert unix timestamp to ISO 8601 compliant date string
657 *
658 * @param string $timestamp Unix time stamp
659 * @access public
660 */
661 function timestamp_to_iso8601($timestamp,$utc=true){
662 $datestr = date('Y-m-d\TH:i:sO',$timestamp);
663 if($utc){
664 $pregStr =
665 '([0-9]{4})-'. // centuries & years CCYY-
666 '([0-9]{2})-'. // months MM-
667 '([0-9]{2})'. // days DD
668 'T'. // separator T
669 '([0-9]{2}):'. // hours hh:
670 '([0-9]{2}):'. // minutes mm:
671 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
672 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
673
674 if(preg_match($pregStr,$datestr,$regs)){
675 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
676 }
677 return false;
678 } else {
679 return $datestr;
680 }
681 }
682
683 /**
684 * convert ISO 8601 compliant date string to unix timestamp
685 *
686 * @param string $datestr ISO 8601 compliant date string
687 * @access public
688 */
689 function iso8601_to_timestamp($datestr){
690 $pregStr =
691 '([0-9]{4})-'. // centuries & years CCYY-
692 '([0-9]{2})-'. // months MM-
693 '([0-9]{2})'. // days DD
694 'T'. // separator T
695 '([0-9]{2}):'. // hours hh:
696 '([0-9]{2}):'. // minutes mm:
697 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
698 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
699 if(preg_match($pregStr,$datestr,$regs)){
700 // not utc
701 if($regs[8] != 'Z'){
702 $op = substr($regs[8],0,1);
703 $h = substr($regs[8],1,2);
704 $m = substr($regs[8],strlen($regs[8])-2,2);
705 if($op == '-'){
706 $regs[4] = $regs[4] + $h;
707 $regs[5] = $regs[5] + $m;
708 } elseif($op == '+'){
709 $regs[4] = $regs[4] - $h;
710 $regs[5] = $regs[5] - $m;
711 }
712 }
713 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
714 } else {
715 return false;
716 }
717 }
718
719 function usleepWindows($usec)
720 {
721 $start = gettimeofday();
722
723 do
724 {
725 $stop = gettimeofday();
726 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
727 + $stop['usec'] - $start['usec'];
728 }
729 while ($timePassed < $usec);
730 }
731
732 ?><?php
733
734
735
736 /**
737 * soap_fault class, allows for creation of faults
738 * mainly used for returning faults from deployed functions
739 * in a server instance.
740 * @author Dietrich Ayala <dietrich@ganx4.com>
741 * @version $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
742 * @access public
743 */
744 class soap_fault extends nusoap_base {
745
746 var $faultcode;
747 var $faultactor;
748 var $faultstring;
749 var $faultdetail;
750
751 /**
752 * constructor
753 *
754 * @param string $faultcode (client | server)
755 * @param string $faultactor only used when msg routed between multiple actors
756 * @param string $faultstring human readable error message
757 * @param string $faultdetail
758 */
759 function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
760 $this->faultcode = $faultcode;
761 $this->faultactor = $faultactor;
762 $this->faultstring = $faultstring;
763 $this->faultdetail = $faultdetail;
764 }
765
766 /**
767 * serialize a fault
768 *
769 * @access public
770 */
771 function serialize(){
772 $ns_string = '';
773 foreach($this->namespaces as $k => $v){
774 $ns_string .= "\n xmlns:$k=\"$v\"";
775 }
776 $return_msg =
777 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
778 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
779 '<SOAP-ENV:Body>'.
780 '<SOAP-ENV:Fault>'.
781 '<faultcode>'.$this->expandEntities($this->faultcode).'</faultcode>'.
782 '<faultactor>'.$this->expandEntities($this->faultactor).'</faultactor>'.
783 '<faultstring>'.$this->expandEntities($this->faultstring).'</faultstring>'.
784 '<detail>'.$this->serialize_val($this->faultdetail).'</detail>'.
785 '</SOAP-ENV:Fault>'.
786 '</SOAP-ENV:Body>'.
787 '</SOAP-ENV:Envelope>';
788 return $return_msg;
789 }
790 }
791
792
793
794 ?><?php
795
796
797
798 /**
799 * parses an XML Schema, allows access to it's data, other utility methods
800 * no validation... yet.
801 * very experimental and limited. As is discussed on XML-DEV, I'm one of the people
802 * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
803 * tutorials I refer to :)
804 *
805 * @author Dietrich Ayala <dietrich@ganx4.com>
806 * @version $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
807 * @access public
808 */
809 class XMLSchema extends nusoap_base {
810
811 // files
812 var $schema = '';
813 var $xml = '';
814 // namespaces
815 var $enclosingNamespaces;
816 // schema info
817 var $schemaInfo = array();
818 var $schemaTargetNamespace = '';
819 // types, elements, attributes defined by the schema
820 var $attributes = array();
821 var $complexTypes = array();
822 var $currentComplexType = false;
823 var $elements = array();
824 var $currentElement = false;
825 var $simpleTypes = array();
826 var $currentSimpleType = false;
827 // imports
828 var $imports = array();
829 // parser vars
830 var $parser;
831 var $position = 0;
832 var $depth = 0;
833 var $depth_array = array();
834 var $message = array();
835 var $defaultNamespace = array();
836
837 /**
838 * constructor
839 *
840 * @param string $schema schema document URI
841 * @param string $xml xml document URI
842 * @param string $namespaces namespaces defined in enclosing XML
843 * @access public
844 */
845 function XMLSchema($schema='',$xml='',$namespaces=array()){
846
847 $this->debug('xmlschema class instantiated, inside constructor');
848 // files
849 $this->schema = $schema;
850 $this->xml = $xml;
851
852 // namespaces
853 $this->enclosingNamespaces = $namespaces;
854 $this->namespaces = array_merge($this->namespaces, $namespaces);
855
856 // parse schema file
857 if($schema != ''){
858 $this->debug('initial schema file: '.$schema);
859 $this->parseFile($schema, 'schema');
860 }
861
862 // parse xml file
863 if($xml != ''){
864 $this->debug('initial xml file: '.$xml);
865 $this->parseFile($xml, 'xml');
866 }
867
868 }
869
870 /**
871 * parse an XML file
872 *
873 * @param string $xml, path/URL to XML file
874 * @param string $type, (schema | xml)
875 * @return boolean
876 * @access public
877 */
878 function parseFile($xml,$type){
879 // parse xml file
880 if($xml != ""){
881 $xmlStr = @join("",@file($xml));
882 if($xmlStr == ""){
883 $msg = 'Error reading XML from '.$xml;
884 $this->setError($msg);
885 $this->debug($msg);
886 return false;
887 } else {
888 $this->debug("parsing $xml");
889 $this->parseString($xmlStr,$type);
890 $this->debug("done parsing $xml");
891 return true;
892 }
893 }
894 return false;
895 }
896
897 /**
898 * parse an XML string
899 *
900 * @param string $xml path or URL
901 * @param string $type, (schema|xml)
902 * @access private
903 */
904 function parseString($xml,$type){
905 // parse xml string
906 if($xml != ""){
907
908 // Create an XML parser.
909 $this->parser = xml_parser_create();
910 // Set the options for parsing the XML data.
911 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
912
913 // Set the object for the parser.
914 xml_set_object($this->parser, $this);
915
916 // Set the element handlers for the parser.
917 if($type == "schema"){
918 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
919 xml_set_character_data_handler($this->parser,'schemaCharacterData');
920 } elseif($type == "xml"){
921 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
922 xml_set_character_data_handler($this->parser,'xmlCharacterData');
923 }
924
925 // Parse the XML file.
926 if(!xml_parse($this->parser,$xml,true)){
927 // Display an error message.
928 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
929 xml_get_current_line_number($this->parser),
930 xml_error_string(xml_get_error_code($this->parser))
931 );
932 $this->debug($errstr);
933 $this->debug("XML payload:\n" . $xml);
934 $this->setError($errstr);
935 }
936
937 xml_parser_free($this->parser);
938 } else{
939 $this->debug('no xml passed to parseString()!!');
940 $this->setError('no xml passed to parseString()!!');
941 }
942 }
943
944 /**
945 * start-element handler
946 *
947 * @param string $parser XML parser object
948 * @param string $name element name
949 * @param string $attrs associative array of attributes
950 * @access private
951 */
952 function schemaStartElement($parser, $name, $attrs) {
953
954 // position in the total number of elements, starting from 0
955 $pos = $this->position++;
956 $depth = $this->depth++;
957 // set self as current value for this depth
958 $this->depth_array[$depth] = $pos;
959 $this->message[$pos] = array('cdata' => '');
960 if ($depth > 0) {
961 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
962 } else {
963 $this->defaultNamespace[$pos] = false;
964 }
965
966 // get element prefix
967 if($prefix = $this->getPrefix($name)){
968 // get unqualified name
969 $name = $this->getLocalPart($name);
970 } else {
971 $prefix = '';
972 }
973
974 // loop thru attributes, expanding, and registering namespace declarations
975 if(count($attrs) > 0){
976 foreach($attrs as $k => $v){
977 // if ns declarations, add to class level array of valid namespaces
978 if(preg_match("^xmlns",$k)){
979 //$this->xdebug("$k: $v");
980 //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
981 if($ns_prefix = substr(strrchr($k,':'),1)){
982 //$this->xdebug("Add namespace[$ns_prefix] = $v");
983 $this->namespaces[$ns_prefix] = $v;
984 } else {
985 $this->defaultNamespace[$pos] = $v;
986 if (! $this->getPrefixFromNamespace($v)) {
987 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
988 }
989 }
990 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){
991 $this->XMLSchemaVersion = $v;
992 $this->namespaces['xsi'] = $v.'-instance';
993 }
994 }
995 }
996 foreach($attrs as $k => $v){
997 // expand each attribute
998 $k = strpos($k,':') ? $this->expandQname($k) : $k;
999 $v = strpos($v,':') ? $this->expandQname($v) : $v;
1000 $eAttrs[$k] = $v;
1001 }
1002 $attrs = $eAttrs;
1003 } else {
1004 $attrs = array();
1005 }
1006 // find status, register data
1007 switch($name){
1008 case 'all':
1009 case 'choice':
1010 case 'sequence':
1011 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1012 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1013 if($name == 'all' || $name == 'sequence'){
1014 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1015 }
1016 break;
1017 case 'attribute':
1018 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1019 $this->xdebug("parsing attribute:");
1020 $this->appendDebug($this->varDump($attrs));
1021 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1022 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1023 if (!strpos($v, ':')) {
1024 // no namespace in arrayType attribute value...
1025 if ($this->defaultNamespace[$pos]) {
1026 // ...so use the default
1027 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1028 }
1029 }
1030 }
1031 if(isset($attrs['name'])){
1032 $this->attributes[$attrs['name']] = $attrs;
1033 $aname = $attrs['name'];
1034 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1035 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1036 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1037 } else {
1038 $aname = '';
1039 }
1040 } elseif(isset($attrs['ref'])){
1041 $aname = $attrs['ref'];
1042 $this->attributes[$attrs['ref']] = $attrs;
1043 }
1044
1045 if(isset($this->currentComplexType)){
1046 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1047 } elseif(isset($this->currentElement)){
1048 $this->elements[$this->currentElement]['attrs'][$aname] = $attrs;
1049 }
1050 // arrayType attribute
1051 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1052 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1053 $prefix = $this->getPrefix($aname);
1054 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1055 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1056 } else {
1057 $v = '';
1058 }
1059 if(strpos($v,'[,]')){
1060 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1061 }
1062 $v = substr($v,0,strpos($v,'[')); // clip the []
1063 if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1064 $v = $this->XMLSchemaVersion.':'.$v;
1065 }
1066 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1067 }
1068 break;
1069 case 'complexType':
1070 if(isset($attrs['name'])){
1071 $this->xdebug('processing named complexType '.$attrs['name']);
1072 $this->currentElement = false;
1073 $this->currentComplexType = $attrs['name'];
1074 $this->complexTypes[$this->currentComplexType] = $attrs;
1075 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1076 if(isset($attrs['base']) && preg_match(':Array$',$attrs['base'])){
1077 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1078 } else {
1079 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1080 }
1081 }else{
1082 $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
1083 $this->currentComplexType = $this->currentElement . '_ContainedType';
1084 $this->currentElement = false;
1085 $this->complexTypes[$this->currentComplexType] = $attrs;
1086 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1087 if(isset($attrs['base']) && preg_match(':Array$',$attrs['base'])){
1088 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1089 } else {
1090 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1091 }
1092 }
1093 break;
1094 case 'element':
1095 // elements defined as part of a complex type should
1096 // not really be added to $this->elements, but for some
1097 // reason, they are
1098 if(isset($attrs['type'])){
1099 $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1100 if (! $this->getPrefix($attrs['type'])) {
1101 if ($this->defaultNamespace[$pos]) {
1102 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1103 $this->xdebug('used default namespace to make type ' . $attrs['type']);
1104 }
1105 }
1106 $this->currentElement = $attrs['name'];
1107 $this->elements[ $attrs['name'] ] = $attrs;
1108 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1109 if (!isset($this->elements[ $attrs['name'] ]['form'])) {
1110 $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
1111 }
1112 $ename = $attrs['name'];
1113 } elseif(isset($attrs['ref'])){
1114 $ename = $attrs['ref'];
1115 } else {
1116 $this->xdebug("processing untyped element ".$attrs['name']);
1117 $this->currentElement = $attrs['name'];
1118 $this->elements[ $attrs['name'] ] = $attrs;
1119 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1120 $this->elements[ $attrs['name'] ]['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
1121 if (!isset($this->elements[ $attrs['name'] ]['form'])) {
1122 $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
1123 }
1124 }
1125 if(isset($ename) && $this->currentComplexType){
1126 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1127 }
1128 break;
1129 // we ignore enumeration values
1130 //case 'enumeration':
1131 //break;
1132 case 'import':
1133 if (isset($attrs['schemaLocation'])) {
1134 //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1135 $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1136 } else {
1137 //$this->xdebug('import namespace ' . $attrs['namespace']);
1138 $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1139 if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1140 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1141 }
1142 }
1143 break;
1144 case 'restriction':
1145 //$this->xdebug("in restriction for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1146 if($this->currentElement){
1147 $this->elements[$this->currentElement]['type'] = $attrs['base'];
1148 } elseif($this->currentSimpleType){
1149 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1150 } elseif($this->currentComplexType){
1151 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1152 if(strstr($attrs['base'],':') == ':Array'){
1153 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1154 }
1155 }
1156 break;
1157 case 'schema':
1158 $this->schemaInfo = $attrs;
1159 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1160 if (isset($attrs['targetNamespace'])) {
1161 $this->schemaTargetNamespace = $attrs['targetNamespace'];
1162 }
1163 if (!isset($attrs['elementFormDefault'])) {
1164 $this->schemaInfo['elementFormDefault'] = 'unqualified';
1165 }
1166 break;
1167 case 'simpleType':
1168 if(isset($attrs['name'])){
1169 $this->xdebug("processing simpleType for name " . $attrs['name']);
1170 $this->currentSimpleType = $attrs['name'];
1171 $this->simpleTypes[ $attrs['name'] ] = $attrs;
1172 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1173 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1174 } else {
1175 //echo 'not parsing: '.$name;
1176 //var_dump($attrs);
1177 }
1178 break;
1179 default:
1180 //$this->xdebug("do not have anything to do for element $name");
1181 }
1182 }
1183
1184 /**
1185 * end-element handler
1186 *
1187 * @param string $parser XML parser object
1188 * @param string $name element name
1189 * @access private
1190 */
1191 function schemaEndElement($parser, $name) {
1192 // bring depth down a notch
1193 $this->depth--;
1194 // position of current element is equal to the last value left in depth_array for my depth
1195 if(isset($this->depth_array[$this->depth])){
1196 $pos = $this->depth_array[$this->depth];
1197 }
1198 // move on...
1199 if($name == 'complexType'){
1200 $this->currentComplexType = false;
1201 $this->currentElement = false;
1202 }
1203 if($name == 'element'){
1204 $this->currentElement = false;
1205 }
1206 if($name == 'simpleType'){
1207 $this->currentSimpleType = false;
1208 }
1209 }
1210
1211 /**
1212 * element content handler
1213 *
1214 * @param string $parser XML parser object
1215 * @param string $data element content
1216 * @access private
1217 */
1218 function schemaCharacterData($parser, $data){
1219 $pos = $this->depth_array[$this->depth - 1];
1220 $this->message[$pos]['cdata'] .= $data;
1221 }
1222
1223 /**
1224 * serialize the schema
1225 *
1226 * @access public
1227 */
1228 function serializeSchema(){
1229
1230 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1231 $xml = '';
1232 // imports
1233 if (sizeof($this->imports) > 0) {
1234 foreach($this->imports as $ns => $list) {
1235 foreach ($list as $ii) {
1236 if ($ii['location'] != '') {
1237 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1238 } else {
1239 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1240 }
1241 }
1242 }
1243 }
1244 // complex types
1245 foreach($this->complexTypes as $typeName => $attrs){
1246 $contentStr = '';
1247 // serialize child elements
1248 if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1249 foreach($attrs['elements'] as $element => $eParts){
1250 if(isset($eParts['ref'])){
1251 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1252 } else {
1253 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
1254 }
1255 }
1256 }
1257 // attributes
1258 if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1259 foreach($attrs['attrs'] as $attr => $aParts){
1260 $contentStr .= " <$schemaPrefix:attribute ref=\"".$this->contractQName($aParts['ref']).'"';
1261 if(isset($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1262 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1263 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType']).'"';
1264 }
1265 $contentStr .= "/>\n";
1266 }
1267 }
1268 // if restriction
1269 if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1270 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
1271 }
1272 // compositor obviates complex/simple content
1273 if(isset($attrs['compositor']) && ($attrs['compositor'] != '')){
1274 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
1275 }
1276 // complex or simple content
1277 elseif((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1278 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
1279 }
1280 // finalize complex type
1281 if($contentStr != ''){
1282 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1283 } else {
1284 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1285 }
1286 $xml .= $contentStr;
1287 }
1288 // simple types
1289 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1290 foreach($this->simpleTypes as $typeName => $attr){
1291 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n </$schemaPrefix:simpleType>";
1292 }
1293 }
1294 // elements
1295 if(isset($this->elements) && count($this->elements) > 0){
1296 foreach($this->elements as $element => $eParts){
1297 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1298 }
1299 }
1300 // attributes
1301 if(isset($this->attributes) && count($this->attributes) > 0){
1302 foreach($this->attributes as $attr => $aParts){
1303 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1304 }
1305 }
1306 // finish 'er up
1307 $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
1308 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1309 $el .= " xmlns:$nsp=\"$ns\"\n";
1310 }
1311 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1312 return $xml;
1313 }
1314
1315 /**
1316 * adds debug data to the clas level debug string
1317 *
1318 * @param string $string debug data
1319 * @access private
1320 */
1321 function xdebug($string){
1322 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1323 }
1324
1325 /**
1326 * get the PHP type of a user defined type in the schema
1327 * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1328 * returns false if no type exists, or not w/ the given namespace
1329 * else returns a string that is either a native php type, or 'struct'
1330 *
1331 * @param string $type, name of defined type
1332 * @param string $ns, namespace of type
1333 * @return mixed
1334 * @access public
1335 */
1336 function getPHPType($type,$ns){
1337 if(isset($this->typemap[$ns][$type])){
1338 //print "found type '$type' and ns $ns in typemap<br>";
1339 return $this->typemap[$ns][$type];
1340 } elseif(isset($this->complexTypes[$type])){
1341 //print "getting type '$type' and ns $ns from complexTypes array<br>";
1342 return $this->complexTypes[$type]['phpType'];
1343 }
1344 return false;
1345 }
1346
1347 /**
1348 * returns an array of information about a given type
1349 * returns false if no type exists by the given name
1350 *
1351 * typeDef = array(
1352 * 'elements' => array(), // refs to elements array
1353 * 'restrictionBase' => '',
1354 * 'phpType' => '',
1355 * 'order' => '(sequence|all)',
1356 * 'attrs' => array() // refs to attributes array
1357 * )
1358 *
1359 * @param string
1360 * @return mixed
1361 * @access public
1362 */
1363 function getTypeDef($type){
1364 //$this->debug("in getTypeDef for type $type");
1365 if(isset($this->complexTypes[$type])){
1366 $this->xdebug("in getTypeDef, found complexType $type");
1367 return $this->complexTypes[$type];
1368 } elseif(isset($this->simpleTypes[$type])){
1369 $this->xdebug("in getTypeDef, found simpleType $type");
1370 if (!isset($this->simpleTypes[$type]['phpType'])) {
1371 // get info for type to tack onto the simple type
1372 // TODO: can this ever really apply (i.e. what is a simpleType really?)
1373 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1374 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1375 $etype = $this->getTypeDef($uqType);
1376 if ($etype) {
1377 if (isset($etype['phpType'])) {
1378 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1379 }
1380 if (isset($etype['elements'])) {
1381 $this->simpleTypes[$type]['elements'] = $etype['elements'];
1382 }
1383 }
1384 }
1385 return $this->simpleTypes[$type];
1386 } elseif(isset($this->elements[$type])){
1387 $this->xdebug("in getTypeDef, found element $type");
1388 if (!isset($this->elements[$type]['phpType'])) {
1389 // get info for type to tack onto the element
1390 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1391 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1392 $etype = $this->getTypeDef($uqType);
1393 if ($etype) {
1394 if (isset($etype['phpType'])) {
1395 $this->elements[$type]['phpType'] = $etype['phpType'];
1396 }
1397 if (isset($etype['elements'])) {
1398 $this->elements[$type]['elements'] = $etype['elements'];
1399 }
1400 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1401 $this->elements[$type]['phpType'] = 'scalar';
1402 }
1403 }
1404 return $this->elements[$type];
1405 } elseif(isset($this->attributes[$type])){
1406 $this->xdebug("in getTypeDef, found attribute $type");
1407 return $this->attributes[$type];
1408 }
1409 $this->xdebug("in getTypeDef, did not find $type");
1410 return false;
1411 }
1412
1413 /**
1414 * returns a sample serialization of a given type, or false if no type by the given name
1415 *
1416 * @param string $type, name of type
1417 * @return mixed
1418 * @access public
1419 */
1420 function serializeTypeDef($type){
1421 //print "in sTD() for type $type<br>";
1422 if($typeDef = $this->getTypeDef($type)){
1423 $str .= '<'.$type;
1424 if(is_array($typeDef['attrs'])){
1425 foreach($attrs as $attName => $data){
1426 $str .= " $attName=\"{type = ".$data['type']."}\"";
1427 }
1428 }
1429 $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1430 if(count($typeDef['elements']) > 0){
1431 $str .= ">";
1432 foreach($typeDef['elements'] as $element => $eData){
1433 $str .= $this->serializeTypeDef($element);
1434 }
1435 $str .= "</$type>";
1436 } elseif($typeDef['typeClass'] == 'element') {
1437 $str .= "></$type>";
1438 } else {
1439 $str .= "/>";
1440 }
1441 return $str;
1442 }
1443 return false;
1444 }
1445
1446 /**
1447 * returns HTML form elements that allow a user
1448 * to enter values for creating an instance of the given type.
1449 *
1450 * @param string $name, name for type instance
1451 * @param string $type, name of type
1452 * @return string
1453 * @access public
1454 */
1455 function typeToForm($name,$type){
1456 // get typedef
1457 if($typeDef = $this->getTypeDef($type)){
1458 // if struct
1459 if($typeDef['phpType'] == 'struct'){
1460 $buffer .= '<table>';
1461 foreach($typeDef['elements'] as $child => $childDef){
1462 $buffer .= "
1463 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1464 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1465 }
1466 $buffer .= '</table>';
1467 // if array
1468 } elseif($typeDef['phpType'] == 'array'){
1469 $buffer .= '<table>';
1470 for($i=0;$i < 3; $i++){
1471 $buffer .= "
1472 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1473 <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1474 }
1475 $buffer .= '</table>';
1476 // if scalar
1477 } else {
1478 $buffer .= "<input type='text' name='parameters[$name]'>";
1479 }
1480 } else {
1481 $buffer .= "<input type='text' name='parameters[$name]'>";
1482 }
1483 return $buffer;
1484 }
1485
1486 /**
1487 * adds a complex type to the schema
1488 *
1489 * example: array
1490 *
1491 * addType(
1492 * 'ArrayOfstring',
1493 * 'complexType',
1494 * 'array',
1495 * '',
1496 * 'SOAP-ENC:Array',
1497 * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
1498 * 'xsd:string'
1499 * );
1500 *
1501 * example: PHP associative array ( SOAP Struct )
1502 *
1503 * addType(
1504 * 'SOAPStruct',
1505 * 'complexType',
1506 * 'struct',
1507 * 'all',
1508 * array('myVar'=> array('name'=>'myVar','type'=>'string')
1509 * );
1510 *
1511 * @param name
1512 * @param typeClass (complexType|simpleType|attribute)
1513 * @param phpType: currently supported are array and struct (php assoc array)
1514 * @param compositor (all|sequence|choice)
1515 * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1516 * @param elements = array ( name = array(name=>'',type=>'') )
1517 * @param attrs = array(
1518 * array(
1519 * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
1520 * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
1521 * )
1522 * )
1523 * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
1524 *
1525 */
1526 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1527 $this->complexTypes[$name] = array(
1528 'name' => $name,
1529 'typeClass' => $typeClass,
1530 'phpType' => $phpType,
1531 'compositor'=> $compositor,
1532 'restrictionBase' => $restrictionBase,
1533 'elements' => $elements,
1534 'attrs' => $attrs,
1535 'arrayType' => $arrayType
1536 );
1537
1538 $this->xdebug("addComplexType $name:");
1539 $this->appendDebug($this->varDump($this->complexTypes[$name]));
1540 }
1541
1542 /**
1543 * adds a simple type to the schema
1544 *
1545 * @param name
1546 * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1547 * @param typeClass (simpleType)
1548 * @param phpType: (scalar)
1549 * @see xmlschema
1550 *
1551 */
1552 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
1553 $this->simpleTypes[$name] = array(
1554 'name' => $name,
1555 'typeClass' => $typeClass,
1556 'phpType' => $phpType,
1557 'type' => $restrictionBase
1558 );
1559
1560 $this->xdebug("addSimpleType $name:");
1561 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1562 }
1563 }
1564
1565
1566
1567 ?><?php
1568
1569
1570
1571 /**
1572 * for creating serializable abstractions of native PHP types
1573 * NOTE: this is only really used when WSDL is not available.
1574 *
1575 * @author Dietrich Ayala <dietrich@ganx4.com>
1576 * @version $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
1577 * @access public
1578 */
1579 class soapval extends nusoap_base {
1580 /**
1581 * constructor
1582 *
1583 * @param string $name optional name
1584 * @param string $type optional type name
1585 * @param mixed $value optional value
1586 * @param string $namespace optional namespace of value
1587 * @param string $type_namespace optional namespace of type
1588 * @param array $attributes associative array of attributes to add to element serialization
1589 * @access public
1590 */
1591 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
1592 $this->name = $name;
1593 $this->value = $value;
1594 $this->type = $type;
1595 $this->element_ns = $element_ns;
1596 $this->type_ns = $type_ns;
1597 $this->attributes = $attributes;
1598 }
1599
1600 /**
1601 * return serialized value
1602 *
1603 * @return string XML data
1604 * @access private
1605 */
1606 function serialize($use='encoded') {
1607 return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
1608 }
1609
1610 /**
1611 * decodes a soapval object into a PHP native type
1612 *
1613 * @param object $soapval optional SOAPx4 soapval object, else uses self
1614 * @return mixed
1615 * @access public
1616 */
1617 function decode(){
1618 return $this->value;
1619 }
1620 }
1621
1622
1623
1624 ?><?php
1625
1626
1627
1628 /**
1629 * transport class for sending/receiving data via HTTP and HTTPS
1630 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
1631 *
1632 * @author Dietrich Ayala <dietrich@ganx4.com>
1633 * @version $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
1634 * @access public
1635 */
1636 class soap_transport_http extends nusoap_base {
1637
1638 var $url = '';
1639 var $uri = '';
1640 var $digest_uri = '';
1641 var $scheme = '';
1642 var $host = '';
1643 var $port = '';
1644 var $path = '';
1645 var $request_method = 'POST';
1646 var $protocol_version = '1.0';
1647 var $encoding = '';
1648 var $outgoing_headers = array();
1649 var $incoming_headers = array();
1650 var $outgoing_payload = '';
1651 var $incoming_payload = '';
1652 var $useSOAPAction = true;
1653 var $persistentConnection = false;
1654 var $ch = false; // cURL handle
1655 var $username;
1656 var $password;
1657
1658 /**
1659 * constructor
1660 */
1661 function soap_transport_http($url){
1662 $this->setURL($url);
1663 preg_match('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
1664 $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
1665 }
1666
1667 function setURL($url) {
1668 $this->url = $url;
1669
1670 $u = parse_url($url);
1671 foreach($u as $k => $v){
1672 $this->debug("$k = $v");
1673 $this->$k = $v;
1674 }
1675
1676 // add any GET params to path
1677 if(isset($u['query']) && $u['query'] != ''){
1678 $this->path .= '?' . $u['query'];
1679 }
1680
1681 // set default port
1682 if(!isset($u['port'])){
1683 if($u['scheme'] == 'https'){
1684 $this->port = 443;
1685 } else {
1686 $this->port = 80;
1687 }
1688 }
1689
1690 $this->uri = $this->path;
1691 $this->digest_uri = $this->uri;
1692
1693 // build headers
1694 if (!isset($u['port'])) {
1695 $this->outgoing_headers['Host'] = $this->host;
1696 } else {
1697 $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
1698 }
1699
1700 if (isset($u['user']) && $u['user'] != '') {
1701 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
1702 }
1703 }
1704
1705 function connect($connection_timeout=0,$response_timeout=30){
1706 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
1707 // "regular" socket.
1708 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
1709 // loaded), and until PHP5 stream_get_wrappers is not available.
1710 // if ($this->scheme == 'https') {
1711 // if (version_compare(phpversion(), '4.3.0') >= 0) {
1712 // if (extension_loaded('openssl')) {
1713 // $this->scheme = 'ssl';
1714 // $this->debug('Using SSL over OpenSSL');
1715 // }
1716 // }
1717 // }
1718 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
1719 if ($this->scheme == 'http' || $this->scheme == 'ssl') {
1720 // use persistent connection
1721 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
1722 if (!feof($this->fp)) {
1723 $this->debug('Re-use persistent connection');
1724 return true;
1725 }
1726 fclose($this->fp);
1727 $this->debug('Closed persistent connection at EOF');
1728 }
1729
1730 // munge host if using OpenSSL
1731 if ($this->scheme == 'ssl') {
1732 $host = 'ssl://' . $this->host;
1733 } else {
1734 $host = $this->host;
1735 }
1736 $this->debug('calling fsockopen with host ' . $host);
1737
1738 // open socket
1739 if($connection_timeout > 0){
1740 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
1741 } else {
1742 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
1743 }
1744
1745 // test pointer
1746 if(!$this->fp) {
1747 $msg = 'Couldn\'t open socket connection to server ' . $this->url;
1748 if ($this->errno) {
1749 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
1750 } else {
1751 $msg .= ' prior to connect(). This is often a problem looking up the host name.';
1752 }
1753 $this->debug($msg);
1754 $this->setError($msg);
1755 return false;
1756 }
1757
1758 // set response timeout
1759 socket_set_timeout( $this->fp, $response_timeout);
1760
1761 $this->debug('socket connected');
1762 return true;
1763 } else if ($this->scheme == 'https') {
1764 if (!extension_loaded('curl')) {
1765 $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
1766 return false;
1767 }
1768 $this->debug('connect using https');
1769 // init CURL
1770 $this->ch = curl_init();
1771 // set url
1772 $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
1773 // add path
1774 $hostURL .= $this->path;
1775 curl_setopt($this->ch, CURLOPT_URL, $hostURL);
1776 // ask for headers in the response output
1777 curl_setopt($this->ch, CURLOPT_HEADER, 1);
1778 // ask for the response output as the return value
1779 curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
1780 // encode
1781 // We manage this ourselves through headers and encoding
1782 // if(function_exists('gzuncompress')){
1783 // curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
1784 // }
1785 // persistent connection
1786 if ($this->persistentConnection) {
1787 // The way we send data, we cannot use persistent connections, since
1788 // there will be some "junk" at the end of our request.
1789 //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
1790 $this->persistentConnection = false;
1791 $this->outgoing_headers['Connection'] = 'close';
1792 }
1793 // set timeout (NOTE: cURL does not have separate connection and response timeouts)
1794 if ($connection_timeout != 0) {
1795 curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
1796 }
1797
1798 // recent versions of cURL turn on peer/host checking by default,
1799 // while PHP binaries are not compiled with a default location for the
1800 // CA cert bundle, so disable peer/host checking.
1801 //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
1802 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
1803 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
1804
1805 /*
1806 TODO: support client certificates (thanks Tobias Boes)
1807 curl_setopt($this->ch, CURLOPT_CAINFO, '$pathToPemFiles/rootca.pem');
1808 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
1809 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
1810 curl_setopt($this->ch, CURLOPT_SSLCERT, '$pathToPemFiles/mycert.pem');
1811 curl_setopt($this->ch, CURLOPT_SSLKEY, '$pathToPemFiles/mykey.pem');
1812 curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $passphrase);
1813 */
1814 $this->debug('cURL connection set up');
1815 return true;
1816 } else {
1817 $this->setError('Unknown scheme ' . $this->scheme);
1818 $this->debug('Unknown scheme ' . $this->scheme);
1819 return false;
1820 }
1821 }
1822
1823 /**
1824 * send the SOAP message via HTTP
1825 *
1826 * @param string $data message data
1827 * @param integer $timeout set connection timeout in seconds
1828 * @param integer $response_timeout set response timeout in seconds
1829 * @return string data
1830 * @access public
1831 */
1832 function send($data, $timeout=0, $response_timeout=30) {
1833
1834 $this->debug('entered send() with data of length: '.strlen($data));
1835
1836 $this->tryagain = true;
1837 $tries = 0;
1838 while ($this->tryagain) {
1839 $this->tryagain = false;
1840 if ($tries++ < 2) {
1841 // make connnection
1842 if (!$this->connect($timeout, $response_timeout)){
1843 return false;
1844 }
1845
1846 // send request
1847 if (!$this->sendRequest($data)){
1848 return false;
1849 }
1850
1851 // get response
1852 $respdata = $this->getResponse();
1853 } else {
1854 $this->setError('Too many tries to get an OK response');
1855 }
1856 }
1857 $this->debug('end of send()');
1858 return $respdata;
1859 }
1860
1861
1862 /**
1863 * send the SOAP message via HTTPS 1.0 using CURL
1864 *
1865 * @param string $msg message data
1866 * @param integer $timeout set connection timeout in seconds
1867 * @param integer $response_timeout set response timeout in seconds
1868 * @return string data
1869 * @access public
1870 */
1871 function sendHTTPS($data, $timeout=0, $response_timeout=30) {
1872 return $this->send($data, $timeout, $response_timeout);
1873 }
1874
1875 /**
1876 * if authenticating, set user credentials here
1877 *
1878 * @param string $username
1879 * @param string $password
1880 * @param string $authtype
1881 * @param array $digestRequest
1882 * @access public
1883 */
1884 function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array()) {
1885 global $_SERVER;
1886
1887 $this->debug("Set credentials for authtype $authtype");
1888 // cf. RFC 2617
1889 if ($authtype == 'basic') {
1890 $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$username).':'.$password);
1891 } elseif ($authtype == 'digest') {
1892 if (isset($digestRequest['nonce'])) {
1893 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
1894
1895 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
1896
1897 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
1898 $A1 = $username. ':' . $digestRequest['realm'] . ':' . $password;
1899
1900 // H(A1) = MD5(A1)
1901 $HA1 = md5($A1);
1902
1903 // A2 = Method ":" digest-uri-value
1904 $A2 = 'POST:' . $this->digest_uri;
1905
1906 // H(A2)
1907 $HA2 = md5($A2);
1908
1909 // KD(secret, data) = H(concat(secret, ":", data))
1910 // if qop == auth:
1911 // request-digest = <"> < KD ( H(A1), unq(nonce-value)
1912 // ":" nc-value
1913 // ":" unq(cnonce-value)
1914 // ":" unq(qop-value)
1915 // ":" H(A2)
1916 // ) <">
1917 // if qop is missing,
1918 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
1919
1920 $unhashedDigest = '';
1921 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
1922 $cnonce = $nonce;
1923 if ($digestRequest['qop'] != '') {
1924 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
1925 } else {
1926 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
1927 }
1928
1929 $hashedDigest = md5($unhashedDigest);
1930
1931 $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"';
1932 }
1933 }
1934 $this->username = $username;
1935 $this->password = $password;
1936 $this->authtype = $authtype;
1937 $this->digestRequest = $digestRequest;
1938
1939 if (isset($this->outgoing_headers['Authorization'])) {
1940 $this->debug('Authorization header set: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
1941 } else {
1942 $this->debug('Authorization header not set');
1943 }
1944 }
1945
1946 /**
1947 * set the soapaction value
1948 *
1949 * @param string $soapaction
1950 * @access public
1951 */
1952 function setSOAPAction($soapaction) {
1953 $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
1954 }
1955
1956 /**
1957 * use http encoding
1958 *
1959 * @param string $enc encoding style. supported values: gzip, deflate, or both
1960 * @access public
1961 */
1962 function setEncoding($enc='gzip, deflate'){
1963 $this->protocol_version = '1.1';
1964 $this->outgoing_headers['Accept-Encoding'] = $enc;
1965 if (!isset($this->outgoing_headers['Connection'])) {
1966 $this->outgoing_headers['Connection'] = 'close';
1967 $this->persistentConnection = false;
1968 }
1969 set_magic_quotes_runtime(0);
1970 // deprecated
1971 $this->encoding = $enc;
1972 }
1973
1974 /**
1975 * set proxy info here
1976 *
1977 * @param string $proxyhost
1978 * @param string $proxyport
1979 * @param string $proxyusername
1980 * @param string $proxypassword
1981 * @access public
1982 */
1983 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
1984 $this->uri = $this->url;
1985 $this->host = $proxyhost;
1986 $this->port = $proxyport;
1987 if ($proxyusername != '' && $proxypassword != '') {
1988 $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
1989 }
1990 }
1991
1992 /**
1993 * decode a string that is encoded w/ "chunked' transfer encoding
1994 * as defined in RFC2068 19.4.6
1995 *
1996 * @param string $buffer
1997 * @param string $lb
1998 * @returns string
1999 * @access public
2000 * @deprecated
2001 */
2002 function decodeChunked($buffer, $lb){
2003 // length := 0
2004 $length = 0;
2005 $new = '';
2006
2007 // read chunk-size, chunk-extension (if any) and CRLF
2008 // get the position of the linebreak
2009 $chunkend = strpos($buffer, $lb);
2010 if ($chunkend == FALSE) {
2011 $this->debug('no linebreak found in decodeChunked');
2012 return $new;
2013 }
2014 $temp = substr($buffer,0,$chunkend);
2015 $chunk_size = hexdec( trim($temp) );
2016 $chunkstart = $chunkend + strlen($lb);
2017 // while (chunk-size > 0) {
2018 while ($chunk_size > 0) {
2019 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2020 $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2021
2022 // Just in case we got a broken connection
2023 if ($chunkend == FALSE) {
2024 $chunk = substr($buffer,$chunkstart);
2025 // append chunk-data to entity-body
2026 $new .= $chunk;
2027 $length += strlen($chunk);
2028 break;
2029 }
2030
2031 // read chunk-data and CRLF
2032 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2033 // append chunk-data to entity-body
2034 $new .= $chunk;
2035 // length := length + chunk-size
2036 $length += strlen($chunk);
2037 // read chunk-size and CRLF
2038 $chunkstart = $chunkend + strlen($lb);
2039
2040 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2041 if ($chunkend == FALSE) {
2042 break; //Just in case we got a broken connection
2043 }
2044 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2045 $chunk_size = hexdec( trim($temp) );
2046 $chunkstart = $chunkend;
2047 }
2048 return $new;
2049 }
2050
2051 /*
2052 * Writes payload, including HTTP headers, to $this->outgoing_payload.
2053 */
2054 function buildPayload($data) {
2055 // add content-length header
2056 $this->outgoing_headers['Content-Length'] = strlen($data);
2057
2058 // start building outgoing payload:
2059 $req = "$this->request_method $this->uri HTTP/$this->protocol_version";
2060 $this->debug("HTTP request: $req");
2061 $this->outgoing_payload = "$req\r\n";
2062
2063 // loop thru headers, serializing
2064 foreach($this->outgoing_headers as $k => $v){
2065 $hdr = $k.': '.$v;
2066 $this->debug("HTTP header: $hdr");
2067 $this->outgoing_payload .= "$hdr\r\n";
2068 }
2069
2070 // header/body separator
2071 $this->outgoing_payload .= "\r\n";
2072
2073 // add data
2074 $this->outgoing_payload .= $data;
2075
2076 ### trigger_error($this->outgoing_payload, E_USER_ERROR);
2077 }
2078
2079 function sendRequest($data){
2080 // build payload
2081 $this->buildPayload($data);
2082
2083 if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2084 // send payload
2085 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2086 $this->setError('couldn\'t write message data to socket');
2087 $this->debug('couldn\'t write message data to socket');
2088 return false;
2089 }
2090 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2091 return true;
2092 } else if ($this->scheme == 'https') {
2093 // set payload
2094 // TODO: cURL does say this should only be the verb, and in fact it
2095 // turns out that the URI and HTTP version are appended to this, which
2096 // some servers refuse to work with
2097 //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2098 foreach($this->outgoing_headers as $k => $v){
2099 $curl_headers[] = "$k: $v";
2100 }
2101 curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
2102 if ($this->request_method == "POST") {
2103 curl_setopt($this->ch, CURLOPT_POST, 1);
2104 curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
2105 } else {
2106 }
2107 $this->debug('set cURL payload');
2108 return true;
2109 }
2110 }
2111
2112 function getResponse(){
2113 $this->incoming_payload = '';
2114
2115 if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2116 // loop until headers have been retrieved
2117 $data = '';
2118 while (!isset($lb)){
2119
2120 // We might EOF during header read.
2121 if(feof($this->fp)) {
2122 $this->incoming_payload = $data;
2123 $this->debug('found no headers before EOF after length ' . strlen($data));
2124 $this->debug("received before EOF:\n" . $data);
2125 $this->setError('server failed to send headers');
2126 return false;
2127 }
2128
2129 $tmp = fgets($this->fp, 256);
2130 $tmplen = strlen($tmp);
2131 $this->debug("read line of $tmplen bytes: " . trim($tmp));
2132
2133 if ($tmplen == 0) {
2134 $this->incoming_payload = $data;
2135 $this->debug('socket read of headers timed out after length ' . strlen($data));
2136 $this->debug("read before timeout:\n" . $data);
2137 $this->setError('socket read of headers timed out');
2138 return false;
2139 }
2140
2141 $data .= $tmp;
2142 $pos = strpos($data,"\r\n\r\n");
2143 if($pos > 1){
2144 $lb = "\r\n";
2145 } else {
2146 $pos = strpos($data,"\n\n");
2147 if($pos > 1){
2148 $lb = "\n";
2149 }
2150 }
2151 // remove 100 header
2152 if(isset($lb) && preg_match('^HTTP/1.1 100',$data)){
2153 unset($lb);
2154 $data = '';
2155 }//
2156 }
2157 // store header data
2158 $this->incoming_payload .= $data;
2159 $this->debug('found end of headers after length ' . strlen($data));
2160 // process headers
2161
2162 $header_data = trim(substr($data,0,$pos));
2163 $header_array = explode($lb,$header_data);
2164 $this->incoming_headers = array();
2165 foreach($header_array as $header_line){
2166 $arr = explode(':',$header_line, 2);
2167 if(count($arr) > 1){
2168 $header_name = strtolower(trim($arr[0]));
2169 $this->incoming_headers[$header_name] = trim($arr[1]);
2170 } else if (isset($header_name)) {
2171 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2172 }
2173 }
2174
2175 // loop until msg has been received
2176 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2177 $content_length = 2147483647; // ignore any content-length header
2178 $chunked = true;
2179 $this->debug("want to read chunked content");
2180 } elseif (isset($this->incoming_headers['content-length'])) {
2181 $content_length = $this->incoming_headers['content-length'];
2182 $chunked = false;
2183 $this->debug("want to read content of length $content_length");
2184 } else {
2185 $content_length = 2147483647;
2186 $chunked = false;
2187 $this->debug("want to read content to EOF");
2188 }
2189
2190 $data = '';
2191 do {
2192 if ($chunked) {
2193 $tmp = fgets($this->fp, 256);
2194 $tmplen = strlen($tmp);
2195 $this->debug("read chunk line of $tmplen bytes");
2196 if ($tmplen == 0) {
2197 $this->incoming_payload = $data;
2198 $this->debug('socket read of chunk length timed out after length ' . strlen($data));
2199 $this->debug("read before timeout:\n" . $data);
2200 $this->setError('socket read of chunk length timed out');
2201 return false;
2202 }
2203 $content_length = hexdec(trim($tmp));
2204 $this->debug("chunk length $content_length");
2205 }
2206 $strlen = 0;
2207 while (($strlen < $content_length) && (!feof($this->fp))) {
2208 $readlen = min(8192, $content_length - $strlen);
2209 $tmp = fread($this->fp, $readlen);
2210 $tmplen = strlen($tmp);
2211 $this->debug("read buffer of $tmplen bytes");
2212 if (($tmplen == 0) && (!feof($this->fp))) {
2213 $this->incoming_payload = $data;
2214 $this->debug('socket read of body timed out after length ' . strlen($data));
2215 $this->debug("read before timeout:\n" . $data);
2216 $this->setError('socket read of body timed out');
2217 return false;
2218 }
2219 $strlen += $tmplen;
2220 $data .= $tmp;
2221 }
2222 if ($chunked && ($content_length > 0)) {
2223 $tmp = fgets($this->fp, 256);
2224 $tmplen = strlen($tmp);
2225 $this->debug("read chunk terminator of $tmplen bytes");
2226 if ($tmplen == 0) {
2227 $this->incoming_payload = $data;
2228 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
2229 $this->debug("read before timeout:\n" . $data);
2230 $this->setError('socket read of chunk terminator timed out');
2231 return false;
2232 }
2233 }
2234 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
2235 if (feof($this->fp)) {
2236 $this->debug('read to EOF');
2237 }
2238 $this->debug('read body of length ' . strlen($data));
2239 $this->incoming_payload .= $data;
2240 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
2241
2242 // close filepointer
2243 if(
2244 (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
2245 (! $this->persistentConnection) || feof($this->fp)){
2246 fclose($this->fp);
2247 $this->fp = false;
2248 $this->debug('closed socket');
2249 }
2250
2251 // connection was closed unexpectedly
2252 if($this->incoming_payload == ''){
2253 $this->setError('no response from server');
2254 return false;
2255 }
2256
2257 // decode transfer-encoding
2258 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
2259 // if(!$data = $this->decodeChunked($data, $lb)){
2260 // $this->setError('Decoding of chunked data failed');
2261 // return false;
2262 // }
2263 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
2264 // set decoded payload
2265 // $this->incoming_payload = $header_data.$lb.$lb.$data;
2266 // }
2267
2268 } else if ($this->scheme == 'https') {
2269 // send and receive
2270 $this->debug('send and receive with cURL');
2271 $this->incoming_payload = curl_exec($this->ch);
2272 $data = $this->incoming_payload;
2273
2274 $cErr = curl_error($this->ch);
2275 if ($cErr != '') {
2276 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
2277 foreach(curl_getinfo($this->ch) as $k => $v){
2278 $err .= "$k: $v<br>";
2279 }
2280 $this->debug($err);
2281 $this->setError($err);
2282 curl_close($this->ch);
2283 return false;
2284 } else {
2285 //echo '<pre>';
2286 //var_dump(curl_getinfo($this->ch));
2287 //echo '</pre>';
2288 }
2289 // close curl
2290 $this->debug('No cURL error, closing cURL');
2291 curl_close($this->ch);
2292
2293 // remove 100 header
2294 if (preg_match('^HTTP/1.1 100',$data)) {
2295 if ($pos = strpos($data,"\r\n\r\n")) {
2296 $data = ltrim(substr($data,$pos));
2297 } elseif($pos = strpos($data,"\n\n") ) {
2298 $data = ltrim(substr($data,$pos));
2299 }
2300 }
2301
2302 // separate content from HTTP headers
2303 if ($pos = strpos($data,"\r\n\r\n")) {
2304 $lb = "\r\n";
2305 } elseif( $pos = strpos($data,"\n\n")) {
2306 $lb = "\n";
2307 } else {
2308 $this->debug('no proper separation of headers and document');
2309 $this->setError('no proper separation of headers and document');
2310 return false;
2311 }
2312 $header_data = trim(substr($data,0,$pos));
2313 $header_array = explode($lb,$header_data);
2314 $data = ltrim(substr($data,$pos));
2315 $this->debug('found proper separation of headers and document');
2316 $this->debug('cleaned data, stringlen: '.strlen($data));
2317 // clean headers
2318 foreach ($header_array as $header_line) {
2319 $arr = explode(':',$header_line,2);
2320 if (count($arr) > 1) {
2321 $this->incoming_headers[strtolower(trim($arr[0]))] = trim($arr[1]);
2322 }
2323 }
2324 }
2325
2326 $arr = explode(' ', $header_array[0], 3);
2327 $http_version = $arr[0];
2328 $http_status = intval($arr[1]);
2329 $http_reason = count($arr) > 2 ? $arr[2] : '';
2330
2331 // see if we need to resend the request with http digest authentication
2332 if (isset($this->incoming_headers['location']) && $http_status == 301) {
2333 $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']);
2334 $this->setURL($this->incoming_headers['location']);
2335 $this->tryagain = true;
2336 return false;
2337 }
2338
2339 // see if we need to resend the request with http digest authentication
2340 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
2341 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
2342 if (substr("Digest ", $this->incoming_headers['www-authenticate'])) {
2343 $this->debug('Server wants digest authentication');
2344 // remove "Digest " from our elements
2345 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
2346
2347 // parse elements into array
2348 $digestElements = explode(',', $digestString);
2349 foreach ($digestElements as $val) {
2350 $tempElement = explode('=', trim($val));
2351 $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
2352 }
2353
2354 // should have (at least) qop, realm, nonce
2355 if (isset($digestRequest['nonce'])) {
2356 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
2357 $this->tryagain = true;
2358 return false;
2359 }
2360 }
2361 $this->debug('HTTP authentication failed');
2362 $this->setError('HTTP authentication failed');
2363 return false;
2364 }
2365
2366 if (
2367 ($http_status >= 300 && $http_status <= 307) ||
2368 ($http_status >= 400 && $http_status <= 417) ||
2369 ($http_status >= 501 && $http_status <= 505)
2370 ) {
2371 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
2372 return false;
2373 }
2374
2375 // decode content-encoding
2376 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
2377 if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
2378 // if decoding works, use it. else assume data wasn't gzencoded
2379 if(function_exists('gzinflate')){
2380 //$timer->setMarker('starting decoding of gzip/deflated content');
2381 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
2382 // this means there are no Zlib headers, although there should be
2383 $this->debug('The gzinflate function exists');
2384 $datalen = strlen($data);
2385 if ($this->incoming_headers['content-encoding'] == 'deflate') {
2386 if ($degzdata = @gzinflate($data)) {
2387 $data = $degzdata;
2388 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
2389 if (strlen($data) < $datalen) {
2390 // test for the case that the payload has been compressed twice
2391 $this->debug('The inflated payload is smaller than the gzipped one; try again');
2392 if ($degzdata = @gzinflate($data)) {
2393 $data = $degzdata;
2394 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
2395 }
2396 }
2397 } else {
2398 $this->debug('Error using gzinflate to inflate the payload');
2399 $this->setError('Error using gzinflate to inflate the payload');
2400 }
2401 } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
2402 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
2403 $data = $degzdata;
2404 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
2405 if (strlen($data) < $datalen) {
2406 // test for the case that the payload has been compressed twice
2407 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
2408 if ($degzdata = @gzinflate(substr($data, 10))) {
2409 $data = $degzdata;
2410 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
2411 }
2412 }
2413 } else {
2414 $this->debug('Error using gzinflate to un-gzip the payload');
2415 $this->setError('Error using gzinflate to un-gzip the payload');
2416 }
2417 }
2418 //$timer->setMarker('finished decoding of gzip/deflated content');
2419 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
2420 // set decoded payload
2421 $this->incoming_payload = $header_data.$lb.$lb.$data;
2422 } else {
2423 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
2424 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
2425 }
2426 } else {
2427 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
2428 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
2429 }
2430 } else {
2431 $this->debug('No Content-Encoding header');
2432 }
2433
2434 if(strlen($data) == 0){
2435 $this->debug('no data after headers!');
2436 $this->setError('no data present after HTTP headers');
2437 return false;
2438 }
2439
2440 return $data;
2441 }
2442
2443 function setContentType($type, $charset = false) {
2444 $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
2445 }
2446
2447 function usePersistentConnection(){
2448 if (isset($this->outgoing_headers['Accept-Encoding'])) {
2449 return false;
2450 }
2451 $this->protocol_version = '1.1';
2452 $this->persistentConnection = true;
2453 $this->outgoing_headers['Connection'] = 'Keep-Alive';
2454 return true;
2455 }
2456 }
2457
2458 ?><?php
2459
2460
2461
2462 /**
2463 *
2464 * soap_server allows the user to create a SOAP server
2465 * that is capable of receiving messages and returning responses
2466 *
2467 * NOTE: WSDL functionality is experimental
2468 *
2469 * @author Dietrich Ayala <dietrich@ganx4.com>
2470 * @version $Id: nusoap.php 4994 2010-04-08 10:06:41Z cenou $
2471 * @access public
2472 */
2473 class soap_server extends nusoap_base {
2474 var $headers = array(); // HTTP headers of request
2475 var $request = ''; // HTTP request
2476 var $requestHeaders = ''; // SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
2477 var $document = ''; // SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
2478 var $requestSOAP = ''; // SOAP payload for request (text)
2479 var $methodURI = ''; // requested method namespace URI
2480 var $methodname = ''; // name of method requested
2481 var $methodparams = array(); // method parameters from request
2482 var $xml_encoding = ''; // character set encoding of incoming (request) messages
2483 var $SOAPAction = ''; // SOAP Action from request
2484
2485 var $outgoing_headers = array();// HTTP headers of response
2486 var $response = ''; // HTTP response
2487 var $responseHeaders = ''; // SOAP headers for response (text)
2488 var $responseSOAP = ''; // SOAP payload for response (text)
2489 var $methodreturn = false; // method return to place in response
2490 var $methodreturnisliteralxml = false; // whether $methodreturn is a string of literal XML
2491 var $fault = false; // SOAP fault for response
2492 var $result = 'successful'; // text indication of result (for debugging)
2493
2494 var $operations = array(); // assoc array of operations => opData
2495 var $wsdl = false; // wsdl instance
2496 var $externalWSDLURL = false; // URL for WSDL
2497 var $debug_flag = false; // whether to append debug to response as XML comment
2498
2499 /**
2500 * constructor
2501 * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
2502 *
2503 * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
2504 * @access public
2505 */
2506 function soap_server($wsdl=false){
2507
2508 // turn on debugging?
2509 global $debug;
2510 global $_REQUEST;
2511 global $_SERVER;
2512 global $HTTP_SERVER_VARS;
2513
2514 if (isset($debug)) {
2515 $this->debug_flag = $debug;
2516 } else if (isset($_REQUEST['debug'])) {
2517 $this->debug_flag = $_REQUEST['debug'];
2518 } else if (isset($_SERVER['QUERY_STRING'])) {
2519 $qs = explode('&', $_SERVER['QUERY_STRING']);
2520 foreach ($qs as $v) {
2521 if (substr($v, 0, 6) == 'debug=') {
2522 $this->debug_flag = substr($v, 6);
2523 }
2524 }
2525 } else if (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
2526 $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
2527 foreach ($qs as $v) {
2528 if (substr($v, 0, 6) == 'debug=') {
2529 $this->debug_flag = substr($v, 6);
2530 }
2531 }
2532 }
2533
2534 // wsdl
2535 if($wsdl){
2536 if (is_object($wsdl) && is_a($wsdl, 'wsdl')) {
2537 $this->wsdl = $wsdl;
2538 $this->externalWSDLURL = $this->wsdl->wsdl;
2539 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
2540 } else {
2541 $this->debug('Create wsdl from ' . $wsdl);
2542 $this->wsdl = new wsdl($wsdl);
2543 $this->externalWSDLURL = $wsdl;
2544 }
2545 $this->appendDebug($this->wsdl->getDebug());
2546 $this->wsdl->clearDebug();
2547 if($err = $this->wsdl->getError()){
2548 trigger_error('WSDL ERROR: '.$err, E_USER_ERROR);
2549 }
2550 }
2551 }
2552
2553 /**
2554 * processes request and returns response
2555 *
2556 * @param string $data usually is the value of $HTTP_RAW_POST_DATA
2557 * @access public
2558 */
2559 function service($data){
2560 global $QUERY_STRING;
2561 if(isset($_SERVER['QUERY_STRING'])){
2562 $qs = $_SERVER['QUERY_STRING'];
2563 } elseif(isset($GLOBALS['QUERY_STRING'])){
2564 $qs = $GLOBALS['QUERY_STRING'];
2565 } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
2566 $qs = $QUERY_STRING;
2567 }
2568
2569 if(isset($qs) && preg_match('wsdl', $qs) ){
2570 // This is a request for WSDL
2571 if($this->externalWSDLURL){
2572 if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
2573 header('Location: '.$this->externalWSDLURL);
2574 } else { // assume file
2575 header("Content-Type: text/xml\r\n");
2576 $fp = fopen($this->externalWSDLURL, 'r');
2577 fpassthru($fp);
2578 }
2579 } else {
2580 header("Content-Type: text/xml; charset=utf-8\r\n");
2581 print $this->wsdl->serialize($this->debug_flag);
2582 }
2583 } elseif($data == '' && $this->wsdl){
2584 // print web interface
2585 print $this->wsdl->webDescription();
2586 } else {
2587 // handle the request
2588 $this->parse_request($data);
2589 if (! $this->fault) {
2590 $this->invoke_method();
2591 }
2592 if (! $this->fault) {
2593 $this->serialize_return();
2594 }
2595 $this->send_response();
2596 }
2597 }
2598
2599 /**
2600 * parses HTTP request headers.
2601 *
2602 * The following fields are set by this function (when successful)
2603 *
2604 * headers
2605 * request
2606 * xml_encoding
2607 * SOAPAction
2608 *
2609 * @access private
2610 */
2611 function parse_http_headers() {
2612 global $HTTP_SERVER_VARS;
2613 global $_SERVER;
2614
2615 $this->request = '';
2616 if(function_exists('getallheaders')){
2617 $this->headers = getallheaders();
2618 foreach($this->headers as $k=>$v){
2619 $this->request .= "$k: $v\r\n";
2620 $this->debug("$k: $v");
2621 }
2622 // get SOAPAction header
2623 if(isset($this->headers['SOAPAction'])){
2624 $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']);
2625 }
2626 // get the character encoding of the incoming request
2627 if(strpos($this->headers['Content-Type'],'=')){
2628 $enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1));
2629 if(pregi('^(utf-8|US-ASCII|UTF-8)$',$enc)){
2630 $this->xml_encoding = strtoupper($enc);
2631 } else {
2632 $this->xml_encoding = 'US-ASCII';
2633 }
2634 } else {
2635 // should be US-ASCII for HTTP 1.0 or utf-8 for HTTP 1.1
2636 $this->xml_encoding = 'utf-8';
2637 }
2638 } elseif(isset($_SERVER) && is_array($_SERVER)){
2639 foreach ($_SERVER as $k => $v) {
2640 if (substr($k, 0, 5) == 'HTTP_') {
2641 $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
2642 } else {
2643 $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
2644 }
2645 if ($k == 'Soapaction') {
2646 // get SOAPAction header
2647 $k = 'SOAPAction';
2648 $v = str_replace('"', '', $v);
2649 $v = str_replace('\\', '', $v);
2650 $this->SOAPAction = $v;
2651 } else if ($k == 'Content-Type') {
2652 // get the character encoding of the incoming request
2653 if (strpos($v, '=')) {
2654 $enc = substr(strstr($v, '='), 1);
2655 $enc = str_replace('"', '', $enc);
2656 $enc = str_replace('\\', '', $enc);
2657 if (pregi('^(utf-8|US-ASCII|UTF-8)$', $enc)) {
2658 $this->xml_encoding = strtoupper($enc);
2659 } else {
2660 $this->xml_encoding = 'US-ASCII';
2661 }
2662 } else {
2663 // should be US-ASCII for HTTP 1.0 or utf-8 for HTTP 1.1
2664 $this->xml_encoding = 'utf-8';
2665 }
2666 }
2667 $this->headers[$k] = $v;
2668 $this->request .= "$k: $v\r\n";
2669 $this->debug("$k: $v");
2670 }
2671 } elseif (is_array($HTTP_SERVER_VARS)) {
2672 foreach ($HTTP_SERVER_VARS as $k => $v) {
2673 if (substr($k, 0, 5) == 'HTTP_') {
2674 $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
2675 if ($k == 'Soapaction') {
2676 // get SOAPAction header
2677 $k = 'SOAPAction';
2678 $v = str_replace('"', '', $v);
2679 $v = str_replace('\\', '', $v);
2680 $this->SOAPAction = $v;
2681 } else if ($k == 'Content-Type') {
2682 // get the character encoding of the incoming request
2683 if (strpos($v, '=')) {
2684 $enc = substr(strstr($v, '='), 1);
2685 $enc = str_replace('"', '', $enc);
2686 $enc = str_replace('\\', '', $enc);
2687 if (pregi('^(utf-8|US-ASCII|UTF-8)$', $enc)) {
2688 $this->xml_encoding = strtoupper($enc);
2689 } else {
2690 $this->xml_encoding = 'US-ASCII';
2691 }
2692 } else {
2693 // should be US-ASCII for HTTP 1.0 or utf-8 for HTTP 1.1
2694 $this->xml_encoding = 'utf-8';
2695 }
2696 }
2697 $this->headers[$k] = $v;
2698 $this->request .= "$k: $v\r\n";
2699 $this->debug("$k: $v");
2700 }
2701 }
2702 }
2703 }
2704
2705 /**
2706 * parses a request
2707 *
2708 * The following fields are set by this function (when successful)
2709 *
2710 * headers
2711 * request
2712 * xml_encoding
2713 * SOAPAction
2714 * request
2715 * requestSOAP
2716 * methodURI
2717 * methodname
2718 * methodparams
2719 * requestHeaders