XCL Web Application Platform 2.5.0
The XoopsCube Legacy Project
Loading...
Searching...
No Matches
nusoap.php
1<?php
2
3/*
4$Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
5
6NuSOAP - Web Services Toolkit for PHP
7
8Copyright (c) 2002 NuSphere Corporation
9
10This library is free software; you can redistribute it and/or
11modify it under the terms of the GNU Lesser General Public
12License as published by the Free Software Foundation; either
13version 2.1 of the License, or (at your option) any later version.
14
15This library is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18Lesser General Public License for more details.
19
20You should have received a copy of the GNU Lesser General Public
21License along with this library; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
24The NuSOAP project home is:
25https://sourceforge.net/projects/nusoap/
26
27The primary support for NuSOAP is the Help forum on the project home page.
28
29If you have any questions or comments, please email:
30
31Dietrich Ayala
32dietrich@ganx4.com
33https://dietrich.ganx4.com/nusoap
34
35NuSphere Corporation
36https://www.nusphere.com
37
38*/
39
40/*
41 * Some of the standards implmented in whole or part by NuSOAP:
42 *
43 * SOAP 1.1 (https://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
44 * WSDL 1.1 (https://www.w3.org/TR/2001/NOTE-wsdl-20010315)
45 * SOAP Messages With Attachments (https://www.w3.org/TR/SOAP-attachments)
46 * XML 1.0 (https://www.w3.org/TR/2006/REC-xml-20060816/)
47 * Namespaces in XML 1.0 (https://www.w3.org/TR/2006/REC-xml-names-20060816/)
48 * XML Schema 1.0 (https://www.w3.org/TR/xmlschema-0/)
49 * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
50 * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
51 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
52 */
53
54/* load classes
55
56// necessary classes
57require_once('class.soapclient.php');
58require_once('class.soap_val.php');
59require_once('class.soap_parser.php');
60require_once('class.soap_fault.php');
61
62// transport classes
63require_once('class.soap_transport_http.php');
64
65// optional add-on classes
66require_once('class.xmlschema.php');
67require_once('class.wsdl.php');
68
69// server class
70require_once('class.soap_server.php');*/
71
72// class variable emulation
73// cf. https://www.webkreator.com/php/techniques/php-static-class-variables.html
74$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
75
86{
93 public $title = 'NuSOAP';
100 public $version = '0.9.5';
107 public $revision = '$Revision: 1.123 $';
114 public $error_str = '';
121 public $debug_str = '';
129 public $charencoding = true;
136 public $debugLevel;
137
144 public $XMLSchemaVersion = 'https://www.w3.org/2001/XMLSchema';
145
152 public $soap_defencoding = 'UTF-8';
153 //var $soap_defencoding = 'UTF-8';
154
163 public $namespaces = [
164 'SOAP-ENV' => 'https://schemas.xmlsoap.org/soap/envelope/',
165 'xsd' => 'https://www.w3.org/2001/XMLSchema',
166 'xsi' => 'https://www.w3.org/2001/XMLSchema-instance',
167 'SOAP-ENC' => 'https://schemas.xmlsoap.org/soap/encoding/'
168 ];
169
176 public $usedNamespaces = [];
177
185 public $typemap = [
186 'https://www.w3.org/2001/XMLSchema' => [
187 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
188 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
189 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
190 // abstract "any" types
191 'anyType'=>'string','anySimpleType'=>'string',
192 // derived datatypes
193 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
194 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
195 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
196 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''
197 ],
198 'https://www.w3.org/2000/10/XMLSchema' => [
199 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
200 'float'=>'double','dateTime'=>'string',
201 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'
202 ],
203 'https://www.w3.org/1999/XMLSchema' => [
204 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
205 'float'=>'double','dateTime'=>'string',
206 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'
207 ],
208 'https://soapinterop.org/xsd' => ['SOAPStruct' =>'struct'],
209 'https://schemas.xmlsoap.org/soap/encoding/' => ['base64' =>'string', 'array' =>'array', 'Array' =>'array'],
210 'https://xml.apache.org/xml-soap' => ['Map']
211 ];
212
221 public $xmlEntities = [
222 'quot' => '"', 'amp' => '&',
223 'lt' => '<', 'gt' => '>', 'apos' => "'"
224 ];
225
231 public function __construct()
232 {
233 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
234 }
235
242 public function getGlobalDebugLevel()
243 {
244 return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
245 }
246
253 public function setGlobalDebugLevel($level)
254 {
255 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
256 }
257
264 public function getDebugLevel()
265 {
266 return $this->debugLevel;
267 }
268
275 public function setDebugLevel($level)
276 {
277 $this->debugLevel = $level;
278 }
279
286 public function debug($string)
287 {
288 if ($this->debugLevel > 0) {
289 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
290 }
291 }
292
299 public function appendDebug($string)
300 {
301 if ($this->debugLevel > 0) {
302 // it would be nice to use a memory stream here to use
303 // memory more efficiently
304 $this->debug_str .= $string;
305 }
306 }
307
313 public function clearDebug()
314 {
315 // it would be nice to use a memory stream here to use
316 // memory more efficiently
317 $this->debug_str = '';
318 }
319
326 public function &getDebug()
327 {
328 // it would be nice to use a memory stream here to use
329 // memory more efficiently
330 return $this->debug_str;
331 }
332
340 public function &getDebugAsXMLComment()
341 {
342 // it would be nice to use a memory stream here to use
343 // memory more efficiently
344 while (strpos($this->debug_str, '--')) {
345 $this->debug_str = str_replace('--', '- -', $this->debug_str);
346 }
347 $ret = "<!--\n" . $this->debug_str . "\n-->";
348 return $ret;
349 }
350
358 public function expandEntities($val)
359 {
360 if ($this->charencoding) {
361 $val = str_replace('&', '&amp;', $val);
362 $val = str_replace("'", '&apos;', $val);
363 $val = str_replace('"', '&quot;', $val);
364 $val = str_replace('<', '&lt;', $val);
365 $val = str_replace('>', '&gt;', $val);
366 }
367 return $val;
368 }
369
376 public function getError()
377 {
378 if ('' != $this->error_str) {
379 return $this->error_str;
380 }
381 return false;
382 }
383
391 public function setError($str)
392 {
393 $this->error_str = $str;
394 }
395
403 public function isArraySimpleOrStruct($val)
404 {
405 $keyList = array_keys($val);
406 foreach ($keyList as $keyListValue) {
407 if (!is_int($keyListValue)) {
408 return 'arrayStruct';
409 }
410 }
411 return 'arraySimple';
412 }
413
429 public function serialize_val($val, $name=false, $type=false, $name_ns=false, $type_ns=false, $attributes=false, $use='encoded', $soapval=false)
430 {
431 $tt_ns = null;
432 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
433 $this->appendDebug('value=' . $this->varDump($val));
434 $this->appendDebug('attributes=' . $this->varDump($attributes));
435
436 if (is_object($val) && 'soapval' == get_class($val) && (! $soapval)) {
437 $this->debug('serialize_val: serialize soapval');
438 $xml = $val->serialize($use);
439 $this->appendDebug($val->getDebug());
440 $val->clearDebug();
441 $this->debug("serialize_val of soapval returning $xml");
442 return $xml;
443 }
444 // force valid name if necessary
445 if (is_numeric($name)) {
446 $name = '__numeric_' . $name;
447 } elseif (! $name) {
448 $name = 'noname';
449 }
450 // if name has ns, add ns prefix to name
451 $xmlns = '';
452 if ($name_ns) {
453 $prefix = 'nu' . random_int(1000, 9999);
454 $name = $prefix.':'.$name;
455 $xmlns .= " xmlns:$prefix=\"$name_ns\"";
456 }
457 // if type is prefixed, create type prefix
458 if ('' != $type_ns && $type_ns == $this->namespaces['xsd']) {
459 // need to fix this. shouldn't default to xsd if no ns specified
460 // w/o checking against typemap
461 $type_prefix = 'xsd';
462 } elseif ($type_ns) {
463 $type_prefix = 'ns' . random_int(1000, 9999);
464 $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
465 }
466 // serialize attributes if present
467 $atts = '';
468 if ($attributes) {
469 foreach ($attributes as $k => $v) {
470 $atts .= " $k=\"".$this->expandEntities($v).'"';
471 }
472 }
473 // serialize null value
474 if (null === $val) {
475 $this->debug('serialize_val: serialize null');
476 if ('literal' == $use) {
477 // TODO: depends on minOccurs
478 $xml = "<$name$xmlns$atts/>";
479 $this->debug("serialize_val returning $xml");
480 return $xml;
481 } else {
482 if (isset($type) && isset($type_prefix)) {
483 $type_str = " xsi:type=\"$type_prefix:$type\"";
484 } else {
485 $type_str = '';
486 }
487 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
488 $this->debug("serialize_val returning $xml");
489 return $xml;
490 }
491 }
492 // serialize if an xsd built-in primitive type
493 if ('' != $type && isset($this->typemap[$this->XMLSchemaVersion][$type])) {
494 $this->debug('serialize_val: serialize xsd built-in primitive type');
495 if (is_bool($val)) {
496 if ('boolean' == $type) {
497 $val = $val ? 'true' : 'false';
498 } elseif (! $val) {
499 $val = 0;
500 }
501 } elseif (is_string($val)) {
502 $val = $this->expandEntities($val);
503 }
504 if ('literal' == $use) {
505 $xml = "<$name$xmlns$atts>$val</$name>";
506 $this->debug("serialize_val returning $xml");
507 return $xml;
508 } else {
509 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
510 $this->debug("serialize_val returning $xml");
511 return $xml;
512 }
513 }
514 // detect type and serialize
515 $xml = '';
516 switch (true) {
517 case (is_bool($val) || 'boolean' == $type):
518 $this->debug('serialize_val: serialize boolean');
519 if ('boolean' == $type) {
520 $val = $val ? 'true' : 'false';
521 } elseif (! $val) {
522 $val = 0;
523 }
524 if ('literal' == $use) {
525 $xml .= "<$name$xmlns$atts>$val</$name>";
526 } else {
527 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
528 }
529 break;
530 case (is_int($val) || is_int($val) || 'int' == $type):
531 $this->debug('serialize_val: serialize int');
532 if ('literal' == $use) {
533 $xml .= "<$name$xmlns$atts>$val</$name>";
534 } else {
535 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
536 }
537 break;
538 case (is_float($val) || is_float($val) || 'float' == $type):
539 $this->debug('serialize_val: serialize float');
540 if ('literal' == $use) {
541 $xml .= "<$name$xmlns$atts>$val</$name>";
542 } else {
543 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
544 }
545 break;
546 case (is_string($val) || 'string' == $type):
547 $this->debug('serialize_val: serialize string');
548 $val = $this->expandEntities($val);
549 if ('literal' == $use) {
550 $xml .= "<$name$xmlns$atts>$val</$name>";
551 } else {
552 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
553 }
554 break;
555 case is_object($val):
556 $this->debug('serialize_val: serialize object');
557 if ('soapval' == get_class($val)) {
558 $this->debug('serialize_val: serialize soapval object');
559 $pXml = $val->serialize($use);
560 $this->appendDebug($val->getDebug());
561 $val->clearDebug();
562 } else {
563 if (! $name) {
564 $name = get_class($val);
565 $this->debug("In serialize_val, used class name $name as element name");
566 } else {
567 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
568 }
569 foreach (get_object_vars($val) as $k => $v) {
570 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use);
571 }
572 }
573 if (isset($type) && isset($type_prefix)) {
574 $type_str = " xsi:type=\"$type_prefix:$type\"";
575 } else {
576 $type_str = '';
577 }
578 if ('literal' == $use) {
579 $xml .= "<$name$xmlns$atts>$pXml</$name>";
580 } else {
581 $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
582 }
583 break;
584 break;
585 case (is_array($val) || $type):
586 // detect if struct or array
587 $valueType = $this->isArraySimpleOrStruct($val);
588 if ('arraySimple' == $valueType || preg_match('/^ArrayOf/', $type)) {
589 $this->debug('serialize_val: serialize array');
590 $i = 0;
591 if (is_array($val) && count($val)> 0) {
592 foreach ($val as $v) {
593 if (is_object($v) && 'soapval' == get_class($v)) {
594 $tt_ns = $v->type_ns;
595 $tt = $v->type;
596 } elseif (is_array($v)) {
597 $tt = $this->isArraySimpleOrStruct($v);
598 } else {
599 $tt = gettype($v);
600 }
601 $array_types[$tt] = 1;
602 // TODO: for literal, the name should be $name
603 $xml .= $this->serialize_val($v, 'item', false, false, false, false, $use);
604 ++$i;
605 }
606 if (count($array_types) > 1) {
607 $array_typename = 'xsd:anyType';
608 } elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
609 if ('integer' == $tt) {
610 $tt = 'int';
611 }
612 $array_typename = 'xsd:'.$tt;
613 } elseif (isset($tt) && 'arraySimple' == $tt) {
614 $array_typename = 'SOAP-ENC:Array';
615 } elseif (isset($tt) && 'arrayStruct' == $tt) {
616 $array_typename = 'unnamed_struct_use_soapval';
617 } else {
618 // if type is prefixed, create type prefix
619 if ('' != $tt_ns && $tt_ns == $this->namespaces['xsd']) {
620 $array_typename = 'xsd:' . $tt;
621 } elseif ($tt_ns) {
622 $tt_prefix = 'ns' . random_int(1000, 9999);
623 $array_typename = "$tt_prefix:$tt";
624 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
625 } else {
626 $array_typename = $tt;
627 }
628 }
629 $array_type = $i;
630 if ('literal' == $use) {
631 $type_str = '';
632 } elseif (isset($type) && isset($type_prefix)) {
633 $type_str = " xsi:type=\"$type_prefix:$type\"";
634 } else {
635 $type_str = ' xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="' . $array_typename . "[$array_type]\"";
636 }
637 // empty array
638 } else {
639 if ('literal' == $use) {
640 $type_str = '';
641 } elseif (isset($type) && isset($type_prefix)) {
642 $type_str = " xsi:type=\"$type_prefix:$type\"";
643 } else {
644 $type_str = ' xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="xsd:anyType[0]"';
645 }
646 }
647 // TODO: for array in literal, there is no wrapper here
648 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
649 } else {
650 // got a struct
651 $this->debug('serialize_val: serialize struct');
652 if (isset($type) && isset($type_prefix)) {
653 $type_str = " xsi:type=\"$type_prefix:$type\"";
654 } else {
655 $type_str = '';
656 }
657 if ('literal' == $use) {
658 $xml .= "<$name$xmlns$atts>";
659 } else {
660 $xml .= "<$name$xmlns$type_str$atts>";
661 }
662 foreach ($val as $k => $v) {
663 // Apache Map
664 if ('Map' == $type && 'https://xml.apache.org/xml-soap' == $type_ns) {
665 $xml .= '<item>';
666 $xml .= $this->serialize_val($k, 'key', false, false, false, false, $use);
667 $xml .= $this->serialize_val($v, 'value', false, false, false, false, $use);
668 $xml .= '</item>';
669 } else {
670 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
671 }
672 }
673 $xml .= "</$name>";
674 }
675 break;
676 default:
677 $this->debug('serialize_val: serialize unknown');
678 $xml .= 'not detected, got '.gettype($val).' for '.$val;
679 break;
680 }
681 $this->debug("serialize_val returning $xml");
682 return $xml;
683 }
684
697 public function serializeEnvelope($body, $headers=false, $namespaces= [], $style='rpc', $use='encoded', $encodingStyle='https://schemas.xmlsoap.org/soap/encoding/')
698 {
699 // TODO: add an option to automatically run utf8_encode on $body and $headers
700 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
701 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
702
703 $this->debug('In serializeEnvelope length=' . strlen($body) . ' body (max 1000 characters)=' . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
704 $this->debug('headers:');
705 $this->appendDebug($this->varDump($headers));
706 $this->debug('namespaces:');
707 $this->appendDebug($this->varDump($namespaces));
708
709 // serialize namespaces
710 $ns_string = '';
711 foreach (array_merge($this->namespaces, $namespaces) as $k => $v) {
712 $ns_string .= " xmlns:$k=\"$v\"";
713 }
714 if ($encodingStyle) {
715 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
716 }
717
718 // serialize headers
719 if ($headers) {
720 if (is_array($headers)) {
721 $xml = '';
722 foreach ($headers as $k => $v) {
723 if (is_object($v) && 'soapval' == get_class($v)) {
724 $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
725 } else {
726 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
727 }
728 }
729 $headers = $xml;
730 $this->debug("In serializeEnvelope, serialized array of headers to $headers");
731 }
732 $headers = '<SOAP-ENV:Header>' . $headers . '</SOAP-ENV:Header>';
733 }
734 // serialize envelope
735 return
736 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?' . '>' .
737 '<SOAP-ENV:Envelope'.$ns_string . '>' .
738 $headers. '<SOAP-ENV:Body>' .
739 $body. '</SOAP-ENV:Body>' . '</SOAP-ENV:Envelope>';
740 }
741
750 public function formatDump($str)
751 {
752 $str = htmlspecialchars($str);
753 return nl2br($str);
754 }
755
763 public function contractQname($qname)
764 {
765 // get element namespace
766 //$this->xdebug("Contract $qname");
767 if (strrpos($qname, ':')) {
768 // get unqualified name
769 $name = substr($qname, strrpos($qname, ':') + 1);
770 // get ns
771 $ns = substr($qname, 0, strrpos($qname, ':'));
772 $p = $this->getPrefixFromNamespace($ns);
773 if ($p) {
774 return $p . ':' . $name;
775 }
776 return $qname;
777 } else {
778 return $qname;
779 }
780 }
781
789 public function expandQname($qname)
790 {
791 // get element prefix
792 if (strpos($qname, ':') && !preg_match('/^http:\/\//', $qname)) {
793 // get unqualified name
794 $name = substr(strstr($qname, ':'), 1);
795 // get ns prefix
796 $prefix = substr($qname, 0, strpos($qname, ':'));
797 if (isset($this->namespaces[$prefix])) {
798 return $this->namespaces[$prefix].':'.$name;
799 } else {
800 return $qname;
801 }
802 } else {
803 return $qname;
804 }
805 }
806
815 public function getLocalPart($str)
816 {
817 if ($sstr = strrchr($str, ':')) {
818 // get unqualified name
819 return substr($sstr, 1);
820 } else {
821 return $str;
822 }
823 }
824
833 public function getPrefix($str)
834 {
835 if ($pos = strrpos($str, ':')) {
836 // get prefix
837 return substr($str, 0, $pos);
838 }
839 return false;
840 }
841
849 public function getNamespaceFromPrefix($prefix)
850 {
851 if (isset($this->namespaces[$prefix])) {
852 return $this->namespaces[$prefix];
853 }
854 //$this->setError("No namespace registered for prefix '$prefix'");
855 return false;
856 }
857
866 public function getPrefixFromNamespace($ns)
867 {
868 foreach ($this->namespaces as $p => $n) {
869 if ($ns == $n || $ns == $p) {
870 $this->usedNamespaces[$p] = $n;
871 return $p;
872 }
873 }
874 return false;
875 }
876
883 public function getmicrotime()
884 {
885 if (function_exists('gettimeofday')) {
886 $tod = gettimeofday();
887 $sec = $tod['sec'];
888 $usec = $tod['usec'];
889 } else {
890 $sec = time();
891 $usec = 0;
892 }
893 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
894 }
895
903 public function varDump($data)
904 {
905 ob_start();
906 var_dump($data);
907 $ret_val = ob_get_contents();
908 ob_end_clean();
909 return $ret_val;
910 }
911
918 public function __toString()
919 {
920 return $this->varDump($this);
921 }
922}
923
924// XML Schema Datatype Helper Functions
925
926//xsd:dateTime helpers
927
936function timestamp_to_iso8601($timestamp, $utc=true)
937{
938 $datestr = date('Y-m-d\TH:i:sO', $timestamp);
939 $pos = strrpos($datestr, '+');
940 if (false === $pos) {
941 $pos = strrpos($datestr, '-');
942 }
943 if (false !== $pos) {
944 if (strlen($datestr) == $pos + 5) {
945 $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
946 }
947 }
948 if ($utc) {
949 $pattern = '/'.
950 '([0-9]{4})-'. // centuries & years CCYY-
951 '([0-9]{2})-'. // months MM-
952 '([0-9]{2})'. // days DD
953 'T'. // separator T
954 '([0-9]{2}):'. // hours hh:
955 '([0-9]{2}):'. // minutes mm:
956 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
957 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
958 '/';
959
960 if (preg_match($pattern, $datestr, $regs)) {
961 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
962 }
963 return false;
964 } else {
965 return $datestr;
966 }
967}
968
976function iso8601_to_timestamp($datestr)
977{
978 $pattern = '/'.
979 '([0-9]{4})-'. // centuries & years CCYY-
980 '([0-9]{2})-'. // months MM-
981 '([0-9]{2})'. // days DD
982 'T'. // separator T
983 '([0-9]{2}):'. // hours hh:
984 '([0-9]{2}):'. // minutes mm:
985 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
986 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
987 '/';
988 if (preg_match($pattern, $datestr, $regs)) {
989 // not utc
990 if ('Z' != $regs[8]) {
991 $op = substr($regs[8], 0, 1);
992 $h = substr($regs[8], 1, 2);
993 $m = substr($regs[8], strlen($regs[8])-2, 2);
994 if ('-' == $op) {
995 $regs[4] = $regs[4] + $h;
996 $regs[5] = $regs[5] + $m;
997 } elseif ('+' == $op) {
998 $regs[4] = $regs[4] - $h;
999 $regs[5] = $regs[5] - $m;
1000 }
1001 }
1002 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1003// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
1004 } else {
1005 return false;
1006 }
1007}
1008
1016function usleepWindows($usec)
1017{
1018 $start = gettimeofday();
1019
1020 do {
1021 $stop = gettimeofday();
1022 $timePassed = 1_000_000 * ($stop['sec'] - $start['sec'])
1023 + $stop['usec'] - $start['usec'];
1024 } while ($timePassed < $usec);
1025}
1026
1027?><?php
1028
1029
1030
1040{
1046 public $faultcode;
1052 public $faultactor;
1058 public $faultstring;
1064 public $faultdetail;
1065
1074 public function __construct($faultcode, $faultactor='', $faultstring='', $faultdetail='')
1075 {
1076 parent::__construct();
1077 $this->faultcode = $faultcode;
1078 $this->faultactor = $faultactor;
1079 $this->faultstring = $faultstring;
1080 $this->faultdetail = $faultdetail;
1081 }
1082
1089 public function serialize()
1090 {
1091 $ns_string = '';
1092 foreach ($this->namespaces as $k => $v) {
1093 $ns_string .= "\n xmlns:$k=\"$v\"";
1094 }
1095 $return_msg =
1096 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1097 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="https://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1098 '<SOAP-ENV:Body>'.
1099 '<SOAP-ENV:Fault>'.
1100 $this->serialize_val($this->faultcode, 'faultcode').
1101 $this->serialize_val($this->faultactor, 'faultactor').
1102 $this->serialize_val($this->faultstring, 'faultstring').
1103 $this->serialize_val($this->faultdetail, 'detail').
1104 '</SOAP-ENV:Fault>'.
1105 '</SOAP-ENV:Body>'.
1106 '</SOAP-ENV:Envelope>';
1107 return $return_msg;
1108 }
1109}
1110
1115{
1116}
1117
1118?><?php
1119
1120
1121
1132{
1133
1134 // files
1135 public $schema = '';
1136 public $xml = '';
1137 // namespaces
1138 public $enclosingNamespaces;
1139 // schema info
1140 public $schemaInfo = [];
1141 public $schemaTargetNamespace = '';
1142 // types, elements, attributes defined by the schema
1143 public $attributes = [];
1144 public $complexTypes = [];
1145 public $complexTypeStack = [];
1146 public $currentComplexType = null;
1147 public $elements = [];
1148 public $elementStack = [];
1149 public $currentElement = null;
1150 public $simpleTypes = [];
1151 public $simpleTypeStack = [];
1152 public $currentSimpleType = null;
1153 // imports
1154 public $imports = [];
1155 // parser vars
1156 public $parser;
1157 public $position = 0;
1158 public $depth = 0;
1159 public $depth_array = [];
1160 public $message = [];
1161 public $defaultNamespace = [];
1162
1171 public function __construct($schema='', $xml='', $namespaces= [])
1172 {
1173 parent::__construct();
1174 $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1175 // files
1176 $this->schema = $schema;
1177 $this->xml = $xml;
1178
1179 // namespaces
1180 $this->enclosingNamespaces = $namespaces;
1181 $this->namespaces = array_merge($this->namespaces, $namespaces);
1182
1183 // parse schema file
1184 if ('' != $schema) {
1185 $this->debug('initial schema file: '.$schema);
1186 $this->parseFile($schema, 'schema');
1187 }
1188
1189 // parse xml file
1190 if ('' != $xml) {
1191 $this->debug('initial xml file: '.$xml);
1192 $this->parseFile($xml, 'xml');
1193 }
1194 }
1195
1204 public function parseFile($xml, $type)
1205 {
1206 // parse xml file
1207 if ('' != $xml) {
1208 $xmlStr = @implode('', @file($xml));
1209 if ('' == $xmlStr) {
1210 $msg = 'Error reading XML from '.$xml;
1211 $this->setError($msg);
1212 $this->debug($msg);
1213 return false;
1214 } else {
1215 $this->debug("parsing $xml");
1216 $this->parseString($xmlStr, $type);
1217 $this->debug("done parsing $xml");
1218 return true;
1219 }
1220 }
1221 return false;
1222 }
1223
1231 public function parseString($xml, $type)
1232 {
1233 // parse xml string
1234 if ('' != $xml) {
1235
1236 // Create an XML parser.
1237 $this->parser = xml_parser_create();
1238 // Set the options for parsing the XML data.
1239 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1240
1241 // Set the object for the parser.
1242 xml_set_object($this->parser, $this);
1243
1244 // Set the element handlers for the parser.
1245 if ('schema' == $type) {
1246 xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
1247 xml_set_character_data_handler($this->parser, 'schemaCharacterData');
1248 } elseif ('xml' == $type) {
1249 xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
1250 xml_set_character_data_handler($this->parser, 'xmlCharacterData');
1251 }
1252
1253 // Parse the XML file.
1254 if (!xml_parse($this->parser, $xml, true)) {
1255 // Display an error message.
1256 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1257 xml_get_current_line_number($this->parser),
1258 xml_error_string(xml_get_error_code($this->parser))
1259 );
1260 $this->debug($errstr);
1261 $this->debug("XML payload:\n" . $xml);
1262 $this->setError($errstr);
1263 }
1264
1265 xml_parser_free($this->parser);
1266 } else {
1267 $this->debug('no xml passed to parseString()!!');
1268 $this->setError('no xml passed to parseString()!!');
1269 }
1270 }
1271
1279 public function CreateTypeName($ename)
1280 {
1281 $scope = '';
1282 for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1283 $scope .= $this->complexTypeStack[$i] . '_';
1284 }
1285 return $scope . $ename . '_ContainedType';
1286 }
1287
1296 public function schemaStartElement($parser, $name, $attrs)
1297 {
1298
1299 $aname = null;
1300 // position in the total number of elements, starting from 0
1301 $pos = $this->position++;
1302 $depth = $this->depth++;
1303 // set self as current value for this depth
1304 $this->depth_array[$depth] = $pos;
1305 $this->message[$pos] = ['cdata' => ''];
1306 if ($depth > 0) {
1307 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1308 } else {
1309 $this->defaultNamespace[$pos] = false;
1310 }
1311
1312 // get element prefix
1313 if ($prefix = $this->getPrefix($name)) {
1314 // get unqualified name
1315 $name = $this->getLocalPart($name);
1316 } else {
1317 $prefix = '';
1318 }
1319
1320 // loop thru attributes, expanding, and registering namespace declarations
1321 if ((is_countable($attrs) ? count($attrs) : 0) > 0) {
1322 foreach ($attrs as $k => $v) {
1323 // if ns declarations, add to class level array of valid namespaces
1324 if (preg_match('/^xmlns/', $k)) {
1325 //$this->xdebug("$k: $v");
1326 //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1327 if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
1328 //$this->xdebug("Add namespace[$ns_prefix] = $v");
1329 $this->namespaces[$ns_prefix] = $v;
1330 } else {
1331 $this->defaultNamespace[$pos] = $v;
1332 if (! $this->getPrefixFromNamespace($v)) {
1333 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1334 }
1335 }
1336 if ('https://www.w3.org/2001/XMLSchema' == $v || 'https://www.w3.org/1999/XMLSchema' == $v || 'https://www.w3.org/2000/10/XMLSchema' == $v) {
1337 $this->XMLSchemaVersion = $v;
1338 $this->namespaces['xsi'] = $v.'-instance';
1339 }
1340 }
1341 }
1342 foreach ($attrs as $k => $v) {
1343 // expand each attribute
1344 $k = strpos($k, ':') ? $this->expandQname($k) : $k;
1345 $v = strpos($v, ':') ? $this->expandQname($v) : $v;
1346 $eAttrs[$k] = $v;
1347 }
1348 $attrs = $eAttrs;
1349 } else {
1350 $attrs = [];
1351 }
1352 // find status, register data
1353 switch ($name) {
1354 case 'all': // (optional) compositor content for a complexType
1355 case 'choice':
1356 case 'group':
1357 case 'sequence':
1358 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1359 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1360 //if($name == 'all' || $name == 'sequence'){
1361 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1362 //}
1363 break;
1364 case 'attribute': // complexType attribute
1365 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['https://schemas.xmlsoap.org/wsdl/:arrayType']);
1366 $this->xdebug('parsing attribute:');
1367 $this->appendDebug($this->varDump($attrs));
1368 if (!isset($attrs['form'])) {
1369 // TODO: handle globals
1370 $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1371 }
1372 if (isset($attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1373 $v = $attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'];
1374 if (!strpos($v, ':')) {
1375 // no namespace in arrayType attribute value...
1376 if ($this->defaultNamespace[$pos]) {
1377 // ...so use the default
1378 $attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'];
1379 }
1380 }
1381 }
1382 if (isset($attrs['name'])) {
1383 $this->attributes[$attrs['name']] = $attrs;
1384 $aname = $attrs['name'];
1385 } elseif (isset($attrs['ref']) && 'https://schemas.xmlsoap.org/soap/encoding/:arrayType' == $attrs['ref']) {
1386 if (isset($attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1387 $aname = $attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'];
1388 } else {
1389 $aname = '';
1390 }
1391 } elseif (isset($attrs['ref'])) {
1392 $aname = $attrs['ref'];
1393 $this->attributes[$attrs['ref']] = $attrs;
1394 }
1395
1396 if ($this->currentComplexType) { // This should *always* be
1397 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1398 }
1399 // arrayType attribute
1400 if (isset($attrs['https://schemas.xmlsoap.org/wsdl/:arrayType']) || 'arrayType' == $this->getLocalPart($aname)) {
1401 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1402 $prefix = $this->getPrefix($aname);
1403 if (isset($attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1404 $v = $attrs['https://schemas.xmlsoap.org/wsdl/:arrayType'];
1405 } else {
1406 $v = '';
1407 }
1408 if (strpos($v, '[,]')) {
1409 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1410 }
1411 $v = substr($v, 0, strpos($v, '[')); // clip the []
1412 if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
1413 $v = $this->XMLSchemaVersion.':'.$v;
1414 }
1415 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1416 }
1417 break;
1418 case 'complexContent': // (optional) content for a complexType
1419 $this->xdebug("do nothing for element $name");
1420 break;
1421 case 'complexType':
1422 array_push($this->complexTypeStack, $this->currentComplexType);
1423 if (isset($attrs['name'])) {
1424 // TODO: what is the scope of named complexTypes that appear
1425 // nested within other c complexTypes?
1426 $this->xdebug('processing named complexType '.$attrs['name']);
1427 //$this->currentElement = false;
1428 $this->currentComplexType = $attrs['name'];
1429 $this->complexTypes[$this->currentComplexType] = $attrs;
1430 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1431 // This is for constructs like
1432 // <complexType name="ListOfString" base="soap:Array">
1433 // <sequence>
1434 // <element name="string" type="xsd:string"
1435 // minOccurs="0" maxOccurs="unbounded" />
1436 // </sequence>
1437 // </complexType>
1438 if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1439 $this->xdebug('complexType is unusual array');
1440 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1441 } else {
1442 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1443 }
1444 } else {
1445 $name = $this->CreateTypeName($this->currentElement);
1446 $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1447 $this->currentComplexType = $name;
1448 //$this->currentElement = false;
1449 $this->complexTypes[$this->currentComplexType] = $attrs;
1450 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1451 // This is for constructs like
1452 // <complexType name="ListOfString" base="soap:Array">
1453 // <sequence>
1454 // <element name="string" type="xsd:string"
1455 // minOccurs="0" maxOccurs="unbounded" />
1456 // </sequence>
1457 // </complexType>
1458 if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
1459 $this->xdebug('complexType is unusual array');
1460 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1461 } else {
1462 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1463 }
1464 }
1465 $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
1466 break;
1467 case 'element':
1468 array_push($this->elementStack, $this->currentElement);
1469 if (!isset($attrs['form'])) {
1470 if ($this->currentComplexType) {
1471 $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1472 } else {
1473 // global
1474 $attrs['form'] = 'qualified';
1475 }
1476 }
1477 if (isset($attrs['type'])) {
1478 $this->xdebug('processing typed element ' . $attrs['name'] . ' of type ' . $attrs['type']);
1479 if (! $this->getPrefix($attrs['type'])) {
1480 if ($this->defaultNamespace[$pos]) {
1481 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1482 $this->xdebug('used default namespace to make type ' . $attrs['type']);
1483 }
1484 }
1485 // This is for constructs like
1486 // <complexType name="ListOfString" base="soap:Array">
1487 // <sequence>
1488 // <element name="string" type="xsd:string"
1489 // minOccurs="0" maxOccurs="unbounded" />
1490 // </sequence>
1491 // </complexType>
1492 if ($this->currentComplexType && 'array' == $this->complexTypes[$this->currentComplexType]['phpType']) {
1493 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1494 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1495 }
1496 $this->currentElement = $attrs['name'];
1497 $ename = $attrs['name'];
1498 } elseif (isset($attrs['ref'])) {
1499 $this->xdebug('processing element as ref to ' . $attrs['ref']);
1500 $this->currentElement = 'ref to ' . $attrs['ref'];
1501 $ename = $this->getLocalPart($attrs['ref']);
1502 } else {
1503 $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1504 $this->xdebug('processing untyped element ' . $attrs['name'] . ' type ' . $type);
1505 $this->currentElement = $attrs['name'];
1506 $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1507 $ename = $attrs['name'];
1508 }
1509 if (isset($ename) && $this->currentComplexType) {
1510 $this->xdebug("add element $ename to complexType $this->currentComplexType");
1511 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1512 } elseif (!isset($attrs['ref'])) {
1513 $this->xdebug("add element $ename to elements array");
1514 $this->elements[ $attrs['name'] ] = $attrs;
1515 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1516 }
1517 break;
1518 case 'enumeration': // restriction value list member
1519 $this->xdebug('enumeration ' . $attrs['value']);
1520 if ($this->currentSimpleType) {
1521 $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1522 } elseif ($this->currentComplexType) {
1523 $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1524 }
1525 break;
1526 case 'extension': // simpleContent or complexContent type extension
1527 $this->xdebug('extension ' . $attrs['base']);
1528 if ($this->currentComplexType) {
1529 $ns = $this->getPrefix($attrs['base']);
1530 if ('' == $ns) {
1531 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
1532 } else {
1533 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1534 }
1535 } else {
1536 $this->xdebug('no current complexType to set extensionBase');
1537 }
1538 break;
1539 case 'import':
1540 if (isset($attrs['schemaLocation'])) {
1541 $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1542 $this->imports[$attrs['namespace']][] = ['location' => $attrs['schemaLocation'], 'loaded' => false];
1543 } else {
1544 $this->xdebug('import namespace ' . $attrs['namespace']);
1545 $this->imports[$attrs['namespace']][] = ['location' => '', 'loaded' => true];
1546 if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1547 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1548 }
1549 }
1550 break;
1551 case 'include':
1552 if (isset($attrs['schemaLocation'])) {
1553 $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
1554 $this->imports[$this->schemaTargetNamespace][] = ['location' => $attrs['schemaLocation'], 'loaded' => false];
1555 } else {
1556 $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
1557 }
1558 break;
1559 case 'list': // simpleType value list
1560 $this->xdebug("do nothing for element $name");
1561 break;
1562 case 'restriction': // simpleType, simpleContent or complexContent value restriction
1563 $this->xdebug('restriction ' . $attrs['base']);
1564 if ($this->currentSimpleType) {
1565 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1566 } elseif ($this->currentComplexType) {
1567 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1568 if (':Array' == strstr($attrs['base'], ':')) {
1569 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1570 }
1571 }
1572 break;
1573 case 'schema':
1574 $this->schemaInfo = $attrs;
1575 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1576 if (isset($attrs['targetNamespace'])) {
1577 $this->schemaTargetNamespace = $attrs['targetNamespace'];
1578 }
1579 if (!isset($attrs['elementFormDefault'])) {
1580 $this->schemaInfo['elementFormDefault'] = 'unqualified';
1581 }
1582 if (!isset($attrs['attributeFormDefault'])) {
1583 $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1584 }
1585 break;
1586 case 'simpleContent': // (optional) content for a complexType
1587 if ($this->currentComplexType) { // This should *always* be
1588 $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
1589 } else {
1590 $this->xdebug("do nothing for element $name because there is no current complexType");
1591 }
1592 break;
1593 case 'simpleType':
1594 array_push($this->simpleTypeStack, $this->currentSimpleType);
1595 if (isset($attrs['name'])) {
1596 $this->xdebug('processing simpleType for name ' . $attrs['name']);
1597 $this->currentSimpleType = $attrs['name'];
1598 $this->simpleTypes[ $attrs['name'] ] = $attrs;
1599 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1600 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1601 } else {
1602 $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1603 $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1604 $this->currentSimpleType = $name;
1605 //$this->currentElement = false;
1606 $this->simpleTypes[$this->currentSimpleType] = $attrs;
1607 $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1608 }
1609 break;
1610 case 'union': // simpleType type list
1611 $this->xdebug("do nothing for element $name");
1612 break;
1613 default:
1614 $this->xdebug("do not have any logic to process element $name");
1615 }
1616 }
1617
1625 public function schemaEndElement($parser, $name)
1626 {
1627 // bring depth down a notch
1628 $this->depth--;
1629 // position of current element is equal to the last value left in depth_array for my depth
1630 if (isset($this->depth_array[$this->depth])) {
1631 $pos = $this->depth_array[$this->depth];
1632 }
1633 // get element prefix
1634 if ($prefix = $this->getPrefix($name)) {
1635 // get unqualified name
1636 $name = $this->getLocalPart($name);
1637 } else {
1638 $prefix = '';
1639 }
1640 // move on...
1641 if ('complexType' == $name) {
1642 $this->xdebug('done processing complexType ' . ($this->currentComplexType ?: '(unknown)'));
1643 $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
1644 $this->currentComplexType = array_pop($this->complexTypeStack);
1645 //$this->currentElement = false;
1646 }
1647 if ('element' == $name) {
1648 $this->xdebug('done processing element ' . ($this->currentElement ?: '(unknown)'));
1649 $this->currentElement = array_pop($this->elementStack);
1650 }
1651 if ('simpleType' == $name) {
1652 $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ?: '(unknown)'));
1653 $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
1654 $this->currentSimpleType = array_pop($this->simpleTypeStack);
1655 }
1656 }
1657
1665 public function schemaCharacterData($parser, $data)
1666 {
1667 $pos = $this->depth_array[$this->depth - 1];
1668 $this->message[$pos]['cdata'] .= $data;
1669 }
1670
1676 public function serializeSchema()
1677 {
1678 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1679 $xml = '';
1680 // imports
1681 if (count($this->imports) > 0) {
1682 foreach ($this->imports as $ns => $list) {
1683 foreach ($list as $ii) {
1684 if ('' != $ii['location']) {
1685 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1686 } else {
1687 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1688 }
1689 }
1690 }
1691 }
1692 // complex types
1693 foreach ($this->complexTypes as $typeName => $attrs) {
1694 $contentStr = '';
1695 // serialize child elements
1696 if (isset($attrs['elements']) && ((is_countable($attrs['elements']) ? count($attrs['elements']) : 0) > 0)) {
1697 foreach ($attrs['elements'] as $element => $eParts) {
1698 if (isset($eParts['ref'])) {
1699 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1700 } else {
1701 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . '"';
1702 foreach ($eParts as $aName => $aValue) {
1703 // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1704 if ('name' != $aName && 'type' != $aName) {
1705 $contentStr .= " $aName=\"$aValue\"";
1706 }
1707 }
1708 $contentStr .= "/>\n";
1709 }
1710 }
1711 // compositor wraps elements
1712 if (isset($attrs['compositor']) && ('' != $attrs['compositor'])) {
1713 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
1714 }
1715 }
1716 // attributes
1717 if (isset($attrs['attrs']) && ((is_countable($attrs['attrs']) ? count($attrs['attrs']) : 0) >= 1)) {
1718 foreach ($attrs['attrs'] as $attr => $aParts) {
1719 $contentStr .= " <$schemaPrefix:attribute";
1720 foreach ($aParts as $a => $v) {
1721 if ('ref' == $a || 'type' == $a) {
1722 $contentStr .= " $a=\"".$this->contractQName($v).'"';
1723 } elseif ('https://schemas.xmlsoap.org/wsdl/:arrayType' == $a) {
1724 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1725 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1726 } else {
1727 $contentStr .= " $a=\"$v\"";
1728 }
1729 }
1730 $contentStr .= "/>\n";
1731 }
1732 }
1733 // if restriction
1734 if (isset($attrs['restrictionBase']) && '' != $attrs['restrictionBase']) {
1735 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
1736 // complex or simple content
1737 if ((isset($attrs['elements']) && (is_countable($attrs['elements']) ? count($attrs['elements']) : 0) > 0) || (isset($attrs['attrs']) && (is_countable($attrs['attrs']) ? count($attrs['attrs']) : 0) > 0)) {
1738 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
1739 }
1740 }
1741 // finalize complex type
1742 if ('' != $contentStr) {
1743 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1744 } else {
1745 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1746 }
1747 $xml .= $contentStr;
1748 }
1749 // simple types
1750 if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
1751 foreach ($this->simpleTypes as $typeName => $eParts) {
1752 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
1753 if (isset($eParts['enumeration'])) {
1754 foreach ($eParts['enumeration'] as $e) {
1755 $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1756 }
1757 }
1758 $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1759 }
1760 }
1761 // elements
1762 if (isset($this->elements) && count($this->elements) > 0) {
1763 foreach ($this->elements as $element => $eParts) {
1764 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1765 }
1766 }
1767 // attributes
1768 if (isset($this->attributes) && count($this->attributes) > 0) {
1769 foreach ($this->attributes as $attr => $aParts) {
1770 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1771 }
1772 }
1773 // finish 'er up
1774 $attr = '';
1775 foreach ($this->schemaInfo as $k => $v) {
1776 if ('elementFormDefault' == $k || 'attributeFormDefault' == $k) {
1777 $attr .= " $k=\"$v\"";
1778 }
1779 }
1780 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1781 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1782 $el .= " xmlns:$nsp=\"$ns\"";
1783 }
1784 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1785 return $xml;
1786 }
1787
1794 public function xdebug($string)
1795 {
1796 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1797 }
1798
1811 public function getPHPType($type, $ns)
1812 {
1813 if (isset($this->typemap[$ns][$type])) {
1814 //print "found type '$type' and ns $ns in typemap<br>";
1815 return $this->typemap[$ns][$type];
1816 } elseif (isset($this->complexTypes[$type])) {
1817 //print "getting type '$type' and ns $ns from complexTypes array<br>";
1818 return $this->complexTypes[$type]['phpType'];
1819 }
1820 return false;
1821 }
1822
1845 public function getTypeDef($type)
1846 {
1847 $typeDef = [];
1848 //$this->debug("in getTypeDef for type $type");
1849 if ('^' == substr($type, -1)) {
1850 $is_element = 1;
1851 $type = substr($type, 0, -1);
1852 } else {
1853 $is_element = 0;
1854 }
1855
1856 if ((! $is_element) && isset($this->complexTypes[$type])) {
1857 $this->xdebug("in getTypeDef, found complexType $type");
1858 return $this->complexTypes[$type];
1859 } elseif ((! $is_element) && isset($this->simpleTypes[$type])) {
1860 $this->xdebug("in getTypeDef, found simpleType $type");
1861 if (!isset($this->simpleTypes[$type]['phpType'])) {
1862 // get info for type to tack onto the simple type
1863 // TODO: can this ever really apply (i.e. what is a simpleType really?)
1864 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1865 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1866 $etype = $this->getTypeDef($uqType);
1867 if ($etype) {
1868 $this->xdebug("in getTypeDef, found type for simpleType $type:");
1869 $this->xdebug($this->varDump($etype));
1870 if (isset($etype['phpType'])) {
1871 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1872 }
1873 if (isset($etype['elements'])) {
1874 $this->simpleTypes[$type]['elements'] = $etype['elements'];
1875 }
1876 }
1877 }
1878 return $this->simpleTypes[$type];
1879 } elseif (isset($this->elements[$type])) {
1880 $this->xdebug("in getTypeDef, found element $type");
1881 if (!isset($this->elements[$type]['phpType'])) {
1882 // get info for type to tack onto the element
1883 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1884 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1885 $etype = $this->getTypeDef($uqType);
1886 if ($etype) {
1887 $this->xdebug("in getTypeDef, found type for element $type:");
1888 $this->xdebug($this->varDump($etype));
1889 if (isset($etype['phpType'])) {
1890 $this->elements[$type]['phpType'] = $etype['phpType'];
1891 }
1892 if (isset($etype['elements'])) {
1893 $this->elements[$type]['elements'] = $etype['elements'];
1894 }
1895 if (isset($etype['extensionBase'])) {
1896 $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
1897 }
1898 } elseif ('https://www.w3.org/2001/XMLSchema' == $ns) {
1899 $this->xdebug("in getTypeDef, element $type is an XSD type");
1900 $this->elements[$type]['phpType'] = 'scalar';
1901 }
1902 }
1903 return $this->elements[$type];
1904 } elseif (isset($this->attributes[$type])) {
1905 $this->xdebug("in getTypeDef, found attribute $type");
1906 return $this->attributes[$type];
1907 } elseif (preg_match('/_ContainedType$/', $type)) {
1908 $this->xdebug("in getTypeDef, have an untyped element $type");
1909 $typeDef['typeClass'] = 'simpleType';
1910 $typeDef['phpType'] = 'scalar';
1911 $typeDef['type'] = 'https://www.w3.org/2001/XMLSchema:string';
1912 return $typeDef;
1913 }
1914 $this->xdebug("in getTypeDef, did not find $type");
1915 return false;
1916 }
1917
1926 public function serializeTypeDef($type)
1927 {
1928 $str = null;
1929 //print "in sTD() for type $type<br>";
1930 if ($typeDef = $this->getTypeDef($type)) {
1931 $str .= '<'.$type;
1932 if (is_array($typeDef['attrs'])) {
1933 foreach ($typeDef['attrs'] as $attName => $data) {
1934 $str .= " $attName=\"{type = ".$data['type'] . '}"';
1935 }
1936 }
1937 $str .= ' xmlns="' . $this->schema['targetNamespace'] . '"';
1938 if ((is_countable($typeDef['elements']) ? count($typeDef['elements']) : 0) > 0) {
1939 $str .= '>';
1940 foreach ($typeDef['elements'] as $element => $eData) {
1941 $str .= $this->serializeTypeDef($element);
1942 }
1943 $str .= "</$type>";
1944 } elseif ('element' == $typeDef['typeClass']) {
1945 $str .= "></$type>";
1946 } else {
1947 $str .= '/>';
1948 }
1949 return $str;
1950 }
1951 return false;
1952 }
1953
1964 public function typeToForm($name, $type)
1965 {
1966 $buffer = null;
1967 // get typedef
1968 if ($typeDef = $this->getTypeDef($type)) {
1969 // if struct
1970 if ('struct' == $typeDef['phpType']) {
1971 $buffer .= '<table>';
1972 foreach ($typeDef['elements'] as $child => $childDef) {
1973 $buffer .= "
1974 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1975 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1976 }
1977 $buffer .= '</table>';
1978 // if array
1979 } elseif ('array' == $typeDef['phpType']) {
1980 $buffer .= '<table>';
1981 for ($i=0;$i < 3; $i++) {
1982 $buffer .= "
1983 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1984 <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1985 }
1986 $buffer .= '</table>';
1987 // if scalar
1988 } else {
1989 $buffer .= "<input type='text' name='parameters[$name]'>";
1990 }
1991 } else {
1992 $buffer .= "<input type='text' name='parameters[$name]'>";
1993 }
1994 return $buffer;
1995 }
1996
2033 public function addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements= [], $attrs= [], $arrayType='')
2034 {
2035 $this->complexTypes[$name] = [
2036 'name' => $name,
2037 'typeClass' => $typeClass,
2038 'phpType' => $phpType,
2039 'compositor'=> $compositor,
2040 'restrictionBase' => $restrictionBase,
2041 'elements' => $elements,
2042 'attrs' => $attrs,
2043 'arrayType' => $arrayType
2044 ];
2045
2046 $this->xdebug("addComplexType $name:");
2047 $this->appendDebug($this->varDump($this->complexTypes[$name]));
2048 }
2049
2062 public function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration= [])
2063 {
2064 $this->simpleTypes[$name] = [
2065 'name' => $name,
2066 'typeClass' => $typeClass,
2067 'phpType' => $phpType,
2068 'type' => $restrictionBase,
2069 'enumeration' => $enumeration
2070 ];
2071
2072 $this->xdebug("addSimpleType $name:");
2073 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2074 }
2075
2083 public function addElement($attrs)
2084 {
2085 if (! $this->getPrefix($attrs['type'])) {
2086 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2087 }
2088 $this->elements[ $attrs['name'] ] = $attrs;
2089 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2090
2091 $this->xdebug('addElement ' . $attrs['name']);
2092 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
2093 }
2094}
2095
2100{
2101}
2102
2103?><?php
2104
2105
2106
2119{
2126 public $name;
2133 public $type;
2140 public $value;
2147 public $element_ns;
2154 public $type_ns;
2161 public $attributes;
2162
2174 public function __construct($name='soapval', $type=false, $value=-1, $element_ns=false, $type_ns=false, $attributes=false)
2175 {
2176 parent::__construct();
2177 $this->name = $name;
2178 $this->type = $type;
2179 $this->value = $value;
2180 $this->element_ns = $element_ns;
2181 $this->type_ns = $type_ns;
2182 $this->attributes = $attributes;
2183 }
2184
2192 public function serialize($use='encoded')
2193 {
2194 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2195 }
2196
2203 public function decode()
2204 {
2205 return $this->value;
2206 }
2207}
2208
2209
2210
2211?><?php
2212
2213
2214
2225{
2226
2227 public $url = '';
2228 public $uri = '';
2229 public $digest_uri = '';
2230 public $scheme = '';
2231 public $host = '';
2232 public $port = '';
2233 public $path = '';
2234 public $request_method = 'POST';
2235 public $protocol_version = '1.0';
2236 public $encoding = '';
2237 public $outgoing_headers = [];
2238 public $incoming_headers = [];
2239 public $incoming_cookies = [];
2240 public $outgoing_payload = '';
2241 public $incoming_payload = '';
2242 public $response_status_line; // HTTP response status line
2243 public $useSOAPAction = true;
2244 public $persistentConnection = false;
2245 public $ch = false; // cURL handle
2246 public $ch_options = []; // cURL custom options
2247 public $use_curl = false; // force cURL use
2248 public $proxy = null; // proxy information (associative array)
2249 public $username = '';
2250 public $password = '';
2251 public $authtype = '';
2252 public $digestRequest = [];
2253 public $certRequest = []; // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2254 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2255 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2256 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2257 // passphrase: SSL key password/passphrase
2258 // certpassword: SSL certificate password
2259 // verifypeer: default is 1
2260 // verifyhost: default is 1
2261
2270 public function __construct($url, $curl_options = null, $use_curl = false)
2271 {
2272 parent::__construct();
2273 $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2274 $this->appendDebug($this->varDump($curl_options));
2275 $this->setURL($url);
2276 if (is_array($curl_options)) {
2277 $this->ch_options = $curl_options;
2278 }
2279 $this->use_curl = $use_curl;
2280 preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2281 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
2282 }
2283
2291 public function setCurlOption($option, $value)
2292 {
2293 $this->debug("setCurlOption option=$option, value=");
2294 $this->appendDebug($this->varDump($value));
2295 curl_setopt($this->ch, $option, $value);
2296 }
2297
2305 public function setHeader($name, $value)
2306 {
2307 $this->outgoing_headers[$name] = $value;
2308 $this->debug("set header $name: $value");
2309 }
2310
2317 public function unsetHeader($name)
2318 {
2319 if (isset($this->outgoing_headers[$name])) {
2320 $this->debug("unset header $name");
2321 unset($this->outgoing_headers[$name]);
2322 }
2323 }
2324
2331 public function setURL($url)
2332 {
2333 $this->url = $url;
2334
2335 $u = parse_url($url);
2336 foreach ($u as $k => $v) {
2337 $this->debug("parsed URL $k = $v");
2338 $this->$k = $v;
2339 }
2340
2341 // add any GET params to path
2342 if (isset($u['query']) && '' != $u['query']) {
2343 $this->path .= '?' . $u['query'];
2344 }
2345
2346 // set default port
2347 if (!isset($u['port'])) {
2348 if ('https' == $u['scheme']) {
2349 $this->port = 443;
2350 } else {
2351 $this->port = 80;
2352 }
2353 }
2354
2355 $this->uri = $this->path;
2356 $this->digest_uri = $this->uri;
2357
2358 // build headers
2359 if (!isset($u['port'])) {
2360 $this->setHeader('Host', $this->host);
2361 } else {
2362 $this->setHeader('Host', $this->host.':'.$this->port);
2363 }
2364
2365 if (isset($u['user']) && '' != $u['user']) {
2366 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2367 }
2368 }
2369
2376 public function io_method()
2377 {
2378 if ($this->use_curl || ('https' == $this->scheme) || ('http' == $this->scheme && 'ntlm' == $this->authtype) || ('http' == $this->scheme && is_array($this->proxy) && 'ntlm' == $this->proxy['authtype'])) {
2379 return 'curl';
2380 }
2381 if (('http' == $this->scheme || 'ssl' == $this->scheme) && 'ntlm' != $this->authtype && (!is_array($this->proxy) || 'ntlm' != $this->proxy['authtype'])) {
2382 return 'socket';
2383 }
2384 return 'unknown';
2385 }
2386
2395 public function connect($connection_timeout=0, $response_timeout=30)
2396 {
2397 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2398 // "regular" socket.
2399 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2400 // loaded), and until PHP5 stream_get_wrappers is not available.
2401// if ($this->scheme == 'https') {
2402// if (version_compare(phpversion(), '4.3.0') >= 0) {
2403// if (extension_loaded('openssl')) {
2404// $this->scheme = 'ssl';
2405// $this->debug('Using SSL over OpenSSL');
2406// }
2407// }
2408// }
2409 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2410 if ('socket' == $this->io_method()) {
2411 if (!is_array($this->proxy)) {
2412 $host = $this->host;
2413 $port = $this->port;
2414 } else {
2415 $host = $this->proxy['host'];
2416 $port = $this->proxy['port'];
2417 }
2418
2419 // use persistent connection
2420 if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
2421 if (!feof($this->fp)) {
2422 $this->debug('Re-use persistent connection');
2423 return true;
2424 }
2425 fclose($this->fp);
2426 $this->debug('Closed persistent connection at EOF');
2427 }
2428
2429 // munge host if using OpenSSL
2430 if ('ssl' == $this->scheme) {
2431 $host = 'ssl://' . $host;
2432 }
2433 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2434
2435 // open socket
2436 if ($connection_timeout > 0) {
2437 $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2438 } else {
2439 $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
2440 }
2441
2442 // test pointer
2443 if (!$this->fp) {
2444 $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2445 if ($this->errno) {
2446 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2447 } else {
2448 $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2449 }
2450 $this->debug($msg);
2451 $this->setError($msg);
2452 return false;
2453 }
2454
2455 // set response timeout
2456 $this->debug('set response timeout to ' . $response_timeout);
2457 stream_set_timeout($this->fp, $response_timeout);
2458
2459 $this->debug('socket connected');
2460 return true;
2461 } elseif ('curl' == $this->io_method()) {
2462 if (!extension_loaded('curl')) {
2463 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2464 $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.');
2465 return false;
2466 }
2467 // Avoid warnings when PHP does not have these options
2468 if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
2469 $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2470 } else {
2471 $CURLOPT_CONNECTIONTIMEOUT = 78;
2472 }
2473 if (defined('CURLOPT_HTTPAUTH')) {
2474 $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2475 } else {
2476 $CURLOPT_HTTPAUTH = 107;
2477 }
2478 if (defined('CURLOPT_PROXYAUTH')) {
2479 $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2480 } else {
2481 $CURLOPT_PROXYAUTH = 111;
2482 }
2483 if (defined('CURLAUTH_BASIC')) {
2484 $CURLAUTH_BASIC = CURLAUTH_BASIC;
2485 } else {
2486 $CURLAUTH_BASIC = 1;
2487 }
2488 if (defined('CURLAUTH_DIGEST')) {
2489 $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2490 } else {
2491 $CURLAUTH_DIGEST = 2;
2492 }
2493 if (defined('CURLAUTH_NTLM')) {
2494 $CURLAUTH_NTLM = CURLAUTH_NTLM;
2495 } else {
2496 $CURLAUTH_NTLM = 8;
2497 }
2498
2499 $this->debug('connect using cURL');
2500 // init CURL
2501 $this->ch = curl_init();
2502 // set url
2503 $hostURL = ('' != $this->port) ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2504 // add path
2505 $hostURL .= $this->path;
2506 $this->setCurlOption(CURLOPT_URL, $hostURL);
2507 // follow location headers (re-directs)
2508 if (ini_get('safe_mode') || ini_get('open_basedir')) {
2509 $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2510 $this->debug('safe_mode = ');
2511 $this->appendDebug($this->varDump(ini_get('safe_mode')));
2512 $this->debug('open_basedir = ');
2513 $this->appendDebug($this->varDump(ini_get('open_basedir')));
2514 } else {
2515 $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2516 }
2517 // ask for headers in the response output
2518 $this->setCurlOption(CURLOPT_HEADER, 1);
2519 // ask for the response output as the return value
2520 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2521 // encode
2522 // We manage this ourselves through headers and encoding
2523// if(function_exists('gzuncompress')){
2524// $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2525// }
2526 // persistent connection
2527 if ($this->persistentConnection) {
2528 // I believe the following comment is now bogus, having applied to
2529 // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2530 // The way we send data, we cannot use persistent connections, since
2531 // there will be some "junk" at the end of our request.
2532 //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2533 $this->persistentConnection = false;
2534 $this->setHeader('Connection', 'close');
2535 }
2536 // set timeouts
2537 if (0 != $connection_timeout) {
2538 $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2539 }
2540 if (0 != $response_timeout) {
2541 $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2542 }
2543
2544 if ('https' == $this->scheme) {
2545 $this->debug('set cURL SSL verify options');
2546 // recent versions of cURL turn on peer/host checking by default,
2547 // while PHP binaries are not compiled with a default location for the
2548 // CA cert bundle, so disable peer/host checking.
2549 //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2550 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2551 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2552
2553 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2554 if ('certificate' == $this->authtype) {
2555 $this->debug('set cURL certificate options');
2556 if (isset($this->certRequest['cainfofile'])) {
2557 $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2558 }
2559 if (isset($this->certRequest['verifypeer'])) {
2560 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2561 } else {
2562 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2563 }
2564 if (isset($this->certRequest['verifyhost'])) {
2565 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2566 } else {
2567 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2568 }
2569 if (isset($this->certRequest['sslcertfile'])) {
2570 $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2571 }
2572 if (isset($this->certRequest['sslkeyfile'])) {
2573 $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2574 }
2575 if (isset($this->certRequest['passphrase'])) {
2576 $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2577 }
2578 if (isset($this->certRequest['certpassword'])) {
2579 $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2580 }
2581 }
2582 }
2583 if ($this->authtype && ('certificate' != $this->authtype)) {
2584 if ($this->username) {
2585 $this->debug('set cURL username/password');
2586 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2587 }
2588 if ('basic' == $this->authtype) {
2589 $this->debug('set cURL for Basic authentication');
2590 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2591 }
2592 if ('digest' == $this->authtype) {
2593 $this->debug('set cURL for digest authentication');
2594 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2595 }
2596 if ('ntlm' == $this->authtype) {
2597 $this->debug('set cURL for NTLM authentication');
2598 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2599 }
2600 }
2601 if (is_array($this->proxy)) {
2602 $this->debug('set cURL proxy options');
2603 if ('' != $this->proxy['port']) {
2604 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
2605 } else {
2606 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2607 }
2608 if ($this->proxy['username'] || $this->proxy['password']) {
2609 $this->debug('set cURL proxy authentication options');
2610 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
2611 if ('basic' == $this->proxy['authtype']) {
2612 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2613 }
2614 if ('ntlm' == $this->proxy['authtype']) {
2615 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2616 }
2617 }
2618 }
2619 $this->debug('cURL connection set up');
2620 return true;
2621 } else {
2622 $this->setError('Unknown scheme ' . $this->scheme);
2623 $this->debug('Unknown scheme ' . $this->scheme);
2624 return false;
2625 }
2626 }
2627
2638 public function send($data, $timeout=0, $response_timeout=30, $cookies=null)
2639 {
2640 $this->debug('entered send() with data of length: '.strlen($data));
2641
2642 $this->tryagain = true;
2643 $tries = 0;
2644 while ($this->tryagain) {
2645 $this->tryagain = false;
2646 if ($tries++ < 2) {
2647 // make connnection
2648 if (!$this->connect($timeout, $response_timeout)) {
2649 return false;
2650 }
2651
2652 // send request
2653 if (!$this->sendRequest($data, $cookies)) {
2654 return false;
2655 }
2656
2657 // get response
2658 $respdata = $this->getResponse();
2659 } else {
2660 $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2661 }
2662 }
2663 $this->debug('end of send()');
2664 return $respdata;
2665 }
2666
2667
2679 public function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies)
2680 {
2681 return $this->send($data, $timeout, $response_timeout, $cookies);
2682 }
2683
2694 public function setCredentials($username, $password, $authtype = 'basic', $digestRequest = [], $certRequest = [])
2695 {
2696 $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2697 $this->appendDebug($this->varDump($digestRequest));
2698 $this->debug('certRequest=');
2699 $this->appendDebug($this->varDump($certRequest));
2700 // cf. RFC 2617
2701 if ('basic' == $authtype) {
2702 $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':', '', $username).':'.$password));
2703 } elseif ('digest' == $authtype) {
2704 if (isset($digestRequest['nonce'])) {
2705 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2706
2707 // calculate the Digest hashes (calculate code based on digest implementation found at: https://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2708
2709 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2710 $A1 = $username. ':' . ($digestRequest['realm'] ?? '') . ':' . $password;
2711
2712 // H(A1) = MD5(A1)
2713 $HA1 = md5($A1);
2714
2715 // A2 = Method ":" digest-uri-value
2716 $A2 = $this->request_method . ':' . $this->digest_uri;
2717
2718 // H(A2)
2719 $HA2 = md5($A2);
2720
2721 // KD(secret, data) = H(concat(secret, ":", data))
2722 // if qop == auth:
2723 // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2724 // ":" nc-value
2725 // ":" unq(cnonce-value)
2726 // ":" unq(qop-value)
2727 // ":" H(A2)
2728 // ) <">
2729 // if qop is missing,
2730 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2731
2732 $unhashedDigest = '';
2733 $nonce = $digestRequest['nonce'] ?? '';
2734 $cnonce = $nonce;
2735 if ('' != $digestRequest['qop']) {
2736 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf('%08d', $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2737 } else {
2738 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2739 }
2740
2741 $hashedDigest = md5($unhashedDigest);
2742
2743 $opaque = '';
2744 if (isset($digestRequest['opaque'])) {
2745 $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2746 }
2747
2748 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf('%08x', $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
2749 }
2750 } elseif ('certificate' == $authtype) {
2751 $this->certRequest = $certRequest;
2752 $this->debug('Authorization header not set for certificate');
2753 } elseif ('ntlm' == $authtype) {
2754 // do nothing
2755 $this->debug('Authorization header not set for ntlm');
2756 }
2757 $this->username = $username;
2758 $this->password = $password;
2759 $this->authtype = $authtype;
2760 $this->digestRequest = $digestRequest;
2761 }
2762
2769 public function setSOAPAction($soapaction)
2770 {
2771 $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2772 }
2773
2780 public function setEncoding($enc='gzip, deflate')
2781 {
2782 if (function_exists('gzdeflate')) {
2783 $this->protocol_version = '1.1';
2784 $this->setHeader('Accept-Encoding', $enc);
2785 if (!isset($this->outgoing_headers['Connection'])) {
2786 $this->setHeader('Connection', 'close');
2787 $this->persistentConnection = false;
2788 }
2789 // deprecated as of PHP 5.3.0
2790 //set_magic_quotes_runtime(0);
2791 $this->encoding = $enc;
2792 }
2793 }
2794
2805 public function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic')
2806 {
2807 if ($proxyhost) {
2808 $this->proxy = [
2809 'host' => $proxyhost,
2810 'port' => $proxyport,
2811 'username' => $proxyusername,
2812 'password' => $proxypassword,
2813 'authtype' => $proxyauthtype
2814 ];
2815 if ('' != $proxyusername && '' != $proxypassword && $proxyauthtype = 'basic') {
2816 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
2817 }
2818 } else {
2819 $this->debug('remove proxy');
2820 $proxy = null;
2821 unsetHeader('Proxy-Authorization');
2822 }
2823 }
2824
2834 public function isSkippableCurlHeader(&$data)
2835 {
2836 $skipHeaders = [
2837 'HTTP/1.1 100',
2838 'HTTP/1.0 301',
2839 'HTTP/1.1 301',
2840 'HTTP/1.0 302',
2841 'HTTP/1.1 302',
2842 'HTTP/1.0 401',
2843 'HTTP/1.1 401',
2844 'HTTP/1.0 200 Connection established'
2845 ];
2846 foreach ($skipHeaders as $hd) {
2847 $prefix = substr($data, 0, strlen($hd));
2848 if ($prefix == $hd) {
2849 return true;
2850 }
2851 }
2852
2853 return false;
2854 }
2855
2867 public function decodeChunked($buffer, $lb)
2868 {
2869 // length := 0
2870 $length = 0;
2871 $new = '';
2872
2873 // read chunk-size, chunk-extension (if any) and CRLF
2874 // get the position of the linebreak
2875 $chunkend = strpos($buffer, $lb);
2876 if (false == $chunkend) {
2877 $this->debug('no linebreak found in decodeChunked');
2878 return $new;
2879 }
2880 $temp = substr($buffer, 0, $chunkend);
2881 $chunk_size = hexdec(trim($temp));
2882 $chunkstart = $chunkend + strlen($lb);
2883 // while (chunk-size > 0) {
2884 while ($chunk_size > 0) {
2885 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2886 $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
2887
2888 // Just in case we got a broken connection
2889 if (false == $chunkend) {
2890 $chunk = substr($buffer, $chunkstart);
2891 // append chunk-data to entity-body
2892 $new .= $chunk;
2893 $length += strlen($chunk);
2894 break;
2895 }
2896
2897 // read chunk-data and CRLF
2898 $chunk = substr($buffer, $chunkstart, $chunkend-$chunkstart);
2899 // append chunk-data to entity-body
2900 $new .= $chunk;
2901 // length := length + chunk-size
2902 $length += strlen($chunk);
2903 // read chunk-size and CRLF
2904 $chunkstart = $chunkend + strlen($lb);
2905
2906 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2907 if (false == $chunkend) {
2908 break; //Just in case we got a broken connection
2909 }
2910 $temp = substr($buffer, $chunkstart, $chunkend-$chunkstart);
2911 $chunk_size = hexdec(trim($temp));
2912 $chunkstart = $chunkend;
2913 }
2914 return $new;
2915 }
2916
2925 public function buildPayload($data, $cookie_str = '')
2926 {
2927 // Note: for cURL connections, $this->outgoing_payload is ignored,
2928 // as is the Content-Length header, but these are still created as
2929 // debugging guides.
2930
2931 // add content-length header
2932 if ('GET' != $this->request_method) {
2933 $this->setHeader('Content-Length', strlen($data));
2934 }
2935
2936 // start building outgoing payload:
2937 if ($this->proxy) {
2938 $uri = $this->url;
2939 } else {
2940 $uri = $this->uri;
2941 }
2942 $req = "$this->request_method $uri HTTP/$this->protocol_version";
2943 $this->debug("HTTP request: $req");
2944 $this->outgoing_payload = "$req\r\n";
2945
2946 // loop thru headers, serializing
2947 foreach ($this->outgoing_headers as $k => $v) {
2948 $hdr = $k.': '.$v;
2949 $this->debug("HTTP header: $hdr");
2950 $this->outgoing_payload .= "$hdr\r\n";
2951 }
2952
2953 // add any cookies
2954 if ('' != $cookie_str) {
2955 $hdr = 'Cookie: '.$cookie_str;
2956 $this->debug("HTTP header: $hdr");
2957 $this->outgoing_payload .= "$hdr\r\n";
2958 }
2959
2960 // header/body separator
2961 $this->outgoing_payload .= "\r\n";
2962
2963 // add data
2964 $this->outgoing_payload .= $data;
2965 }
2966
2975 public function sendRequest($data, $cookies = null)
2976 {
2977 // build cookie string
2978 $cookie_str = $this->getCookiesForRequest($cookies, (('ssl' == $this->scheme) || ('https' == $this->scheme)));
2979
2980 // build payload
2981 $this->buildPayload($data, $cookie_str);
2982
2983 if ('socket' == $this->io_method()) {
2984 // send payload
2985 if (!fwrite($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2986 $this->setError('couldn\'t write message data to socket');
2987 $this->debug('couldn\'t write message data to socket');
2988 return false;
2989 }
2990 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2991 return true;
2992 } elseif ('curl' == $this->io_method()) {
2993 // set payload
2994 // cURL does say this should only be the verb, and in fact it
2995 // turns out that the URI and HTTP version are appended to this, which
2996 // some servers refuse to work with (so we no longer use this method!)
2997 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2998 $curl_headers = [];
2999 foreach ($this->outgoing_headers as $k => $v) {
3000 if ('Connection' == $k || 'Content-Length' == $k || 'Host' == $k || 'Authorization' == $k || 'Proxy-Authorization' == $k) {
3001 $this->debug("Skip cURL header $k: $v");
3002 } else {
3003 $curl_headers[] = "$k: $v";
3004 }
3005 }
3006 if ('' != $cookie_str) {
3007 $curl_headers[] = 'Cookie: ' . $cookie_str;
3008 }
3009 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
3010 $this->debug('set cURL HTTP headers');
3011 if ('POST' == $this->request_method) {
3012 $this->setCurlOption(CURLOPT_POST, 1);
3013 $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
3014 $this->debug('set cURL POST data');
3015 } else {
3016 }
3017 // insert custom user-set cURL options
3018 foreach ($this->ch_options as $key => $val) {
3019 $this->setCurlOption($key, $val);
3020 }
3021
3022 $this->debug('set cURL payload');
3023 return true;
3024 }
3025 }
3026
3033 public function getResponse()
3034 {
3035 $header_array = [];
3036 $data = null;
3037 $header_data = null;
3038 $this->incoming_payload = '';
3039
3040 if ('socket' == $this->io_method()) {
3041 // loop until headers have been retrieved
3042 $data = '';
3043 while (!isset($lb)) {
3044
3045 // We might EOF during header read.
3046 if (feof($this->fp)) {
3047 $this->incoming_payload = $data;
3048 $this->debug('found no headers before EOF after length ' . strlen($data));
3049 $this->debug("received before EOF:\n" . $data);
3050 $this->setError('server failed to send headers');
3051 return false;
3052 }
3053
3054 $tmp = fgets($this->fp, 256);
3055 $tmplen = strlen($tmp);
3056 $this->debug("read line of $tmplen bytes: " . trim($tmp));
3057
3058 if (0 == $tmplen) {
3059 $this->incoming_payload = $data;
3060 $this->debug('socket read of headers timed out after length ' . strlen($data));
3061 $this->debug('read before timeout: ' . $data);
3062 $this->setError('socket read of headers timed out');
3063 return false;
3064 }
3065
3066 $data .= $tmp;
3067 $pos = strpos($data, "\r\n\r\n");
3068 if ($pos > 1) {
3069 $lb = "\r\n";
3070 } else {
3071 $pos = strpos($data, "\n\n");
3072 if ($pos > 1) {
3073 $lb = "\n";
3074 }
3075 }
3076 // remove 100 headers
3077 if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
3078 unset($lb);
3079 $data = '';
3080 }//
3081 }
3082 // store header data
3083 $this->incoming_payload .= $data;
3084 $this->debug('found end of headers after length ' . strlen($data));
3085 // process headers
3086 $header_data = trim(substr($data, 0, $pos));
3087 $header_array = explode($lb, $header_data);
3088 $this->incoming_headers = [];
3089 $this->incoming_cookies = [];
3090 foreach ($header_array as $header_line) {
3091 $arr = explode(':', $header_line, 2);
3092 if (count($arr) > 1) {
3093 $header_name = strtolower(trim($arr[0]));
3094 $this->incoming_headers[$header_name] = trim($arr[1]);
3095 if ('set-cookie' == $header_name) {
3096 // TODO: allow multiple cookies from parseCookie
3097 $cookie = $this->parseCookie(trim($arr[1]));
3098 if ($cookie) {
3099 $this->incoming_cookies[] = $cookie;
3100 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3101 } else {
3102 $this->debug('did not find cookie in ' . trim($arr[1]));
3103 }
3104 }
3105 } elseif (isset($header_name)) {
3106 // append continuation line to previous header
3107 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3108 }
3109 }
3110
3111 // loop until msg has been received
3112 if (isset($this->incoming_headers['transfer-encoding']) && 'chunked' == strtolower($this->incoming_headers['transfer-encoding'])) {
3113 $content_length = 2_147_483_647; // ignore any content-length header
3114 $chunked = true;
3115 $this->debug('want to read chunked content');
3116 } elseif (isset($this->incoming_headers['content-length'])) {
3117 $content_length = $this->incoming_headers['content-length'];
3118 $chunked = false;
3119 $this->debug("want to read content of length $content_length");
3120 } else {
3121 $content_length = 2_147_483_647;
3122 $chunked = false;
3123 $this->debug('want to read content to EOF');
3124 }
3125 $data = '';
3126 do {
3127 if ($chunked) {
3128 $tmp = fgets($this->fp, 256);
3129 $tmplen = strlen($tmp);
3130 $this->debug("read chunk line of $tmplen bytes");
3131 if (0 == $tmplen) {
3132 $this->incoming_payload = $data;
3133 $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3134 $this->debug("read before timeout:\n" . $data);
3135 $this->setError('socket read of chunk length timed out');
3136 return false;
3137 }
3138 $content_length = hexdec(trim($tmp));
3139 $this->debug("chunk length $content_length");
3140 }
3141 $strlen = 0;
3142 while (($strlen < $content_length) && (!feof($this->fp))) {
3143 $readlen = min(8192, $content_length - $strlen);
3144 $tmp = fread($this->fp, $readlen);
3145 $tmplen = strlen($tmp);
3146 $this->debug("read buffer of $tmplen bytes");
3147 if ((0 == $tmplen) && (!feof($this->fp))) {
3148 $this->incoming_payload = $data;
3149 $this->debug('socket read of body timed out after length ' . strlen($data));
3150 $this->debug("read before timeout:\n" . $data);
3151 $this->setError('socket read of body timed out');
3152 return false;
3153 }
3154 $strlen += $tmplen;
3155 $data .= $tmp;
3156 }
3157 if ($chunked && ($content_length > 0)) {
3158 $tmp = fgets($this->fp, 256);
3159 $tmplen = strlen($tmp);
3160 $this->debug("read chunk terminator of $tmplen bytes");
3161 if (0 == $tmplen) {
3162 $this->incoming_payload = $data;
3163 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3164 $this->debug("read before timeout:\n" . $data);
3165 $this->setError('socket read of chunk terminator timed out');
3166 return false;
3167 }
3168 }
3169 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3170 if (feof($this->fp)) {
3171 $this->debug('read to EOF');
3172 }
3173 $this->debug('read body of length ' . strlen($data));
3174 $this->incoming_payload .= $data;
3175 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
3176
3177 // close filepointer
3178 if (
3179 (isset($this->incoming_headers['connection']) && 'close' == strtolower($this->incoming_headers['connection'])) ||
3180 (! $this->persistentConnection) || feof($this->fp)) {
3181 fclose($this->fp);
3182 $this->fp = false;
3183 $this->debug('closed socket');
3184 }
3185
3186 // connection was closed unexpectedly
3187 if ('' == $this->incoming_payload) {
3188 $this->setError('no response from server');
3189 return false;
3190 }
3191
3192 // decode transfer-encoding
3193// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3194// if(!$data = $this->decodeChunked($data, $lb)){
3195// $this->setError('Decoding of chunked data failed');
3196// return false;
3197// }
3198 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3199 // set decoded payload
3200// $this->incoming_payload = $header_data.$lb.$lb.$data;
3201// }
3202 } elseif ('curl' == $this->io_method()) {
3203 // send and receive
3204 $this->debug('send and receive with cURL');
3205 $this->incoming_payload = curl_exec($this->ch);
3206 $data = $this->incoming_payload;
3207
3208 $cErr = curl_error($this->ch);
3209 if ('' != $cErr) {
3210 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
3211 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3212 foreach (curl_getinfo($this->ch) as $k => $v) {
3213 $err .= "$k: $v<br>";
3214 }
3215 $this->debug($err);
3216 $this->setError($err);
3217 curl_close($this->ch);
3218 return false;
3219 } else {
3220 //echo '<pre>';
3221 //var_dump(curl_getinfo($this->ch));
3222 //echo '</pre>';
3223 }
3224 // close curl
3225 $this->debug('No cURL error, closing cURL');
3226 curl_close($this->ch);
3227
3228 // try removing skippable headers
3229 $savedata = $data;
3230 while ($this->isSkippableCurlHeader($data)) {
3231 $this->debug('Found HTTP header to skip');
3232 if ($pos = strpos($data, "\r\n\r\n")) {
3233 $data = ltrim(substr($data, $pos));
3234 } elseif ($pos = strpos($data, "\n\n")) {
3235 $data = ltrim(substr($data, $pos));
3236 }
3237 }
3238
3239 if ('' == $data) {
3240 // have nothing left; just remove 100 header(s)
3241 $data = $savedata;
3242 while (preg_match('/^HTTP\/1.1 100/', $data)) {
3243 if ($pos = strpos($data, "\r\n\r\n")) {
3244 $data = ltrim(substr($data, $pos));
3245 } elseif ($pos = strpos($data, "\n\n")) {
3246 $data = ltrim(substr($data, $pos));
3247 }
3248 }
3249 }
3250
3251 // separate content from HTTP headers
3252 if ($pos = strpos($data, "\r\n\r\n")) {
3253 $lb = "\r\n";
3254 } elseif ($pos = strpos($data, "\n\n")) {
3255 $lb = "\n";
3256 } else {
3257 $this->debug('no proper separation of headers and document');
3258 $this->setError('no proper separation of headers and document');
3259 return false;
3260 }
3261 $header_data = trim(substr($data, 0, $pos));
3262 $header_array = explode($lb, $header_data);
3263 $data = ltrim(substr($data, $pos));
3264 $this->debug('found proper separation of headers and document');
3265 $this->debug('cleaned data, stringlen: '.strlen($data));
3266 // clean headers
3267 foreach ($header_array as $header_line) {
3268 $arr = explode(':', $header_line, 2);
3269 if (count($arr) > 1) {
3270 $header_name = strtolower(trim($arr[0]));
3271 $this->incoming_headers[$header_name] = trim($arr[1]);
3272 if ('set-cookie' == $header_name) {
3273 // TODO: allow multiple cookies from parseCookie
3274 $cookie = $this->parseCookie(trim($arr[1]));
3275 if ($cookie) {
3276 $this->incoming_cookies[] = $cookie;
3277 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3278 } else {
3279 $this->debug('did not find cookie in ' . trim($arr[1]));
3280 }
3281 }
3282 } elseif (isset($header_name)) {
3283 // append continuation line to previous header
3284 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3285 }
3286 }
3287 }
3288
3289 $this->response_status_line = $header_array[0];
3290 $arr = explode(' ', $this->response_status_line, 3);
3291 $http_version = $arr[0];
3292 $http_status = (int)$arr[1];
3293 $http_reason = count($arr) > 2 ? $arr[2] : '';
3294
3295 // see if we need to resend the request with http digest authentication
3296 if (isset($this->incoming_headers['location']) && (301 == $http_status || 302 == $http_status)) {
3297 $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3298 $this->setURL($this->incoming_headers['location']);
3299 $this->tryagain = true;
3300 return false;
3301 }
3302
3303 // see if we need to resend the request with http digest authentication
3304 if (isset($this->incoming_headers['www-authenticate']) && 401 == $http_status) {
3305 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3306 if (strstr($this->incoming_headers['www-authenticate'], 'Digest ')) {
3307 $this->debug('Server wants digest authentication');
3308 // remove "Digest " from our elements
3309 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3310
3311 // parse elements into array
3312 $digestElements = explode(',', $digestString);
3313 foreach ($digestElements as $val) {
3314 $tempElement = explode('=', trim($val), 2);
3315 $digestRequest[$tempElement[0]] = str_replace('"', '', $tempElement[1]);
3316 }
3317
3318 // should have (at least) qop, realm, nonce
3319 if (isset($digestRequest['nonce'])) {
3320 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3321 $this->tryagain = true;
3322 return false;
3323 }
3324 }
3325 $this->debug('HTTP authentication failed');
3326 $this->setError('HTTP authentication failed');
3327 return false;
3328 }
3329
3330 if (
3331 ($http_status >= 300 && $http_status <= 307) ||
3332 ($http_status >= 400 && $http_status <= 417) ||
3333 ($http_status >= 501 && $http_status <= 505)
3334 ) {
3335 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3336 return false;
3337 }
3338
3339 // decode content-encoding
3340 if (isset($this->incoming_headers['content-encoding']) && '' != $this->incoming_headers['content-encoding']) {
3341 if ('deflate' == strtolower($this->incoming_headers['content-encoding']) || 'gzip' == strtolower($this->incoming_headers['content-encoding'])) {
3342 // if decoding works, use it. else assume data wasn't gzencoded
3343 if (function_exists('gzinflate')) {
3344 //$timer->setMarker('starting decoding of gzip/deflated content');
3345 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3346 // this means there are no Zlib headers, although there should be
3347 $this->debug('The gzinflate function exists');
3348 $datalen = strlen($data);
3349 if ('deflate' == $this->incoming_headers['content-encoding']) {
3350 if ($degzdata = @gzinflate($data)) {
3351 $data = $degzdata;
3352 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3353 if (strlen($data) < $datalen) {
3354 // test for the case that the payload has been compressed twice
3355 $this->debug('The inflated payload is smaller than the gzipped one; try again');
3356 if ($degzdata = @gzinflate($data)) {
3357 $data = $degzdata;
3358 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3359 }
3360 }
3361 } else {
3362 $this->debug('Error using gzinflate to inflate the payload');
3363 $this->setError('Error using gzinflate to inflate the payload');
3364 }
3365 } elseif ('gzip' == $this->incoming_headers['content-encoding']) {
3366 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3367 $data = $degzdata;
3368 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3369 if (strlen($data) < $datalen) {
3370 // test for the case that the payload has been compressed twice
3371 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3372 if ($degzdata = @gzinflate(substr($data, 10))) {
3373 $data = $degzdata;
3374 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3375 }
3376 }
3377 } else {
3378 $this->debug('Error using gzinflate to un-gzip the payload');
3379 $this->setError('Error using gzinflate to un-gzip the payload');
3380 }
3381 }
3382 //$timer->setMarker('finished decoding of gzip/deflated content');
3383 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3384 // set decoded payload
3385 $this->incoming_payload = $header_data.$lb.$lb.$data;
3386 } else {
3387 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3388 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3389 }
3390 } else {
3391 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3392 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3393 }
3394 } else {
3395 $this->debug('No Content-Encoding header');
3396 }
3397
3398 if (0 == strlen($data)) {
3399 $this->debug('no data after headers!');
3400 $this->setError('no data present after HTTP headers');
3401 return false;
3402 }
3403
3404 return $data;
3405 }
3406
3414 public function setContentType($type, $charset = false)
3415 {
3416 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3417 }
3418
3425 public function usePersistentConnection()
3426 {
3427 if (isset($this->outgoing_headers['Accept-Encoding'])) {
3428 return false;
3429 }
3430 $this->protocol_version = '1.1';
3431 $this->persistentConnection = true;
3432 $this->setHeader('Connection', 'Keep-Alive');
3433 return true;
3434 }
3435
3443 /*
3444 * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3445 */
3446 public function parseCookie($cookie_str)
3447 {
3448 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3449 $data = preg_split('/;/', $cookie_str);
3450 $value_str = $data[0];
3451
3452 $cookie_param = 'domain=';
3453 $start = strpos($cookie_str, $cookie_param);
3454 if ($start > 0) {
3455 $domain = substr($cookie_str, $start + strlen($cookie_param));
3456 $domain = substr($domain, 0, strpos($domain, ';'));
3457 } else {
3458 $domain = '';
3459 }
3460
3461 $cookie_param = 'expires=';
3462 $start = strpos($cookie_str, $cookie_param);
3463 if ($start > 0) {
3464 $expires = substr($cookie_str, $start + strlen($cookie_param));
3465 $expires = substr($expires, 0, strpos($expires, ';'));
3466 } else {
3467 $expires = '';
3468 }
3469
3470 $cookie_param = 'path=';
3471 $start = strpos($cookie_str, $cookie_param);
3472 if ($start > 0) {
3473 $path = substr($cookie_str, $start + strlen($cookie_param));
3474 $path = substr($path, 0, strpos($path, ';'));
3475 } else {
3476 $path = '/';
3477 }
3478
3479 $cookie_param = ';secure;';
3480 if (false !== strpos($cookie_str, $cookie_param)) {
3481 $secure = true;
3482 } else {
3483 $secure = false;
3484 }
3485
3486 $sep_pos = strpos($value_str, '=');
3487
3488 if ($sep_pos) {
3489 $name = substr($value_str, 0, $sep_pos);
3490 $value = substr($value_str, $sep_pos + 1);
3491 $cookie= [
3492 'name' => $name,
3493 'value' => $value,
3494 'domain' => $domain,
3495 'path' => $path,
3496 'expires' => $expires,
3497 'secure' => $secure
3498 ];
3499 return $cookie;
3500 }
3501 return false;
3502 }
3503
3512 public function getCookiesForRequest($cookies, $secure=false)
3513 {
3514 $cookie_str = '';
3515 if ((null !== $cookies) && (is_array($cookies))) {
3516 foreach ($cookies as $cookie) {
3517 if (! is_array($cookie)) {
3518 continue;
3519 }
3520 $this->debug('check cookie for validity: ' . $cookie['name'] . '=' . $cookie['value']);
3521 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3522 if (strtotime($cookie['expires']) <= time()) {
3523 $this->debug('cookie has expired');
3524 continue;
3525 }
3526 }
3527 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3528 $domain = preg_quote($cookie['domain']);
3529 if (! preg_match("'.*$domain$'i", $this->host)) {
3530 $this->debug('cookie has different domain');
3531 continue;
3532 }
3533 }
3534 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3535 $path = preg_quote($cookie['path']);
3536 if (! preg_match("'^$path.*'i", $this->path)) {
3537 $this->debug('cookie is for a different path');
3538 continue;
3539 }
3540 }
3541 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3542 $this->debug('cookie is secure, transport is not');
3543 continue;
3544 }
3545 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3546 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3547 }
3548 }
3549 return $cookie_str;
3550 }
3551}
3552
3553?><?php
3554
3555
3556
3568{
3574 public $headers = [];
3580 public $request = '';
3586 public $requestHeaders = '';
3592 public $requestHeader = null;
3598 public $document = '';
3604 public $requestSOAP = '';
3610 public $methodURI = '';
3616 public $methodname = '';
3622 public $methodparams = [];
3628 public $SOAPAction = '';
3634 public $xml_encoding = '';
3640 public $decode_utf8 = true;
3641
3647 public $outgoing_headers = [];
3653 public $response = '';
3659 public $responseHeaders = '';
3665 public $responseSOAP = '';
3671 public $methodreturn = false;
3677 public $methodreturnisliteralxml = false;
3683 public $fault = false;
3689 public $result = 'successful';
3690
3697 public $operations = [];
3703 public $wsdl = false;
3709 public $externalWSDLURL = false;
3715 public $debug_flag = false;
3716
3717
3725 public function __construct($wsdl=false)
3726 {
3727 parent::__construct();
3728 // turn on debugging?
3729 global $debug;
3730 global $_SERVER;
3731
3732 if (isset($_SERVER)) {
3733 $this->debug('_SERVER is defined:');
3734 $this->appendDebug($this->varDump($_SERVER));
3735 } elseif (isset($_SERVER)) {
3736 $this->debug('HTTP_SERVER_VARS is defined:');
3737 $this->appendDebug($this->varDump($_SERVER));
3738 } else {
3739 $this->debug('Neither _SERVER nor HTTP_SERVER_VARS is defined.');
3740 }
3741
3742 if (isset($debug)) {
3743 $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3744 $this->debug_flag = $debug;
3745 } elseif (isset($_SERVER['QUERY_STRING'])) {
3746 $qs = explode('&', $_SERVER['QUERY_STRING']);
3747 foreach ($qs as $v) {
3748 if ('debug=' == substr($v, 0, 6)) {
3749 $this->debug('In nusoap_server, set debug_flag=' . substr($v, 6) . ' based on query string #1');
3750 $this->debug_flag = substr($v, 6);
3751 }
3752 }
3753 } elseif (isset($_SERVER['QUERY_STRING'])) {
3754 $qs = explode('&', $_SERVER['QUERY_STRING']);
3755 foreach ($qs as $v) {
3756 if ('debug=' == substr($v, 0, 6)) {
3757 $this->debug('In nusoap_server, set debug_flag=' . substr($v, 6) . ' based on query string #2');
3758 $this->debug_flag = substr($v, 6);
3759 }
3760 }
3761 }
3762
3763 // wsdl
3764 if ($wsdl) {
3765 $this->debug('In nusoap_server, WSDL is specified');
3766 if (is_object($wsdl) && ('wsdl' == get_class($wsdl))) {
3767 $this->wsdl = $wsdl;
3768 $this->externalWSDLURL = $this->wsdl->wsdl;
3769 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3770 } else {
3771 $this->debug('Create wsdl from ' . $wsdl);
3772 $this->wsdl = new wsdl($wsdl);
3773 $this->externalWSDLURL = $wsdl;
3774 }
3775 $this->appendDebug($this->wsdl->getDebug());
3776 $this->wsdl->clearDebug();
3777 if ($err = $this->wsdl->getError()) {
3778 die('WSDL ERROR: '.$err);
3779 }
3780 }
3781 }
3782
3789 public function service($data)
3790 {
3791 global $_SERVER;
3792
3793 if (isset($_SERVER['REQUEST_METHOD'])) {
3794 $rm = $_SERVER['REQUEST_METHOD'];
3795 } elseif (isset($_SERVER['REQUEST_METHOD'])) {
3796 $rm = $_SERVER['REQUEST_METHOD'];
3797 } else {
3798 $rm = '';
3799 }
3800
3801 if (isset($_SERVER['QUERY_STRING'])) {
3802 $qs = $_SERVER['QUERY_STRING'];
3803 } elseif (isset($_SERVER['QUERY_STRING'])) {
3804 $qs = $_SERVER['QUERY_STRING'];
3805 } else {
3806 $qs = '';
3807 }
3808 $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
3809
3810 if ('POST' == $rm) {
3811 $this->debug('In service, invoke the request');
3812 $this->parse_request($data);
3813 if (! $this->fault) {
3814 $this->invoke_method();
3815 }
3816 if (! $this->fault) {
3817 $this->serialize_return();
3818 }
3819 $this->send_response();
3820 } elseif (preg_match('/wsdl/', $qs)) {
3821 $this->debug('In service, this is a request for WSDL');
3822 if ($this->externalWSDLURL) {
3823 if (false !== strpos($this->externalWSDLURL, 'https://')) { // assume URL
3824 $this->debug('In service, re-direct for WSDL');
3825 header('Location: '.$this->externalWSDLURL);
3826 } else { // assume file
3827 $this->debug('In service, use file passthru for WSDL');
3828 header("Content-Type: text/xml\r\n");
3829 $pos = strpos($this->externalWSDLURL, 'file://');
3830 if (false === $pos) {
3831 $filename = $this->externalWSDLURL;
3832 } else {
3833 $filename = substr($this->externalWSDLURL, $pos + 7);
3834 }
3835 $fp = fopen($this->externalWSDLURL, 'r');
3836 fpassthru($fp);
3837 }
3838 } elseif ($this->wsdl) {
3839 $this->debug('In service, serialize WSDL');
3840 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3841 print $this->wsdl->serialize($this->debug_flag);
3842 if ($this->debug_flag) {
3843 $this->debug('wsdl:');
3844 $this->appendDebug($this->varDump($this->wsdl));
3845 print $this->getDebugAsXMLComment();
3846 }
3847 } else {
3848 $this->debug('In service, there is no WSDL');
3849 header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3850 print 'This service does not provide WSDL';
3851 }
3852 } elseif ($this->wsdl) {
3853 $this->debug('In service, return Web description');
3854 print $this->wsdl->webDescription();
3855 } else {
3856 $this->debug('In service, no Web description');
3857 header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3858 print 'This service does not provide a Web description';
3859 }
3860 }
3861
3874 public function parse_http_headers()
3875 {
3876 global $_SERVER;
3877
3878 $this->request = '';
3879 $this->SOAPAction = '';
3880 if (function_exists('getallheaders')) {
3881 $this->debug('In parse_http_headers, use getallheaders');
3882 $headers = getallheaders();
3883 foreach ($headers as $k=>$v) {
3884 $k = strtolower($k);
3885 $this->headers[$k] = $v;
3886 $this->request .= "$k: $v\r\n";
3887 $this->debug("$k: $v");
3888 }
3889 // get SOAPAction header
3890 if (isset($this->headers['soapaction'])) {
3891 $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
3892 }
3893 // get the character encoding of the incoming request
3894 if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
3895 $enc = str_replace('"', '', substr(strstr($this->headers['content-type'], '='), 1));
3896 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3897 $this->xml_encoding = strtoupper($enc);
3898 } else {
3899 $this->xml_encoding = 'US-ASCII';
3900 }
3901 } else {
3902 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3903 $this->xml_encoding = 'ISO-8859-1';
3904 }
3905 } elseif (isset($_SERVER) && is_array($_SERVER)) {
3906 $this->debug('In parse_http_headers, use _SERVER');
3907 foreach ($_SERVER as $k => $v) {
3908 if ('HTTP_' == substr($k, 0, 5)) {
3909 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3910 } else {
3911 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3912 }
3913 if ('soapaction' == $k) {
3914 // get SOAPAction header
3915 $k = 'SOAPAction';
3916 $v = str_replace('"', '', $v);
3917 $v = str_replace('\\', '', $v);
3918 $this->SOAPAction = $v;
3919 } elseif ('content-type' == $k) {
3920 // get the character encoding of the incoming request
3921 if (strpos($v, '=')) {
3922 $enc = substr(strstr($v, '='), 1);
3923 $enc = str_replace('"', '', $enc);
3924 $enc = str_replace('\\', '', $enc);
3925 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3926 $this->xml_encoding = strtoupper($enc);
3927 } else {
3928 $this->xml_encoding = 'US-ASCII';
3929 }
3930 } else {
3931 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3932 $this->xml_encoding = 'ISO-8859-1';
3933 }
3934 }
3935 $this->headers[$k] = $v;
3936 $this->request .= "$k: $v\r\n";
3937 $this->debug("$k: $v");
3938 }
3939 } elseif (is_array($_SERVER)) {
3940 $this->debug('In parse_http_headers, use HTTP_SERVER_VARS');
3941 foreach ($_SERVER as $k => $v) {
3942 if ('HTTP_' == substr($k, 0, 5)) {
3943 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3944 $k = strtolower(substr($k, 5));
3945 } else {
3946 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3947 $k = strtolower($k);
3948 }
3949 if ('soapaction' == $k) {
3950 // get SOAPAction header
3951 $k = 'SOAPAction';
3952 $v = str_replace('"', '', $v);
3953 $v = str_replace('\\', '', $v);
3954 $this->SOAPAction = $v;
3955 } elseif ('content-type' == $k) {
3956 // get the character encoding of the incoming request
3957 if (strpos($v, '=')) {
3958 $enc = substr(strstr($v, '='), 1);
3959 $enc = str_replace('"', '', $enc);
3960 $enc = str_replace('\\', '', $enc);
3961 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
3962 $this->xml_encoding = strtoupper($enc);
3963 } else {
3964 $this->xml_encoding = 'US-ASCII';
3965 }
3966 } else {
3967 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3968 $this->xml_encoding = 'ISO-8859-1';
3969 }
3970 }
3971 $this->headers[$k] = $v;
3972 $this->request .= "$k: $v\r\n";
3973 $this->debug("$k: $v");
3974 }
3975 } else {
3976 $this->debug('In parse_http_headers, HTTP headers not accessible');
3977 $this->setError('HTTP headers not accessible');
3978 }
3979 }
3980
4003 public function parse_request($data='')
4004 {
4005 $this->debug('entering parse_request()');
4006 $this->parse_http_headers();
4007 $this->debug('got character encoding: '.$this->xml_encoding);
4008 // uncompress if necessary
4009 if (isset($this->headers['content-encoding']) && '' != $this->headers['content-encoding']) {
4010 $this->debug('got content encoding: ' . $this->headers['content-encoding']);
4011 if ('deflate' == $this->headers['content-encoding'] || 'gzip' == $this->headers['content-encoding']) {
4012 // if decoding works, use it. else assume data wasn't gzencoded
4013 if (function_exists('gzuncompress')) {
4014 if ('deflate' == $this->headers['content-encoding'] && $degzdata = @gzuncompress($data)) {
4015 $data = $degzdata;
4016 } elseif ('gzip' == $this->headers['content-encoding'] && $degzdata = gzinflate(substr($data, 10))) {
4017 $data = $degzdata;
4018 } else {
4019 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
4020 return;
4021 }
4022 } else {
4023 $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
4024 return;
4025 }
4026 }
4027 }
4028 $this->request .= "\r\n".$data;
4029 $data = $this->parseRequest($this->headers, $data);
4030 $this->requestSOAP = $data;
4031 $this->debug('leaving parse_request');
4032 }
4033
4051 public function invoke_method()
4052 {
4053 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
4054
4055 //
4056 // if you are debugging in this area of the code, your service uses a class to implement methods,
4057 // you use SOAP RPC, and the client is .NET, please be aware of the following...
4058 // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
4059 // method name. that is fine for naming the .NET methods. it is not fine for properly constructing
4060 // the XML request and reading the XML response. you need to add the RequestElementName and
4061 // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
4062 // generates for the method. these parameters are used to specify the correct XML element names
4063 // for .NET to use, i.e. the names with the '.' in them.
4064 //
4065 $orig_methodname = $this->methodname;
4066 if ($this->wsdl) {
4067 if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
4068 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
4069 $this->appendDebug('opData=' . $this->varDump($this->opData));
4070 } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
4071 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
4072 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
4073 $this->appendDebug('opData=' . $this->varDump($this->opData));
4074 $this->methodname = $this->opData['name'];
4075 } else {
4076 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
4077 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
4078 return;
4079 }
4080 } else {
4081 $this->debug('in invoke_method, no WSDL to validate method');
4082 }
4083
4084 // if a . is present in $this->methodname, we see if there is a class in scope,
4085 // which could be referred to. We will also distinguish between two deliminators,
4086 // to allow methods to be called a the class or an instance
4087 if (strpos($this->methodname, '..') > 0) {
4088 $delim = '..';
4089 } elseif (strpos($this->methodname, '.') > 0) {
4090 $delim = '.';
4091 } else {
4092 $delim = '';
4093 }
4094 $this->debug("in invoke_method, delim=$delim");
4095
4096 $class = '';
4097 $method = '';
4098 if (strlen($delim) > 0 && 1 == substr_count($this->methodname, $delim)) {
4099 $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
4100 if (class_exists($try_class)) {
4101 // get the class and method name
4102 $class = $try_class;
4103 $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
4104 $this->debug("in invoke_method, class=$class method=$method delim=$delim");
4105 } else {
4106 $this->debug("in invoke_method, class=$try_class not found");
4107 }
4108 } else {
4109 $try_class = '';
4110 $this->debug('in invoke_method, no class to try');
4111 }
4112
4113 // does method exist?
4114 if ('' == $class) {
4115 if (!function_exists($this->methodname)) {
4116 $this->debug("in invoke_method, function '$this->methodname' not found!");
4117 $this->result = 'fault: method not found';
4118 $this->fault('SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
4119 return;
4120 }
4121 } else {
4122 $method_to_compare = ('4.' == substr(phpversion(), 0, 2)) ? strtolower($method) : $method;
4123 if (!in_array($method_to_compare, get_class_methods($class))) {
4124 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
4125 $this->result = 'fault: method not found';
4126 $this->fault('SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
4127 return;
4128 }
4129 }
4130
4131 // evaluate message, getting back parameters
4132 // verify that request parameters match the method's signature
4133 if (! $this->verify_method($this->methodname, $this->methodparams)) {
4134 // debug
4135 $this->debug('ERROR: request not verified against method signature');
4136 $this->result = 'fault: request failed validation against method signature';
4137 // return fault
4138 $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
4139 return;
4140 }
4141
4142 // if there are parameters to pass
4143 $this->debug('in invoke_method, params:');
4144 $this->appendDebug($this->varDump($this->methodparams));
4145 $this->debug("in invoke_method, calling '$this->methodname'");
4146 if (!function_exists('call_user_func_array')) {
4147 if ('' == $class) {
4148 $this->debug('in invoke_method, calling function using eval()');
4149 $funcCall = "\$this->methodreturn = $this->methodname(";
4150 } else {
4151 if ('..' == $delim) {
4152 $this->debug('in invoke_method, calling class method using eval()');
4153 $funcCall = '$this->methodreturn = ' . $class . '::' . $method . '(';
4154 } else {
4155 $this->debug('in invoke_method, calling instance method using eval()');
4156 // generate unique instance name
4157 $instname = '$inst_' . time();
4158 $funcCall = $instname . ' = new ' . $class . '(); ';
4159 $funcCall .= '$this->methodreturn = ' . $instname . '->' . $method . '(';
4160 }
4161 }
4162 if ($this->methodparams) {
4163 foreach ($this->methodparams as $param) {
4164 if (is_array($param) || is_object($param)) {
4165 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
4166 return;
4167 }
4168 $funcCall .= "\"$param\",";
4169 }
4170 $funcCall = substr($funcCall, 0, -1);
4171 }
4172 $funcCall .= ');';
4173 $this->debug('in invoke_method, function call: '.$funcCall);
4174 @eval($funcCall);
4175 } else {
4176 if ('' == $class) {
4177 $this->debug('in invoke_method, calling function using call_user_func_array()');
4178 $call_arg = (string)$this->methodname; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4179 } elseif ('..' == $delim) {
4180 $this->debug('in invoke_method, calling class method using call_user_func_array()');
4181 $call_arg = [$class, $method];
4182 } else {
4183 $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4184 $instance = new $class ();
4185 $call_arg = [&$instance, $method];
4186 }
4187 if (is_array($this->methodparams)) {
4188 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4189 } else {
4190 $this->methodreturn = call_user_func_array($call_arg, []);
4191 }
4192 }
4193 $this->debug('in invoke_method, methodreturn:');
4194 $this->appendDebug($this->varDump($this->methodreturn));
4195 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
4196 }
4197
4209 public function serialize_return()
4210 {
4211 $opParams = null;
4212 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4213 // if fault
4214 if (isset($this->methodreturn) && is_object($this->methodreturn) && (('soap_fault' == get_class($this->methodreturn)) || ('nusoap_fault' == get_class($this->methodreturn)))) {
4215 $this->debug('got a fault object from method');
4216 $this->fault = $this->methodreturn;
4217 return;
4218 } elseif ($this->methodreturnisliteralxml) {
4219 $return_val = $this->methodreturn;
4220 // returned value(s)
4221 } else {
4222 $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
4223 $this->debug('serializing return value');
4224 if ($this->wsdl) {
4225 if ((is_countable($this->opData['output']['parts']) ? count($this->opData['output']['parts']) : 0) > 1) {
4226 $this->debug('more than one output part, so use the method return unchanged');
4227 $opParams = $this->methodreturn;
4228 } elseif (1 == (is_countable($this->opData['output']['parts']) ? count($this->opData['output']['parts']) : 0)) {
4229 $this->debug('exactly one output part, so wrap the method return in a simple array');
4230 // TODO: verify that it is not already wrapped!
4231 //foreach ($this->opData['output']['parts'] as $name => $type) {
4232 // $this->debug('wrap in element named ' . $name);
4233 //}
4234 $opParams = [$this->methodreturn];
4235 }
4236 $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams);
4237 $this->appendDebug($this->wsdl->getDebug());
4238 $this->wsdl->clearDebug();
4239 if ($errstr = $this->wsdl->getError()) {
4240 $this->debug('got wsdl error: '.$errstr);
4241 $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4242 return;
4243 }
4244 } else {
4245 if (isset($this->methodreturn)) {
4246 $return_val = $this->serialize_val($this->methodreturn, 'return');
4247 } else {
4248 $return_val = '';
4249 $this->debug('in absence of WSDL, assume void return for backward compatibility');
4250 }
4251 }
4252 }
4253 $this->debug('return value:');
4254 $this->appendDebug($this->varDump($return_val));
4255
4256 $this->debug('serializing response');
4257 if ($this->wsdl) {
4258 $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4259 if ('rpc' == $this->opData['style']) {
4260 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4261 if ('literal' == $this->opData['output']['use']) {
4262 // https://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
4263 if ($this->methodURI) {
4264 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname . 'Response>';
4265 } else {
4266 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
4267 }
4268 } else {
4269 if ($this->methodURI) {
4270 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname . 'Response>';
4271 } else {
4272 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
4273 }
4274 }
4275 } else {
4276 $this->debug('style is not rpc for serialization: assume document');
4277 $payload = $return_val;
4278 }
4279 } else {
4280 $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4281 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname . 'Response>';
4282 }
4283 $this->result = 'successful';
4284 if ($this->wsdl) {
4285 //if($this->debug_flag){
4286 $this->appendDebug($this->wsdl->getDebug());
4287 // }
4288 if (isset($this->opData['output']['encodingStyle'])) {
4289 $encodingStyle = $this->opData['output']['encodingStyle'];
4290 } else {
4291 $encodingStyle = '';
4292 }
4293 // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4294 $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
4295 } else {
4296 $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
4297 }
4298 $this->debug('Leaving serialize_return');
4299 }
4300
4311 public function send_response()
4312 {
4313 $this->debug('Enter send_response');
4314 if ($this->fault) {
4315 $payload = $this->fault->serialize();
4316 $this->outgoing_headers[] = 'HTTP/1.0 500 Internal Server Error';
4317 $this->outgoing_headers[] = 'Status: 500 Internal Server Error';
4318 } else {
4319 $payload = $this->responseSOAP;
4320 // Some combinations of PHP+Web server allow the Status
4321 // to come through as a header. Since OK is the default
4322 // just do nothing.
4323 // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4324 // $this->outgoing_headers[] = "Status: 200 OK";
4325 }
4326 // add debug data if in debug mode
4327 if (isset($this->debug_flag) && $this->debug_flag) {
4328 $payload .= $this->getDebugAsXMLComment();
4329 }
4330 $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4331 preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4332 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1] . ')';
4333 // Let the Web server decide about this
4334 //$this->outgoing_headers[] = "Connection: Close\r\n";
4335 $payload = $this->getHTTPBody($payload);
4336 $type = $this->getHTTPContentType();
4337 $charset = $this->getHTTPContentTypeCharset();
4338 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4339 //begin code to compress payload - by John
4340 // NOTE: there is no way to know whether the Web server will also compress
4341 // this data.
4342 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4343 if (strstr($this->headers['accept-encoding'], 'gzip')) {
4344 if (function_exists('gzencode')) {
4345 if (isset($this->debug_flag) && $this->debug_flag) {
4346 $payload .= '<!-- Content being gzipped -->';
4347 }
4348 $this->outgoing_headers[] = 'Content-Encoding: gzip';
4349 $payload = gzencode($payload);
4350 } else {
4351 if (isset($this->debug_flag) && $this->debug_flag) {
4352 $payload .= '<!-- Content will not be gzipped: no gzencode -->';
4353 }
4354 }
4355 } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4356 // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4357 // instead of gzcompress output,
4358 // which conflicts with HTTP 1.1 spec (https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4359 if (function_exists('gzdeflate')) {
4360 if (isset($this->debug_flag) && $this->debug_flag) {
4361 $payload .= '<!-- Content being deflated -->';
4362 }
4363 $this->outgoing_headers[] = 'Content-Encoding: deflate';
4364 $payload = gzdeflate($payload);
4365 } else {
4366 if (isset($this->debug_flag) && $this->debug_flag) {
4367 $payload .= '<!-- Content will not be deflated: no gzcompress -->';
4368 }
4369 }
4370 }
4371 }
4372 //end code
4373 $this->outgoing_headers[] = 'Content-Length: ' . strlen($payload);
4374 reset($this->outgoing_headers);
4375 foreach ($this->outgoing_headers as $hdr) {
4376 header($hdr, false);
4377 }
4378 print $payload;
4379 $this->response = implode("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
4380 }
4381
4391 public function verify_method($operation, $request)
4392 {
4393 if (isset($this->wsdl) && is_object($this->wsdl)) {
4394 if ($this->wsdl->getOperationData($operation)) {
4395 return true;
4396 }
4397 } elseif (isset($this->operations[$operation])) {
4398 return true;
4399 }
4400 return false;
4401 }
4402
4411 public function parseRequest($headers, $data)
4412 {
4413 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
4414 $this->appendDebug($this->varDump($headers));
4415 if (!isset($headers['content-type'])) {
4416 $this->setError('Request not of type text/xml (no content-type header)');
4417 return false;
4418 }
4419 if (!strstr($headers['content-type'], 'text/xml')) {
4420 $this->setError('Request not of type text/xml');
4421 return false;
4422 }
4423 if (strpos($headers['content-type'], '=')) {
4424 $enc = str_replace('"', '', substr(strstr($headers['content-type'], '='), 1));
4425 $this->debug('Got response encoding: ' . $enc);
4426 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4427 $this->xml_encoding = strtoupper($enc);
4428 } else {
4429 $this->xml_encoding = 'US-ASCII';
4430 }
4431 } else {
4432 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4433 $this->xml_encoding = 'ISO-8859-1';
4434 }
4435 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4436 // parse response, get soap parser obj
4437 $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
4438 // parser debug
4439 $this->debug("parser debug: \n".$parser->getDebug());
4440 // if fault occurred during message parsing
4441 if ($err = $parser->getError()) {
4442 $this->result = 'fault: error in msg parsing: '.$err;
4443 $this->fault('SOAP-ENV:Client', "error in msg parsing:\n".$err);
4444 // else successfully parsed request into soapval object
4445 } else {
4446 // get/set methodname
4447 $this->methodURI = $parser->root_struct_namespace;
4448 $this->methodname = $parser->root_struct_name;
4449 $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
4450 $this->debug('calling parser->get_soapbody()');
4451 $this->methodparams = $parser->get_soapbody();
4452 // get SOAP headers
4453 $this->requestHeaders = $parser->getHeaders();
4454 // get SOAP Header
4455 $this->requestHeader = $parser->get_soapheader();
4456 // add document for doclit support
4457 $this->document = $parser->document;
4458 }
4459 }
4460
4468 public function getHTTPBody($soapmsg)
4469 {
4470 return $soapmsg;
4471 }
4472
4481 public function getHTTPContentType()
4482 {
4483 return 'text/xml';
4484 }
4485
4496 {
4497 return $this->soap_defencoding;
4498 }
4499
4509 public function add_to_map($methodname, $in, $out)
4510 {
4511 $this->operations[$methodname] = ['name' => $methodname, 'in' => $in, 'out' => $out];
4512 }
4513
4529 public function register($name, $in= [], $out= [], $namespace=false, $soapaction=false, $style=false, $use=false, $documentation='', $encodingStyle='')
4530 {
4531 global $_SERVER;
4532
4533 if ($this->externalWSDLURL) {
4534 die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4535 }
4536 if (! $name) {
4537 die('You must specify a name when you register an operation');
4538 }
4539 if (!is_array($in)) {
4540 die('You must provide an array for operation inputs');
4541 }
4542 if (!is_array($out)) {
4543 die('You must provide an array for operation outputs');
4544 }
4545 if (false == $namespace) {
4546 }
4547 if (false == $soapaction) {
4548 if (isset($_SERVER)) {
4549 $SERVER_NAME = $_SERVER['SERVER_NAME'];
4550 $SCRIPT_NAME = $_SERVER['PHP_SELF'] ?? $_SERVER['SCRIPT_NAME'];
4551 $HTTPS = $_SERVER['HTTPS'] ?? $_SERVER['HTTPS'] ?? 'off';
4552 } elseif (isset($_SERVER)) {
4553 $SERVER_NAME = $_SERVER['SERVER_NAME'];
4554 $SCRIPT_NAME = $_SERVER['PHP_SELF'] ?? $_SERVER['SCRIPT_NAME'];
4555 $HTTPS = $_SERVER['HTTPS'] ?? 'off';
4556 } else {
4557 $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
4558 }
4559 if ('1' == $HTTPS || 'on' == $HTTPS) {
4560 $SCHEME = 'https';
4561 } else {
4562 $SCHEME = 'http';
4563 }
4564 $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4565 }
4566 if (false == $style) {
4567 $style = 'rpc';
4568 }
4569 if (false == $use) {
4570 $use = 'encoded';
4571 }
4572 if ('encoded' == $use && '' == $encodingStyle) {
4573 $encodingStyle = 'https://schemas.xmlsoap.org/soap/encoding/';
4574 }
4575
4576 $this->operations[$name] = [
4577 'name' => $name,
4578 'in' => $in,
4579 'out' => $out,
4580 'namespace' => $namespace,
4581 'soapaction' => $soapaction,
4582 'style' => $style
4583 ];
4584 if ($this->wsdl) {
4585 $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
4586 }
4587 return true;
4588 }
4589
4600 public function fault($faultcode, $faultstring, $faultactor='', $faultdetail='')
4601 {
4602 if ('' == $faultdetail && $this->debug_flag) {
4603 $faultdetail = $this->getDebug();
4604 }
4605 $this->fault = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
4606 $this->fault->soap_defencoding = $this->soap_defencoding;
4607 }
4608
4620 public function configureWSDL($serviceName, $namespace = false, $endpoint = false, $style='rpc', $transport = 'https://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4621 {
4622 global $_SERVER;
4623
4624 if (isset($_SERVER)) {
4625 $SERVER_NAME = $_SERVER['SERVER_NAME'];
4626 $SERVER_PORT = $_SERVER['SERVER_PORT'];
4627 $SCRIPT_NAME = $_SERVER['PHP_SELF'] ?? $_SERVER['SCRIPT_NAME'];
4628 $HTTPS = $_SERVER['HTTPS'] ?? $_SERVER['HTTPS'] ?? 'off';
4629 } elseif (isset($_SERVER)) {
4630 $SERVER_NAME = $_SERVER['SERVER_NAME'];
4631 $SERVER_PORT = $_SERVER['SERVER_PORT'];
4632 $SCRIPT_NAME = $_SERVER['PHP_SELF'] ?? $_SERVER['SCRIPT_NAME'];
4633 $HTTPS = $_SERVER['HTTPS'] ?? 'off';
4634 } else {
4635 $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
4636 }
4637 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4638 $colon = strpos($SERVER_NAME, ':');
4639 if ($colon) {
4640 $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4641 }
4642 if (80 == $SERVER_PORT) {
4643 $SERVER_PORT = '';
4644 } else {
4645 $SERVER_PORT = ':' . $SERVER_PORT;
4646 }
4647 if (false == $namespace) {
4648 $namespace = "https://$SERVER_NAME/soap/$serviceName";
4649 }
4650
4651 if (false == $endpoint) {
4652 if ('1' == $HTTPS || 'on' == $HTTPS) {
4653 $SCHEME = 'https';
4654 } else {
4655 $SCHEME = 'http';
4656 }
4657 $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4658 }
4659
4660 if (false == $schemaTargetNamespace) {
4661 $schemaTargetNamespace = $namespace;
4662 }
4663
4664 $this->wsdl = new wsdl();
4665 $this->wsdl->serviceName = $serviceName;
4666 $this->wsdl->endpoint = $endpoint;
4667 $this->wsdl->namespaces['tns'] = $namespace;
4668 $this->wsdl->namespaces['soap'] = 'https://schemas.xmlsoap.org/wsdl/soap/';
4669 $this->wsdl->namespaces['wsdl'] = 'https://schemas.xmlsoap.org/wsdl/';
4670 if ($schemaTargetNamespace != $namespace) {
4671 $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4672 }
4673 $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4674 if ('document' == $style) {
4675 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4676 }
4677 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4678 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['https://schemas.xmlsoap.org/soap/encoding/'][0] = ['location' => '', 'loaded' => true];
4679 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['https://schemas.xmlsoap.org/wsdl/'][0] = ['location' => '', 'loaded' => true];
4680 $this->wsdl->bindings[$serviceName.'Binding'] = [
4681 'name'=>$serviceName.'Binding',
4682 'style'=>$style,
4683 'transport'=>$transport,
4684 'portType'=>$serviceName.'PortType'
4685 ];
4686 $this->wsdl->ports[$serviceName.'Port'] = [
4687 'binding'=>$serviceName.'Binding',
4688 'location'=>$endpoint,
4689 'bindingType'=>'https://schemas.xmlsoap.org/wsdl/soap/'
4690 ];
4691 }
4692}
4693
4698{
4699}
4700
4701?><?php
4702
4703
4704
4714class wsdl extends nusoap_base
4715{
4716 // URL or filename of the root of this WSDL
4717 public $wsdl;
4718 // define internal arrays of bindings, ports, operations, messages, etc.
4719 public $schemas = [];
4720 public $currentSchema;
4721 public $message = [];
4722 public $complexTypes = [];
4723 public $messages = [];
4724 public $currentMessage;
4725 public $currentOperation;
4726 public $portTypes = [];
4727 public $currentPortType;
4728 public $bindings = [];
4729 public $currentBinding;
4730 public $ports = [];
4731 public $currentPort;
4732 public $opData = [];
4733 public $status = '';
4734 public $documentation = false;
4735 public $endpoint = '';
4736 // array of wsdl docs to import
4737 public $import = [];
4738 // parser vars
4739 public $parser;
4740 public $position = 0;
4741 public $depth = 0;
4742 public $depth_array = [];
4743 // for getting wsdl
4744 public $proxyhost = '';
4745 public $proxyport = '';
4746 public $proxyusername = '';
4747 public $proxypassword = '';
4748 public $timeout = 0;
4749 public $response_timeout = 30;
4750 public $curl_options = []; // User-specified cURL options
4751 public $use_curl = false; // whether to always try to use cURL
4752 // for HTTP authentication
4753 public $username = ''; // Username for HTTP authentication
4754 public $password = ''; // Password for HTTP authentication
4755 public $authtype = ''; // Type of HTTP authentication
4756 public $certRequest = []; // Certificate for HTTP SSL authentication
4757
4772 public function __construct($wsdl = '', $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30, $curl_options=null, $use_curl=false)
4773 {
4774 parent::__construct();
4775 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4776 $this->proxyhost = $proxyhost;
4777 $this->proxyport = $proxyport;
4778 $this->proxyusername = $proxyusername;
4779 $this->proxypassword = $proxypassword;
4780 $this->timeout = $timeout;
4781 $this->response_timeout = $response_timeout;
4782 if (is_array($curl_options)) {
4783 $this->curl_options = $curl_options;
4784 }
4785 $this->use_curl = $use_curl;
4786 $this->fetchWSDL($wsdl);
4787 }
4788
4795 public function fetchWSDL($wsdl)
4796 {
4797 $this->debug("parse and process WSDL path=$wsdl");
4798 $this->wsdl = $wsdl;
4799 // parse wsdl file
4800 if ('' != $this->wsdl) {
4801 $this->parseWSDL($this->wsdl);
4802 }
4803 // imports
4804 // TODO: handle imports more properly, grabbing them in-line and nesting them
4805 $imported_urls = [];
4806 $imported = 1;
4807 while ($imported > 0) {
4808 $imported = 0;
4809 // Schema imports
4810 foreach ($this->schemas as $ns => $list) {
4811 foreach ($list as $xs) {
4812 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4813 foreach ($xs->imports as $ns2 => $list2) {
4814 for ($ii = 0; $ii < (is_countable($list2) ? count($list2) : 0); $ii++) {
4815 if (! $list2[$ii]['loaded']) {
4816 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4817 $url = $list2[$ii]['location'];
4818 if ('' != $url) {
4819 $urlparts = parse_url($url);
4820 if (!isset($urlparts['host'])) {
4821 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
4822 substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) .$urlparts['path'];
4823 }
4824 if (! in_array($url, $imported_urls)) {
4825 $this->parseWSDL($url);
4826 $imported++;
4827 $imported_urls[] = $url;
4828 }
4829 } else {
4830 $this->debug('Unexpected scenario: empty URL for unloaded import');
4831 }
4832 }
4833 }
4834 }
4835 }
4836 }
4837 // WSDL imports
4838 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4839 foreach ($this->import as $ns => $list) {
4840 for ($ii = 0; $ii < (is_countable($list) ? count($list) : 0); $ii++) {
4841 if (! $list[$ii]['loaded']) {
4842 $this->import[$ns][$ii]['loaded'] = true;
4843 $url = $list[$ii]['location'];
4844 if ('' != $url) {
4845 $urlparts = parse_url($url);
4846 if (!isset($urlparts['host'])) {
4847 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4848 substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) .$urlparts['path'];
4849 }
4850 if (! in_array($url, $imported_urls)) {
4851 $this->parseWSDL($url);
4852 $imported++;
4853 $imported_urls[] = $url;
4854 }
4855 } else {
4856 $this->debug('Unexpected scenario: empty URL for unloaded import');
4857 }
4858 }
4859 }
4860 }
4861 }
4862 // add new data to operation data
4863 foreach ($this->bindings as $binding => $bindingData) {
4864 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4865 foreach ($bindingData['operations'] as $operation => $data) {
4866 $this->debug('post-parse data gathering for ' . $operation);
4867 $this->bindings[$binding]['operations'][$operation]['input'] =
4868 isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4869 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4870 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4871 $this->bindings[$binding]['operations'][$operation]['output'] =
4872 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4873 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4874 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4875 if (isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])) {
4876 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4877 }
4878 if (isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])) {
4879 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4880 }
4881 // Set operation style if necessary, but do not override one already provided
4882 if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4883 $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4884 }
4885 $this->bindings[$binding]['operations'][$operation]['transport'] = $bindingData['transport'] ?? '';
4886 $this->bindings[$binding]['operations'][$operation]['documentation'] = $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] ?? '';
4887 $this->bindings[$binding]['operations'][$operation]['endpoint'] = $bindingData['endpoint'] ?? '';
4888 }
4889 }
4890 }
4891 }
4892
4900 public function parseWSDL($wsdl = '')
4901 {
4902 $this->debug("parse WSDL at path=$wsdl");
4903
4904 if ('' == $wsdl) {
4905 $this->debug('no wsdl passed to parseWSDL()!!');
4906 $this->setError('no wsdl passed to parseWSDL()!!');
4907 return false;
4908 }
4909
4910 // parse $wsdl for url format
4911 $wsdl_props = parse_url($wsdl);
4912
4913 if (isset($wsdl_props['scheme']) && ('http' == $wsdl_props['scheme'] || 'https' == $wsdl_props['scheme'])) {
4914 $this->debug('getting WSDL http(s) URL ' . $wsdl);
4915 // get wsdl
4916 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4917 $tr->request_method = 'GET';
4918 $tr->useSOAPAction = false;
4919 if ($this->proxyhost && $this->proxyport) {
4920 $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
4921 }
4922 if ('' != $this->authtype) {
4923 $tr->setCredentials($this->username, $this->password, $this->authtype, [], $this->certRequest);
4924 }
4925 $tr->setEncoding('gzip, deflate');
4926 $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4927 //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4928 //$this->debug("WSDL response\n" . $tr->incoming_payload);
4929 $this->appendDebug($tr->getDebug());
4930 // catch errors
4931 if ($err = $tr->getError()) {
4932 $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err;
4933 $this->debug($errstr);
4934 $this->setError($errstr);
4935 unset($tr);
4936 return false;
4937 }
4938 unset($tr);
4939 $this->debug('got WSDL URL');
4940 } else {
4941 // $wsdl is not http(s), so treat it as a file URL or plain file path
4942 if (isset($wsdl_props['scheme']) && ('file' == $wsdl_props['scheme']) && isset($wsdl_props['path'])) {
4943 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4944 } else {
4945 $path = $wsdl;
4946 }
4947 $this->debug('getting WSDL file ' . $path);
4948 if ($fp = @fopen($path, 'r')) {
4949 $wsdl_string = '';
4950 while ($data = fread($fp, 32768)) {
4951 $wsdl_string .= $data;
4952 }
4953 fclose($fp);
4954 } else {
4955 $errstr = "Bad path to WSDL file $path";
4956 $this->debug($errstr);
4957 $this->setError($errstr);
4958 return false;
4959 }
4960 }
4961 $this->debug('Parse WSDL');
4962 // end new code added
4963 // Create an XML parser.
4964 $this->parser = xml_parser_create();
4965 // Set the options for parsing the XML data.
4966 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4967 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4968 // Set the object for the parser.
4969 xml_set_object($this->parser, $this);
4970 // Set the element handlers for the parser.
4971 xml_set_element_handler($this->parser, 'start_element', 'end_element');
4972 xml_set_character_data_handler($this->parser, 'character_data');
4973 // Parse the XML file.
4974 if (!xml_parse($this->parser, $wsdl_string, true)) {
4975 // Display an error message.
4976 $errstr = sprintf(
4977 'XML error parsing WSDL from %s on line %d: %s',
4978 $wsdl,
4979 xml_get_current_line_number($this->parser),
4980 xml_error_string(xml_get_error_code($this->parser))
4981 );
4982 $this->debug($errstr);
4983 $this->debug("XML payload:\n" . $wsdl_string);
4984 $this->setError($errstr);
4985 return false;
4986 }
4987 // free the parser
4988 xml_parser_free($this->parser);
4989 $this->debug('Parsing WSDL done');
4990 // catch wsdl parse errors
4991 if ($this->getError()) {
4992 return false;
4993 }
4994 return true;
4995 }
4996
5005 public function start_element($parser, $name, $attrs)
5006 {
5007 if ('schema' == $this->status) {
5008 $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5009 $this->appendDebug($this->currentSchema->getDebug());
5010 $this->currentSchema->clearDebug();
5011 } elseif (preg_match('/schema$/', $name)) {
5012 $this->debug('Parsing WSDL schema');
5013 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
5014 $this->status = 'schema';
5015 $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
5016 $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5017 $this->appendDebug($this->currentSchema->getDebug());
5018 $this->currentSchema->clearDebug();
5019 } else {
5020 // position in the total number of elements, starting from 0
5021 $pos = $this->position++;
5022 $depth = $this->depth++;
5023 // set self as current value for this depth
5024 $this->depth_array[$depth] = $pos;
5025 $this->message[$pos] = ['cdata' => ''];
5026 // process attributes
5027 if ((is_countable($attrs) ? count($attrs) : 0) > 0) {
5028 // register namespace declarations
5029 foreach ($attrs as $k => $v) {
5030 if (preg_match('/^xmlns/', $k)) {
5031 if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
5032 $this->namespaces[$ns_prefix] = $v;
5033 } else {
5034 $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
5035 }
5036 if ('https://www.w3.org/2001/XMLSchema' == $v || 'https://www.w3.org/1999/XMLSchema' == $v || 'https://www.w3.org/2000/10/XMLSchema' == $v) {
5037 $this->XMLSchemaVersion = $v;
5038 $this->namespaces['xsi'] = $v . '-instance';
5039 }
5040 }
5041 }
5042 // expand each attribute prefix to its namespace
5043 foreach ($attrs as $k => $v) {
5044 $k = strpos($k, ':') ? $this->expandQname($k) : $k;
5045 if ('location' != $k && 'soapAction' != $k && 'namespace' != $k) {
5046 $v = strpos($v, ':') ? $this->expandQname($v) : $v;
5047 }
5048 $eAttrs[$k] = $v;
5049 }
5050 $attrs = $eAttrs;
5051 } else {
5052 $attrs = [];
5053 }
5054 // get element prefix, namespace and name
5055 if (preg_match('/:/', $name)) {
5056 // get ns prefix
5057 $prefix = substr($name, 0, strpos($name, ':'));
5058 // get ns
5059 $namespace = $this->namespaces[$prefix] ?? '';
5060 // get unqualified name
5061 $name = substr(strstr($name, ':'), 1);
5062 }
5063 // process attributes, expanding any prefixes to namespaces
5064 // find status, register data
5065 switch ($this->status) {
5066 case 'message':
5067 if ('part' == $name) {
5068 if (isset($attrs['type'])) {
5069 $this->debug('msg ' . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
5070 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
5071 }
5072 if (isset($attrs['element'])) {
5073 $this->debug('msg ' . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
5074 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
5075 }
5076 }
5077 break;
5078 case 'portType':
5079 switch ($name) {
5080 case 'operation':
5081 $this->currentPortOperation = $attrs['name'];
5082 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
5083 if (isset($attrs['parameterOrder'])) {
5084 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
5085 }
5086 break;
5087 case 'documentation':
5088 $this->documentation = true;
5089 break;
5090 // merge input/output data
5091 default:
5092 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
5093 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
5094 break;
5095 }
5096 break;
5097 case 'binding':
5098 switch ($name) {
5099 case 'binding':
5100 // get ns prefix
5101 if (isset($attrs['style'])) {
5102 $this->bindings[$this->currentBinding]['prefix'] = $prefix;
5103 }
5104 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
5105 break;
5106 case 'header':
5107 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
5108 break;
5109 case 'operation':
5110 if (isset($attrs['soapAction'])) {
5111 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
5112 }
5113 if (isset($attrs['style'])) {
5114 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
5115 }
5116 if (isset($attrs['name'])) {
5117 $this->currentOperation = $attrs['name'];
5118 $this->debug("current binding operation: $this->currentOperation");
5119 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
5120 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
5121 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = $this->bindings[$this->currentBinding]['endpoint'] ?? '';
5122 }
5123 break;
5124 case 'input':
5125 $this->opStatus = 'input';
5126 break;
5127 case 'output':
5128 $this->opStatus = 'output';
5129 break;
5130 case 'body':
5131 if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
5132 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
5133 } else {
5134 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
5135 }
5136 break;
5137 }
5138 break;
5139 case 'service':
5140 switch ($name) {
5141 case 'port':
5142 $this->currentPort = $attrs['name'];
5143 $this->debug('current port: ' . $this->currentPort);
5144 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
5145
5146 break;
5147 case 'address':
5148 $this->ports[$this->currentPort]['location'] = $attrs['location'];
5149 $this->ports[$this->currentPort]['bindingType'] = $namespace;
5150 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
5151 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
5152 break;
5153 }
5154 break;
5155 }
5156 // set status
5157 switch ($name) {
5158 case 'import':
5159 if (isset($attrs['location'])) {
5160 $this->import[$attrs['namespace']][] = ['location' => $attrs['location'], 'loaded' => false];
5161 $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . (is_countable($this->import[$attrs['namespace']]) ? count($this->import[$attrs['namespace']]) : 0).')');
5162 } else {
5163 $this->import[$attrs['namespace']][] = ['location' => '', 'loaded' => true];
5164 if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
5165 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
5166 }
5167 $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . (is_countable($this->import[$attrs['namespace']]) ? count($this->import[$attrs['namespace']]) : 0).')');
5168 }
5169 break;
5170 //wait for schema
5171 //case 'types':
5172 // $this->status = 'schema';
5173 // break;
5174 case 'message':
5175 $this->status = 'message';
5176 $this->messages[$attrs['name']] = [];
5177 $this->currentMessage = $attrs['name'];
5178 break;
5179 case 'portType':
5180 $this->status = 'portType';
5181 $this->portTypes[$attrs['name']] = [];
5182 $this->currentPortType = $attrs['name'];
5183 break;
5184 case 'binding':
5185 if (isset($attrs['name'])) {
5186 // get binding name
5187 if (strpos($attrs['name'], ':')) {
5188 $this->currentBinding = $this->getLocalPart($attrs['name']);
5189 } else {
5190 $this->currentBinding = $attrs['name'];
5191 }
5192 $this->status = 'binding';
5193 $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
5194 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
5195 }
5196 break;
5197 case 'service':
5198 $this->serviceName = $attrs['name'];
5199 $this->status = 'service';
5200 $this->debug('current service: ' . $this->serviceName);
5201 break;
5202 case 'definitions':
5203 foreach ($attrs as $name => $value) {
5204 $this->wsdl_info[$name] = $value;
5205 }
5206 break;
5207 }
5208 }
5209 }
5210
5218 public function end_element($parser, $name)
5219 {
5220 // unset schema status
5221 if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
5222 $this->status = '';
5223 $this->appendDebug($this->currentSchema->getDebug());
5224 $this->currentSchema->clearDebug();
5225 $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5226 $this->debug('Parsing WSDL schema done');
5227 }
5228 if ('schema' == $this->status) {
5229 $this->currentSchema->schemaEndElement($parser, $name);
5230 } else {
5231 // bring depth down a notch
5232 $this->depth--;
5233 }
5234 // end documentation
5235 if ($this->documentation) {
5236 //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5237 //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5238 $this->documentation = false;
5239 }
5240 }
5241
5249 public function character_data($parser, $data)
5250 {
5251 $pos = $this->depth_array[$this->depth] ?? 0;
5252 if (isset($this->message[$pos]['cdata'])) {
5253 $this->message[$pos]['cdata'] .= $data;
5254 }
5255 if ($this->documentation) {
5256 $this->documentation .= $data;
5257 }
5258 }
5259
5269 public function setCredentials($username, $password, $authtype = 'basic', $certRequest = [])
5270 {
5271 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5272 $this->appendDebug($this->varDump($certRequest));
5273 $this->username = $username;
5274 $this->password = $password;
5275 $this->authtype = $authtype;
5276 $this->certRequest = $certRequest;
5277 }
5278
5279 public function getBindingData($binding)
5280 {
5281 if (is_array($this->bindings[$binding])) {
5282 return $this->bindings[$binding];
5283 }
5284 }
5285
5294 public function getOperations($portName = '', $bindingType = 'soap')
5295 {
5296 $ops = [];
5297 if ('soap' == $bindingType) {
5298 $bindingType = 'https://schemas.xmlsoap.org/wsdl/soap/';
5299 } elseif ('soap12' == $bindingType) {
5300 $bindingType = 'https://schemas.xmlsoap.org/wsdl/soap12/';
5301 } else {
5302 $this->debug("getOperations bindingType $bindingType may not be supported");
5303 }
5304 $this->debug("getOperations for port '$portName' bindingType $bindingType");
5305 // loop thru ports
5306 foreach ($this->ports as $port => $portData) {
5307 $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
5308 if ('' == $portName || $port == $portName) {
5309 // binding type of port matches parameter
5310 if ($portData['bindingType'] == $bindingType) {
5311 $this->debug("getOperations found port $port bindingType $bindingType");
5312 //$this->debug("port data: " . $this->varDump($portData));
5313 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5314 // merge bindings
5315 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5316 $ops = array_merge($ops, $this->bindings[ $portData['binding'] ]['operations']);
5317 }
5318 }
5319 }
5320 }
5321 if (0 == count($ops)) {
5322 $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
5323 }
5324 return $ops;
5325 }
5326
5335 public function getOperationData($operation, $bindingType = 'soap')
5336 {
5337 if ('soap' == $bindingType) {
5338 $bindingType = 'https://schemas.xmlsoap.org/wsdl/soap/';
5339 } elseif ('soap12' == $bindingType) {
5340 $bindingType = 'https://schemas.xmlsoap.org/wsdl/soap12/';
5341 }
5342 // loop thru ports
5343 foreach ($this->ports as $port => $portData) {
5344 // binding type of port matches parameter
5345 if ($portData['bindingType'] == $bindingType) {
5346 // get binding
5347 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5348 foreach (array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5349 // note that we could/should also check the namespace here
5350 if ($operation == $bOperation) {
5351 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5352 return $opData;
5353 }
5354 }
5355 }
5356 }
5357 }
5358
5367 public function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
5368 {
5369 if ('soap' == $bindingType) {
5370 $bindingType = 'https://schemas.xmlsoap.org/wsdl/soap/';
5371 } elseif ('soap12' == $bindingType) {
5372 $bindingType = 'https://schemas.xmlsoap.org/wsdl/soap12/';
5373 }
5374 // loop thru ports
5375 foreach ($this->ports as $port => $portData) {
5376 // binding type of port matches parameter
5377 if ($portData['bindingType'] == $bindingType) {
5378 // loop through operations for the binding
5379 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5380 if ($opData['soapAction'] == $soapAction) {
5381 return $opData;
5382 }
5383 }
5384 }
5385 }
5386 }
5387
5406 public function getTypeDef($type, $ns)
5407 {
5408 $this->debug("in getTypeDef: type=$type, ns=$ns");
5409 if ((! $ns) && isset($this->namespaces['tns'])) {
5410 $ns = $this->namespaces['tns'];
5411 $this->debug("in getTypeDef: type namespace forced to $ns");
5412 }
5413 if (!isset($this->schemas[$ns])) {
5414 foreach ($this->schemas as $ns0 => $schema0) {
5415 if (0 == strcasecmp($ns, $ns0)) {
5416 $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5417 $ns = $ns0;
5418 break;
5419 }
5420 }
5421 }
5422 if (isset($this->schemas[$ns])) {
5423 $this->debug("in getTypeDef: have schema for namespace $ns");
5424 for ($i = 0; $i < (is_countable($this->schemas[$ns]) ? count($this->schemas[$ns]) : 0); $i++) {
5425 $xs = &$this->schemas[$ns][$i];
5426 $t = $xs->getTypeDef($type);
5427 $this->appendDebug($xs->getDebug());
5428 $xs->clearDebug();
5429 if ($t) {
5430 $this->debug("in getTypeDef: found type $type");
5431 if (!isset($t['phpType'])) {
5432 // get info for type to tack onto the element
5433 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5434 $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5435 $etype = $this->getTypeDef($uqType, $ns);
5436 if ($etype) {
5437 $this->debug("found type for [element] $type:");
5438 $this->debug($this->varDump($etype));
5439 if (isset($etype['phpType'])) {
5440 $t['phpType'] = $etype['phpType'];
5441 }
5442 if (isset($etype['elements'])) {
5443 $t['elements'] = $etype['elements'];
5444 }
5445 if (isset($etype['attrs'])) {
5446 $t['attrs'] = $etype['attrs'];
5447 }
5448 } else {
5449 $this->debug("did not find type for [element] $type");
5450 }
5451 }
5452 return $t;
5453 }
5454 }
5455 $this->debug("in getTypeDef: did not find type $type");
5456 } else {
5457 $this->debug("in getTypeDef: do not have schema for namespace $ns");
5458 }
5459 return false;
5460 }
5461
5467 public function webDescription()
5468 {
5469 global $_SERVER;
5470
5471 if (isset($_SERVER)) {
5472 $PHP_SELF = $_SERVER['PHP_SELF'];
5473 } elseif (isset($_SERVER)) {
5474 $PHP_SELF = $_SERVER['PHP_SELF'];
5475 } else {
5476 $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
5477 }
5478
5479 $b = '
5480 <html><head><title>NuSOAP: '.$this->serviceName.'</title>
5481 <style type="text/css">
5482 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5483 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5484 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5485 ul { margin-top: 10px; margin-left: 20px; }
5486 li { list-style-type: none; margin-top: 10px; color: #000000; }
5487 .content{
5488 margin-left: 0px; padding-bottom: 2em; }
5489 .nav {
5490 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5491 margin-top: 10px; margin-left: 0px; color: #000000;
5492 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5493 .title {
5494 font-family: arial; font-size: 26px; color: #ffffff;
5495 background-color: #999999; width: 100%;
5496 margin-left: 0px; margin-right: 0px;
5497 padding-top: 10px; padding-bottom: 10px;}
5498 .hidden {
5499 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5500 font-family: arial; overflow: hidden; width: 600;
5501 padding: 20px; font-size: 10px; background-color: #999999;
5502 layer-background-color:#FFFFFF; }
5503 a,a:active { color: charcoal; font-weight: bold; }
5504 a:visited { color: #666666; font-weight: bold; }
5505 a:hover { color: cc3300; font-weight: bold; }
5506 </style>
5507 <script language="JavaScript" type="text/javascript">
5508 <!--
5509 // POP-UP CAPTIONS...
5510 function lib_bwcheck(){ //Browsercheck (needed)
5511 this.ver=navigator.appVersion
5512 this.agent=navigator.userAgent
5513 this.dom=document.getElementById?1:0
5514 this.opera5=this.agent.indexOf("Opera 5")>-1
5515 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5516 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5517 this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5518 this.ie=this.ie4||this.ie5||this.ie6
5519 this.mac=this.agent.indexOf("Mac")>-1
5520 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5521 this.ns4=(document.layers && !this.dom)?1:0;
5522 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5523 return this
5524 }
5525 var bw = new lib_bwcheck()
5526 //Makes crossbrowser object.
5527 function makeObj(obj){
5528 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5529 if(!this.evnt) return false
5530 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5531 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5532 this.writeIt=b_writeIt;
5533 return this
5534 }
5535 // A unit of measure that will be added when setting the position of a layer.
5536 //var px = bw.ns4||window.opera?"":"px";
5537 function b_writeIt(text){
5538 if (bw.ns4){this.wref.write(text);this.wref.close()}
5539 else this.wref.innerHTML = text
5540 }
5541 //Shows the messages
5542 var oDesc;
5543 function popup(divid){
5544 if(oDesc = new makeObj(divid)){
5545 oDesc.css.visibility = "visible"
5546 }
5547 }
5548 function popout(){ // Hides message
5549 if(oDesc) oDesc.css.visibility = "hidden"
5550 }
5551 //-->
5552 </script>
5553 </head>
5554 <body>
5555 <div class=content>
5556 <br><br>
5557 <div class=title>'.$this->serviceName.'</div>
5558 <div class=nav>
5559 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
5560 Click on an operation name to view it&apos;s details.</p>
5561 <ul>';
5562 foreach ($this->getOperations() as $op => $data) {
5563 $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5564 // create hidden div
5565 $b .= "<div id='$op' class='hidden'>
5566 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5567 foreach ($data as $donnie => $marie) { // loop through opdata
5568 if ('input' == $donnie || 'output' == $donnie) { // show input/output data
5569 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
5570 foreach ($marie as $captain => $tenille) { // loop through data
5571 if ('parts' == $captain) { // loop thru parts
5572 $b .= "&nbsp;&nbsp;$captain:<br>";
5573 //if(is_array($tenille)){
5574 foreach ($tenille as $joanie => $chachi) {
5575 $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5576 }
5577 //}
5578 } else {
5579 $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5580 }
5581 }
5582 } else {
5583 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
5584 }
5585 }
5586 $b .= '</div>';
5587 }
5588 $b .= '
5589 <ul>
5590 </div>
5591 </div></body></html>';
5592 return $b;
5593 }
5594
5602 public function serialize($debug = 0)
5603 {
5604 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5605 $xml .= "\n<definitions";
5606 foreach ($this->namespaces as $k => $v) {
5607 $xml .= " xmlns:$k=\"$v\"";
5608 }
5609 // 10.9.02 - add poulter fix for wsdl and tns declarations
5610 if (isset($this->namespaces['wsdl'])) {
5611 $xml .= ' xmlns="' . $this->namespaces['wsdl'] . '"';
5612 }
5613 if (isset($this->namespaces['tns'])) {
5614 $xml .= ' targetNamespace="' . $this->namespaces['tns'] . '"';
5615 }
5616 $xml .= '>';
5617 // imports
5618 if (count($this->import) > 0) {
5619 foreach ($this->import as $ns => $list) {
5620 foreach ($list as $ii) {
5621 if ('' != $ii['location']) {
5622 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5623 } else {
5624 $xml .= '<import namespace="' . $ns . '" />';
5625 }
5626 }
5627 }
5628 }
5629 // types
5630 if (count($this->schemas)>=1) {
5631 $xml .= "\n<types>\n";
5632 foreach ($this->schemas as $ns => $list) {
5633 foreach ($list as $xs) {
5634 $xml .= $xs->serializeSchema();
5635 }
5636 }
5637 $xml .= '</types>';
5638 }
5639 // messages
5640 if (count($this->messages) >= 1) {
5641 foreach ($this->messages as $msgName => $msgParts) {
5642 $xml .= "\n<message name=\"" . $msgName . '">';
5643 if (is_array($msgParts)) {
5644 foreach ($msgParts as $partName => $partType) {
5645 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5646 if (strpos($partType, ':')) {
5647 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5648 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5649 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5650 $typePrefix = 'xsd';
5651 } else {
5652 foreach ($this->typemap as $ns => $types) {
5653 if (isset($types[$partType])) {
5654 $typePrefix = $this->getPrefixFromNamespace($ns);
5655 }
5656 }
5657 if (!isset($typePrefix)) {
5658 die("$partType has no namespace!");
5659 }
5660 }
5661 $ns = $this->getNamespaceFromPrefix($typePrefix);
5662 $localPart = $this->getLocalPart($partType);
5663 $typeDef = $this->getTypeDef($localPart, $ns);
5664 if ('element' == $typeDef['typeClass']) {
5665 $elementortype = 'element';
5666 if ('^' == substr($localPart, -1)) {
5667 $localPart = substr($localPart, 0, -1);
5668 }
5669 } else {
5670 $elementortype = 'type';
5671 }
5672 $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5673 }
5674 }
5675 $xml .= '</message>';
5676 }
5677 }
5678 // bindings & porttypes
5679 if (count($this->bindings) >= 1) {
5680 $binding_xml = '';
5681 $portType_xml = '';
5682 foreach ($this->bindings as $bindingName => $attrs) {
5683 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5684 $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5685 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5686 foreach ($attrs['operations'] as $opName => $opParts) {
5687 $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5688 $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
5689 if (isset($opParts['input']['encodingStyle']) && '' != $opParts['input']['encodingStyle']) {
5690 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5691 } else {
5692 $enc_style = '';
5693 }
5694 $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5695 if (isset($opParts['output']['encodingStyle']) && '' != $opParts['output']['encodingStyle']) {
5696 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5697 } else {
5698 $enc_style = '';
5699 }
5700 $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5701 $binding_xml .= "\n" . ' </operation>';
5702 $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5703 if (isset($opParts['parameterOrder'])) {
5704 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5705 }
5706 $portType_xml .= '>';
5707 if (isset($opParts['documentation']) && '' != $opParts['documentation']) {
5708 $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5709 }
5710 $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5711 $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5712 $portType_xml .= "\n" . ' </operation>';
5713 }
5714 $portType_xml .= "\n" . '</portType>';
5715 $binding_xml .= "\n" . '</binding>';
5716 }
5717 $xml .= $portType_xml . $binding_xml;
5718 }
5719 // services
5720 $xml .= "\n<service name=\"" . $this->serviceName . '">';
5721 if (count($this->ports) >= 1) {
5722 foreach ($this->ports as $pName => $attrs) {
5723 $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5724 $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5725 $xml .= "\n" . ' </port>';
5726 }
5727 }
5728 $xml .= "\n" . '</service>';
5729 return $xml . "\n</definitions>";
5730 }
5731
5741 public function parametersMatchWrapped($type, &$parameters)
5742 {
5743 $this->debug("in parametersMatchWrapped type=$type, parameters=");
5744 $this->appendDebug($this->varDump($parameters));
5745
5746 // split type into namespace:unqualified-type
5747 if (strpos($type, ':')) {
5748 $uqType = substr($type, strrpos($type, ':') + 1);
5749 $ns = substr($type, 0, strrpos($type, ':'));
5750 $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5751 if ($this->getNamespaceFromPrefix($ns)) {
5752 $ns = $this->getNamespaceFromPrefix($ns);
5753 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5754 }
5755 } else {
5756 // TODO: should the type be compared to types in XSD, and the namespace
5757 // set to XSD if the type matches?
5758 $this->debug("in parametersMatchWrapped: No namespace for type $type");
5759 $ns = '';
5760 $uqType = $type;
5761 }
5762
5763 // get the type information
5764 if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5765 $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5766 return false;
5767 }
5768 $this->debug('in parametersMatchWrapped: found typeDef=');
5769 $this->appendDebug($this->varDump($typeDef));
5770 if ('^' == substr($uqType, -1)) {
5771 $uqType = substr($uqType, 0, -1);
5772 }
5773 $phpType = $typeDef['phpType'];
5774 $arrayType = ($typeDef['arrayType'] ?? '');
5775 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5776
5777 // we expect a complexType or element of complexType
5778 if ('struct' != $phpType) {
5779 $this->debug('in parametersMatchWrapped: not a struct');
5780 return false;
5781 }
5782
5783 // see whether the parameter names match the elements
5784 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5785 $elements = 0;
5786 $matches = 0;
5787 foreach ($typeDef['elements'] as $name => $attrs) {
5788 if (isset($parameters[$name])) {
5789 $this->debug("in parametersMatchWrapped: have parameter named $name");
5790 $matches++;
5791 } else {
5792 $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5793 }
5794 $elements++;
5795 }
5796
5797 $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5798 if (0 == $matches) {
5799 return false;
5800 }
5801 return true;
5802 }
5803
5804 // since there are no elements for the type, if the user passed no
5805 // parameters, the parameters match wrapped.
5806 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5807 return 0 == count($parameters);
5808 }
5809
5825 public function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
5826 {
5827 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5828 $this->appendDebug('parameters=' . $this->varDump($parameters));
5829
5830 if ('input' != $direction && 'output' != $direction) {
5831 $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5832 $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5833 return false;
5834 }
5835 if (!$opData = $this->getOperationData($operation, $bindingType)) {
5836 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5837 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5838 return false;
5839 }
5840 $this->debug('in serializeRPCParameters: opData:');
5841 $this->appendDebug($this->varDump($opData));
5842
5843 // Get encoding style for output and set to current
5844 $encodingStyle = 'https://schemas.xmlsoap.org/soap/encoding/';
5845 if (('input' == $direction) && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5846 $encodingStyle = $opData['output']['encodingStyle'];
5847 $enc_style = $encodingStyle;
5848 }
5849
5850 // set input params
5851 $xml = '';
5852 if (isset($opData[$direction]['parts']) && (is_countable($opData[$direction]['parts']) ? count($opData[$direction]['parts']) : 0) > 0) {
5853 $parts = &$opData[$direction]['parts'];
5854 $part_count = is_countable($parts) ? count($parts) : 0;
5855 $style = $opData['style'];
5856 $use = $opData[$direction]['use'];
5857 $this->debug("have $part_count part(s) to serialize using $style/$use");
5858 if (is_array($parameters)) {
5859 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5860 $parameter_count = count($parameters);
5861 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5862 // check for Microsoft-style wrapped parameters
5863 if ('document' == $style && 'literal' == $use && 1 == $part_count && isset($parts['parameters'])) {
5864 $this->debug('check whether the caller has wrapped the parameters');
5865 if ('output' == $direction && 'arraySimple' == $parametersArrayType && 1 == $parameter_count) {
5866 // TODO: consider checking here for double-wrapping, when
5867 // service function wraps, then NuSOAP wraps again
5868 $this->debug("change simple array to associative with 'parameters' element");
5869 $parameters['parameters'] = $parameters[0];
5870 unset($parameters[0]);
5871 }
5872 if (('arrayStruct' == $parametersArrayType || 0 == $parameter_count) && !isset($parameters['parameters'])) {
5873 $this->debug('check whether caller\'s parameters match the wrapped ones');
5874 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5875 $this->debug('wrap the parameters for the caller');
5876 $parameters = ['parameters' => $parameters];
5877 $parameter_count = 1;
5878 }
5879 }
5880 }
5881 foreach ($parts as $name => $type) {
5882 $this->debug("serializing part $name of type $type");
5883 // Track encoding style
5884 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5885 $encodingStyle = $opData[$direction]['encodingStyle'];
5886 $enc_style = $encodingStyle;
5887 } else {
5888 $enc_style = false;
5889 }
5890 // NOTE: add error handling here
5891 // if serializeType returns false, then catch global error and fault
5892 if ('arraySimple' == $parametersArrayType) {
5893 $p = array_shift($parameters);
5894 $this->debug('calling serializeType w/indexed param');
5895 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5896 } elseif (isset($parameters[$name])) {
5897 $this->debug('calling serializeType w/named param');
5898 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5899 } else {
5900 // TODO: only send nillable
5901 $this->debug('calling serializeType w/null param');
5902 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5903 }
5904 }
5905 } else {
5906 $this->debug('no parameters passed.');
5907 }
5908 }
5909 $this->debug("serializeRPCParameters returning: $xml");
5910 return $xml;
5911 }
5912
5927 public function serializeParameters($operation, $direction, $parameters)
5928 {
5929 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5930 $this->appendDebug('parameters=' . $this->varDump($parameters));
5931
5932 if ('input' != $direction && 'output' != $direction) {
5933 $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5934 $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5935 return false;
5936 }
5937 if (!$opData = $this->getOperationData($operation)) {
5938 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5939 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5940 return false;
5941 }
5942 $this->debug('opData:');
5943 $this->appendDebug($this->varDump($opData));
5944
5945 // Get encoding style for output and set to current
5946 $encodingStyle = 'https://schemas.xmlsoap.org/soap/encoding/';
5947 if (('input' == $direction) && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5948 $encodingStyle = $opData['output']['encodingStyle'];
5949 $enc_style = $encodingStyle;
5950 }
5951
5952 // set input params
5953 $xml = '';
5954 if (isset($opData[$direction]['parts']) && (is_countable($opData[$direction]['parts']) ? count($opData[$direction]['parts']) : 0) > 0) {
5955 $use = $opData[$direction]['use'];
5956 $this->debug("use=$use");
5957 $this->debug('got ' . (is_countable($opData[$direction]['parts']) ? count($opData[$direction]['parts']) : 0) . ' part(s)');
5958 if (is_array($parameters)) {
5959 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5960 $this->debug('have ' . $parametersArrayType . ' parameters');
5961 foreach ($opData[$direction]['parts'] as $name => $type) {
5962 $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5963 // Track encoding style
5964 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5965 $encodingStyle = $opData[$direction]['encodingStyle'];
5966 $enc_style = $encodingStyle;
5967 } else {
5968 $enc_style = false;
5969 }
5970 // NOTE: add error handling here
5971 // if serializeType returns false, then catch global error and fault
5972 if ('arraySimple' == $parametersArrayType) {
5973 $p = array_shift($parameters);
5974 $this->debug('calling serializeType w/indexed param');
5975 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5976 } elseif (isset($parameters[$name])) {
5977 $this->debug('calling serializeType w/named param');
5978 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5979 } else {
5980 // TODO: only send nillable
5981 $this->debug('calling serializeType w/null param');
5982 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5983 }
5984 }
5985 } else {
5986 $this->debug('no parameters passed.');
5987 }
5988 }
5989 $this->debug("serializeParameters returning: $xml");
5990 return $xml;
5991 }
5992
6005 public function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
6006 {
6007 $cols = null;
6008 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? 'unqualified' : 'qualified'));
6009 $this->appendDebug('value=' . $this->varDump($value));
6010 if ('encoded' == $use && $encodingStyle) {
6011 $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
6012 }
6013
6014 // if a soapval has been supplied, let its type override the WSDL
6015 if (is_object($value) && 'soapval' == get_class($value)) {
6016 if ($value->type_ns) {
6017 $type = $value->type_ns . ':' . $value->type;
6018 $forceType = true;
6019 $this->debug("in serializeType: soapval overrides type to $type");
6020 } elseif ($value->type) {
6021 $type = $value->type;
6022 $forceType = true;
6023 $this->debug("in serializeType: soapval overrides type to $type");
6024 } else {
6025 $forceType = false;
6026 $this->debug('in serializeType: soapval does not override type');
6027 }
6028 $attrs = $value->attributes;
6029 $value = $value->value;
6030 $this->debug("in serializeType: soapval overrides value to $value");
6031 if ($attrs) {
6032 if (!is_array($value)) {
6033 $value['!'] = $value;
6034 }
6035 foreach ($attrs as $n => $v) {
6036 $value['!' . $n] = $v;
6037 }
6038 $this->debug('in serializeType: soapval provides attributes');
6039 }
6040 } else {
6041 $forceType = false;
6042 }
6043
6044 $xml = '';
6045 if (strpos($type, ':')) {
6046 $uqType = substr($type, strrpos($type, ':') + 1);
6047 $ns = substr($type, 0, strrpos($type, ':'));
6048 $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
6049 if ($this->getNamespaceFromPrefix($ns)) {
6050 $ns = $this->getNamespaceFromPrefix($ns);
6051 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
6052 }
6053
6054 if ($ns == $this->XMLSchemaVersion || 'https://schemas.xmlsoap.org/soap/encoding/' == $ns) {
6055 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
6056 if ($unqualified && 'literal' == $use) {
6057 $elementNS = ' xmlns=""';
6058 } else {
6059 $elementNS = '';
6060 }
6061 if (null === $value) {
6062 if ('literal' == $use) {
6063 // TODO: depends on minOccurs
6064 $xml = "<$name$elementNS/>";
6065 } else {
6066 // TODO: depends on nillable, which should be checked before calling this method
6067 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6068 }
6069 $this->debug("in serializeType: returning: $xml");
6070 return $xml;
6071 }
6072 if ('Array' == $uqType) {
6073 // JBoss/Axis does this sometimes
6074 return $this->serialize_val($value, $name, false, false, false, false, $use);
6075 }
6076 if ('boolean' == $uqType) {
6077 if ((is_string($value) && 'false' == $value) || (! $value)) {
6078 $value = 'false';
6079 } else {
6080 $value = 'true';
6081 }
6082 }
6083 if ('string' == $uqType && 'string' == gettype($value)) {
6084 $value = $this->expandEntities($value);
6085 }
6086 if (('long' == $uqType || 'unsignedLong' == $uqType) && 'double' == gettype($value)) {
6087 $value = sprintf('%.0lf', $value);
6088 }
6089 // it's a scalar
6090 // TODO: what about null/nil values?
6091 // check type isn't a custom type extending xmlschema namespace
6092 if (!$this->getTypeDef($uqType, $ns)) {
6093 if ('literal' == $use) {
6094 if ($forceType) {
6095 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6096 } else {
6097 $xml = "<$name$elementNS>$value</$name>";
6098 }
6099 } else {
6100 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6101 }
6102 $this->debug("in serializeType: returning: $xml");
6103 return $xml;
6104 }
6105 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
6106 } elseif ('https://xml.apache.org/xml-soap' == $ns) {
6107 $this->debug('in serializeType: appears to be Apache SOAP type');
6108 if ('Map' == $uqType) {
6109 $tt_prefix = $this->getPrefixFromNamespace('https://xml.apache.org/xml-soap');
6110 if (! $tt_prefix) {
6111 $this->debug('in serializeType: Add namespace for Apache SOAP type');
6112 $tt_prefix = 'ns' . random_int(1000, 9999);
6113 $this->namespaces[$tt_prefix] = 'https://xml.apache.org/xml-soap';
6114 // force this to be added to usedNamespaces
6115 $tt_prefix = $this->getPrefixFromNamespace('https://xml.apache.org/xml-soap');
6116 }
6117 $contents = '';
6118 foreach ($value as $k => $v) {
6119 $this->debug("serializing map element: key $k, value $v");
6120 $contents .= '<item>';
6121 $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
6122 $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
6123 $contents .= '</item>';
6124 }
6125 if ('literal' == $use) {
6126 if ($forceType) {
6127 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6128 } else {
6129 $xml = "<$name>$contents</$name>";
6130 }
6131 } else {
6132 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6133 }
6134 $this->debug("in serializeType: returning: $xml");
6135 return $xml;
6136 }
6137 $this->debug('in serializeType: Apache SOAP type, but only support Map');
6138 }
6139 } else {
6140 // TODO: should the type be compared to types in XSD, and the namespace
6141 // set to XSD if the type matches?
6142 $this->debug("in serializeType: No namespace for type $type");
6143 $ns = '';
6144 $uqType = $type;
6145 }
6146 if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6147 $this->setError("$type ($uqType) is not a supported type.");
6148 $this->debug("in serializeType: $type ($uqType) is not a supported type.");
6149 return false;
6150 } else {
6151 $this->debug('in serializeType: found typeDef');
6152 $this->appendDebug('typeDef=' . $this->varDump($typeDef));
6153 if ('^' == substr($uqType, -1)) {
6154 $uqType = substr($uqType, 0, -1);
6155 }
6156 }
6157 if (!isset($typeDef['phpType'])) {
6158 $this->setError("$type ($uqType) has no phpType.");
6159 $this->debug("in serializeType: $type ($uqType) has no phpType.");
6160 return false;
6161 }
6162 $phpType = $typeDef['phpType'];
6163 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . ($typeDef['arrayType'] ?? ''));
6164 // if php type == struct, map value to the <all> element names
6165 if ('struct' == $phpType) {
6166 if (isset($typeDef['typeClass']) && 'element' == $typeDef['typeClass']) {
6167 $elementName = $uqType;
6168 if (isset($typeDef['form']) && ('qualified' == $typeDef['form'])) {
6169 $elementNS = " xmlns=\"$ns\"";
6170 } else {
6171 $elementNS = ' xmlns=""';
6172 }
6173 } else {
6174 $elementName = $name;
6175 if ($unqualified) {
6176 $elementNS = ' xmlns=""';
6177 } else {
6178 $elementNS = '';
6179 }
6180 }
6181 if (null === $value) {
6182 if ('literal' == $use) {
6183 // TODO: depends on minOccurs and nillable
6184 $xml = "<$elementName$elementNS/>";
6185 } else {
6186 $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6187 }
6188 $this->debug("in serializeType: returning: $xml");
6189 return $xml;
6190 }
6191 if (is_object($value)) {
6192 $value = get_object_vars($value);
6193 }
6194 if (is_array($value)) {
6195 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6196 if ('literal' == $use) {
6197 if ($forceType) {
6198 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6199 } else {
6200 $xml = "<$elementName$elementNS$elementAttrs>";
6201 }
6202 } else {
6203 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
6204 }
6205
6206 if (isset($typeDef['simpleContent']) && 'true' == $typeDef['simpleContent']) {
6207 if (isset($value['!'])) {
6208 $xml .= $value['!'];
6209 $this->debug("in serializeType: serialized simpleContent for type $type");
6210 } else {
6211 $this->debug("in serializeType: no simpleContent to serialize for type $type");
6212 }
6213 } else {
6214 // complexContent
6215 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6216 }
6217 $xml .= "</$elementName>";
6218 } else {
6219 $this->debug('in serializeType: phpType is struct, but value is not an array');
6220 $this->setError('phpType is struct, but value is not an array: see debug output for details');
6221 $xml = '';
6222 }
6223 } elseif ('array' == $phpType) {
6224 if (isset($typeDef['form']) && ('qualified' == $typeDef['form'])) {
6225 $elementNS = " xmlns=\"$ns\"";
6226 } else {
6227 if ($unqualified) {
6228 $elementNS = ' xmlns=""';
6229 } else {
6230 $elementNS = '';
6231 }
6232 }
6233 if (null === $value) {
6234 if ('literal' == $use) {
6235 // TODO: depends on minOccurs
6236 $xml = "<$name$elementNS/>";
6237 } else {
6238 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
6239 $this->getPrefixFromNamespace('https://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' .
6240 $this->getPrefixFromNamespace('https://schemas.xmlsoap.org/soap/encoding/') .
6241 ':arrayType="' .
6242 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
6243 ':' .
6244 $this->getLocalPart($typeDef['arrayType']) . '[0]"/>';
6245 }
6246 $this->debug("in serializeType: returning: $xml");
6247 return $xml;
6248 }
6249 if (isset($typeDef['multidimensional'])) {
6250 $nv = [];
6251 foreach ($value as $v) {
6252 $cols = ',' . (is_countable($v) ? count($v) : 0);
6253 $nv = array_merge($nv, $v);
6254 }
6255 $value = $nv;
6256 } else {
6257 $cols = '';
6258 }
6259 if (is_array($value) && count($value) >= 1) {
6260 $rows = count($value);
6261 $contents = '';
6262 foreach ($value as $k => $v) {
6263 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6264 //if (strpos($typeDef['arrayType'], ':') ) {
6265 if (!in_array($typeDef['arrayType'], $this->typemap['https://www.w3.org/2001/XMLSchema'])) {
6266 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6267 } else {
6268 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6269 }
6270 }
6271 } else {
6272 $rows = 0;
6273 $contents = null;
6274 }
6275 // TODO: for now, an empty value will be serialized as a zero element
6276 // array. Revisit this when coding the handling of null/nil values.
6277 if ('literal' == $use) {
6278 $xml = "<$name$elementNS>"
6279 .$contents
6280 ."</$name>";
6281 } else {
6282 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('https://schemas.xmlsoap.org/soap/encoding/').':Array" '.
6283 $this->getPrefixFromNamespace('https://schemas.xmlsoap.org/soap/encoding/')
6284 .':arrayType="'
6285 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6286 . ':' . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">"
6287 .$contents
6288 ."</$name>";
6289 }
6290 } elseif ('scalar' == $phpType) {
6291 if (isset($typeDef['form']) && ('qualified' == $typeDef['form'])) {
6292 $elementNS = " xmlns=\"$ns\"";
6293 } else {
6294 if ($unqualified) {
6295 $elementNS = ' xmlns=""';
6296 } else {
6297 $elementNS = '';
6298 }
6299 }
6300 if ('literal' == $use) {
6301 if ($forceType) {
6302 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6303 } else {
6304 $xml = "<$name$elementNS>$value</$name>";
6305 }
6306 } else {
6307 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6308 }
6309 }
6310 $this->debug("in serializeType: returning: $xml");
6311 return $xml;
6312 }
6313
6324 public function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
6325 {
6326 $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
6327 $xml = '';
6328 if (isset($typeDef['extensionBase'])) {
6329 $nsx = $this->getPrefix($typeDef['extensionBase']);
6330 $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6331 if ($this->getNamespaceFromPrefix($nsx)) {
6332 $nsx = $this->getNamespaceFromPrefix($nsx);
6333 }
6334 if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6335 $this->debug("serialize attributes for extension base $nsx:$uqTypex");
6336 $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
6337 } else {
6338 $this->debug("extension base $nsx:$uqTypex is not a supported type");
6339 }
6340 }
6341 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6342 $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6343 if (is_array($value)) {
6344 $xvalue = $value;
6345 } elseif (is_object($value)) {
6346 $xvalue = get_object_vars($value);
6347 } else {
6348 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6349 $xvalue = [];
6350 }
6351 foreach ($typeDef['attrs'] as $aName => $attrs) {
6352 if (isset($xvalue['!' . $aName])) {
6353 $xname = '!' . $aName;
6354 $this->debug("value provided for attribute $aName with key $xname");
6355 } elseif (isset($xvalue[$aName])) {
6356 $xname = $aName;
6357 $this->debug("value provided for attribute $aName with key $xname");
6358 } elseif (isset($attrs['default'])) {
6359 $xname = '!' . $aName;
6360 $xvalue[$xname] = $attrs['default'];
6361 $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6362 } else {
6363 $xname = '';
6364 $this->debug("no value provided for attribute $aName");
6365 }
6366 if ($xname) {
6367 $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . '"';
6368 }
6369 }
6370 } else {
6371 $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6372 }
6373 return $xml;
6374 }
6375
6388 public function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false)
6389 {
6390 $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
6391 $xml = '';
6392 if (isset($typeDef['extensionBase'])) {
6393 $nsx = $this->getPrefix($typeDef['extensionBase']);
6394 $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6395 if ($this->getNamespaceFromPrefix($nsx)) {
6396 $nsx = $this->getNamespaceFromPrefix($nsx);
6397 }
6398 if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6399 $this->debug("serialize elements for extension base $nsx:$uqTypex");
6400 $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
6401 } else {
6402 $this->debug("extension base $nsx:$uqTypex is not a supported type");
6403 }
6404 }
6405 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6406 $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6407 if (is_array($value)) {
6408 $xvalue = $value;
6409 } elseif (is_object($value)) {
6410 $xvalue = get_object_vars($value);
6411 } else {
6412 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6413 $xvalue = [];
6414 }
6415 // toggle whether all elements are present - ideally should validate against schema
6416 if (count($typeDef['elements']) != count($xvalue)) {
6417 $optionals = true;
6418 }
6419 foreach ($typeDef['elements'] as $eName => $attrs) {
6420 if (!isset($xvalue[$eName])) {
6421 if (isset($attrs['default'])) {
6422 $xvalue[$eName] = $attrs['default'];
6423 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6424 }
6425 }
6426 // if user took advantage of a minOccurs=0, then only serialize named parameters
6427 if (isset($optionals)
6428 && (!isset($xvalue[$eName]))
6429 && ((!isset($attrs['nillable'])) || 'true' != $attrs['nillable'])
6430 ) {
6431 if (isset($attrs['minOccurs']) && '0' <> $attrs['minOccurs']) {
6432 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6433 }
6434 // do nothing
6435 $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6436 } else {
6437 // get value
6438 if (isset($xvalue[$eName])) {
6439 $v = $xvalue[$eName];
6440 } else {
6441 $v = null;
6442 }
6443 if (isset($attrs['form'])) {
6444 $unqualified = ('unqualified' == $attrs['form']);
6445 } else {
6446 $unqualified = false;
6447 }
6448 if (isset($attrs['maxOccurs']) && ('unbounded' == $attrs['maxOccurs'] || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && 'arraySimple' == $this->isArraySimpleOrStruct($v)) {
6449 $vv = $v;
6450 foreach ($vv as $k => $v) {
6451 if (isset($attrs['type']) || isset($attrs['ref'])) {
6452 // serialize schema-defined type
6453 $xml .= $this->serializeType($eName, $attrs['type'] ?? $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6454 } else {
6455 // serialize generic type (can this ever really happen?)
6456 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6457 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6458 }
6459 }
6460 } else {
6461 if (null === $v && isset($attrs['minOccurs']) && '0' == $attrs['minOccurs']) {
6462 // do nothing
6463 } elseif (null === $v && isset($attrs['nillable']) && 'true' == $attrs['nillable']) {
6464 // TODO: serialize a nil correctly, but for now serialize schema-defined type
6465 $xml .= $this->serializeType($eName, $attrs['type'] ?? $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6466 } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
6467 // serialize schema-defined type
6468 $xml .= $this->serializeType($eName, $attrs['type'] ?? $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6469 } else {
6470 // serialize generic type (can this ever really happen?)
6471 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6472 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6473 }
6474 }
6475 }
6476 }
6477 } else {
6478 $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6479 }
6480 return $xml;
6481 }
6482
6497 public function addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements= [], $attrs= [], $arrayType='')
6498 {
6499 if (count($elements) > 0) {
6500 $eElements = [];
6501 foreach ($elements as $n => $e) {
6502 // expand each element
6503 $ee = [];
6504 foreach ($e as $k => $v) {
6505 $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6506 $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6507 $ee[$k] = $v;
6508 }
6509 $eElements[$n] = $ee;
6510 }
6511 $elements = $eElements;
6512 }
6513
6514 if (count($attrs) > 0) {
6515 foreach ($attrs as $n => $a) {
6516 // expand each attribute
6517 foreach ($a as $k => $v) {
6518 $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6519 $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6520 $aa[$k] = $v;
6521 }
6522 $eAttrs[$n] = $aa;
6523 }
6524 $attrs = $eAttrs;
6525 }
6526
6527 $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6528 $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
6529
6530 $typens = $this->namespaces['types'] ?? $this->namespaces['tns'];
6531 $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
6532 }
6533
6545 public function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration= [])
6546 {
6547 $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6548
6549 $typens = $this->namespaces['types'] ?? $this->namespaces['tns'];
6550 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6551 }
6552
6560 public function addElement($attrs)
6561 {
6562 $typens = $this->namespaces['types'] ?? $this->namespaces['tns'];
6563 $this->schemas[$typens][0]->addElement($attrs);
6564 }
6565
6581 public function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '')
6582 {
6583 if ('encoded' == $use && '' == $encodingStyle) {
6584 $encodingStyle = 'https://schemas.xmlsoap.org/soap/encoding/';
6585 }
6586
6587 if ('document' == $style) {
6588 $elements = [];
6589 foreach ($in as $n => $t) {
6590 $elements[$n] = ['name' => $n, 'type' => $t, 'form' => 'unqualified'];
6591 }
6592 $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6593 $this->addElement(['name' => $name, 'type' => $name . 'RequestType']);
6594 $in = ['parameters' => 'tns:' . $name . '^'];
6595
6596 $elements = [];
6597 foreach ($out as $n => $t) {
6598 $elements[$n] = ['name' => $n, 'type' => $t, 'form' => 'unqualified'];
6599 }
6600 $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6601 $this->addElement(['name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified']);
6602 $out = ['parameters' => 'tns:' . $name . 'Response' . '^'];
6603 }
6604
6605 // get binding
6606 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6607 [
6608 'name' => $name,
6609 'binding' => $this->serviceName . 'Binding',
6610 'endpoint' => $this->endpoint,
6611 'soapAction' => $soapaction,
6612 'style' => $style,
6613 'input' => [
6614 'use' => $use,
6615 'namespace' => $namespace,
6616 'encodingStyle' => $encodingStyle,
6617 'message' => $name . 'Request',
6618 'parts' => $in
6619 ],
6620 'output' => [
6621 'use' => $use,
6622 'namespace' => $namespace,
6623 'encodingStyle' => $encodingStyle,
6624 'message' => $name . 'Response',
6625 'parts' => $out
6626 ],
6627 'namespace' => $namespace,
6628 'transport' => 'https://schemas.xmlsoap.org/soap/http',
6629 'documentation' => $documentation
6630 ];
6631 // add portTypes
6632 // add messages
6633 if ($in) {
6634 foreach ($in as $pName => $pType) {
6635 if (strpos($pType, ':')) {
6636 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ':' . $this->getLocalPart($pType);
6637 }
6638 $this->messages[$name.'Request'][$pName] = $pType;
6639 }
6640 } else {
6641 $this->messages[$name.'Request']= '0';
6642 }
6643 if ($out) {
6644 foreach ($out as $pName => $pType) {
6645 if (strpos($pType, ':')) {
6646 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ':' . $this->getLocalPart($pType);
6647 }
6648 $this->messages[$name.'Response'][$pName] = $pType;
6649 }
6650 } else {
6651 $this->messages[$name.'Response']= '0';
6652 }
6653 return true;
6654 }
6655}
6656?><?php
6657
6658
6659
6670{
6671
6672 public $xml = '';
6673 public $xml_encoding = '';
6674 public $method = '';
6675 public $root_struct = '';
6676 public $root_struct_name = '';
6677 public $root_struct_namespace = '';
6678 public $root_header = '';
6679 public $document = ''; // incoming SOAP body (text)
6680 // determines where in the message we are (envelope,header,body,method)
6681 public $status = '';
6682 public $position = 0;
6683 public $depth = 0;
6684 public $default_namespace = '';
6685 public $namespaces = [];
6686 public $message = [];
6687 public $parent = '';
6688 public $fault = false;
6689 public $fault_code = '';
6690 public $fault_str = '';
6691 public $fault_detail = '';
6692 public $depth_array = [];
6693 public $debug_flag = true;
6694 public $soapresponse = null; // parsed SOAP Body
6695 public $soapheader = null; // parsed SOAP Header
6696 public $responseHeaders = ''; // incoming SOAP headers (text)
6697 public $body_position = 0;
6698 // for multiref parsing:
6699 // array of id => pos
6700 public $ids = [];
6701 // array of id => hrefs => pos
6702 public $multirefs = [];
6703 // toggle for auto-decoding element content
6704 public $decode_utf8 = true;
6705
6715 public function __construct($xml, $encoding='UTF-8', $method='', $decode_utf8=true)
6716 {
6717 parent::__construct();
6718 $this->xml = $xml;
6719 $this->xml_encoding = $encoding;
6720 $this->method = $method;
6721 $this->decode_utf8 = $decode_utf8;
6722
6723 // Check whether content has been read.
6724 if (!empty($xml)) {
6725 // Check XML encoding
6726 $pos_xml = strpos($xml, '<?xml');
6727 if (false !== $pos_xml) {
6728 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6729 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6730 $xml_encoding = $res[1];
6731 if (strtoupper($xml_encoding) != $encoding) {
6732 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6733 $this->debug($err);
6734 if ('ISO-8859-1' != $encoding || 'UTF-8' != strtoupper($xml_encoding)) {
6735 $this->setError($err);
6736 return;
6737 }
6738 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6739 } else {
6740 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6741 }
6742 } else {
6743 $this->debug('No encoding specified in XML declaration');
6744 }
6745 } else {
6746 $this->debug('No XML declaration');
6747 }
6748 $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
6749 // Create an XML parser - why not xml_parser_create_ns?
6750 $this->parser = xml_parser_create($this->xml_encoding);
6751 // Set the options for parsing the XML data.
6752 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6753 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6754 xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6755 // Set the object for the parser.
6756 xml_set_object($this->parser, $this);
6757 // Set the element handlers for the parser.
6758 xml_set_element_handler($this->parser, 'start_element', 'end_element');
6759 xml_set_character_data_handler($this->parser, 'character_data');
6760
6761 // Parse the XML file.
6762 if (!xml_parse($this->parser, $xml, true)) {
6763 // Display an error message.
6764 $err = sprintf('XML error parsing SOAP payload on line %d: %s',
6765 xml_get_current_line_number($this->parser),
6766 xml_error_string(xml_get_error_code($this->parser)));
6767 $this->debug($err);
6768 $this->debug("XML payload:\n" . $xml);
6769 $this->setError($err);
6770 } else {
6771 $this->debug('in nusoap_parser ctor, message:');
6772 $this->appendDebug($this->varDump($this->message));
6773 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
6774 // get final value
6775 $this->soapresponse = $this->message[$this->root_struct]['result'];
6776 // get header value
6777 if ('' != $this->root_header && isset($this->message[$this->root_header]['result'])) {
6778 $this->soapheader = $this->message[$this->root_header]['result'];
6779 }
6780 // resolve hrefs/ids
6781 if (count($this->multirefs) > 0) {
6782 foreach ($this->multirefs as $id => $hrefs) {
6783 $this->debug('resolving multirefs for id: '.$id);
6784 $idVal = $this->buildVal($this->ids[$id]);
6785 if (is_array($idVal) && isset($idVal['!id'])) {
6786 unset($idVal['!id']);
6787 }
6788 foreach ($hrefs as $refPos => $ref) {
6789 $this->debug('resolving href at pos '.$refPos);
6790 $this->multirefs[$id][$refPos] = $idVal;
6791 }
6792 }
6793 }
6794 }
6795 xml_parser_free($this->parser);
6796 } else {
6797 $this->debug('xml was empty, didn\'t parse!');
6798 $this->setError('xml was empty, didn\'t parse!');
6799 }
6800 }
6801
6810 public function start_element($parser, $name, $attrs)
6811 {
6812 // position in a total number of elements, starting from 0
6813 // update class level pos
6814 $pos = $this->position++;
6815 // and set mine
6816 $this->message[$pos] = ['pos' => $pos, 'children' =>'', 'cdata' =>''];
6817 // depth = how many levels removed from root?
6818 // set mine as current global depth and increment global depth value
6819 $this->message[$pos]['depth'] = $this->depth++;
6820
6821 // else add self as child to whoever the current parent is
6822 if (0 != $pos) {
6823 $this->message[$this->parent]['children'] .= '|'.$pos;
6824 }
6825 // set my parent
6826 $this->message[$pos]['parent'] = $this->parent;
6827 // set self as current parent
6828 $this->parent = $pos;
6829 // set self as current value for this depth
6830 $this->depth_array[$this->depth] = $pos;
6831 // get element prefix
6832 if (strpos($name, ':')) {
6833 // get ns prefix
6834 $prefix = substr($name, 0, strpos($name, ':'));
6835 // get unqualified name
6836 $name = substr(strstr($name, ':'), 1);
6837 }
6838 // set status
6839 if ('Envelope' == $name && '' == $this->status) {
6840 $this->status = 'envelope';
6841 } elseif ('Header' == $name && 'envelope' == $this->status) {
6842 $this->root_header = $pos;
6843 $this->status = 'header';
6844 } elseif ('Body' == $name && 'envelope' == $this->status) {
6845 $this->status = 'body';
6846 $this->body_position = $pos;
6847 // set method
6848 } elseif ('body' == $this->status && $pos == ($this->body_position + 1)) {
6849 $this->status = 'method';
6850 $this->root_struct_name = $name;
6851 $this->root_struct = $pos;
6852 $this->message[$pos]['type'] = 'struct';
6853 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6854 }
6855 // set my status
6856 $this->message[$pos]['status'] = $this->status;
6857 // set name
6858 $this->message[$pos]['name'] = htmlspecialchars($name);
6859 // set attrs
6860 $this->message[$pos]['attrs'] = $attrs;
6861
6862 // loop through atts, logging ns and type declarations
6863 $attstr = '';
6864 foreach ($attrs as $key => $value) {
6865 $key_prefix = $this->getPrefix($key);
6866 $key_localpart = $this->getLocalPart($key);
6867 // if ns declarations, add to class level array of valid namespaces
6868 if ('xmlns' == $key_prefix) {
6869 if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
6870 $this->XMLSchemaVersion = $value;
6871 $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6872 $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
6873 }
6874 $this->namespaces[$key_localpart] = $value;
6875 // set method namespace
6876 if ($name == $this->root_struct_name) {
6877 $this->methodNamespace = $value;
6878 }
6879 // if it's a type declaration, set type
6880 } elseif ('type' == $key_localpart) {
6881 if (isset($this->message[$pos]['type']) && 'array' == $this->message[$pos]['type']) {
6882 // do nothing: already processed arrayType
6883 } else {
6884 $value_prefix = $this->getPrefix($value);
6885 $value_localpart = $this->getLocalPart($value);
6886 $this->message[$pos]['type'] = $value_localpart;
6887 $this->message[$pos]['typePrefix'] = $value_prefix;
6888 if (isset($this->namespaces[$value_prefix])) {
6889 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6890 } elseif (isset($attrs['xmlns:'.$value_prefix])) {
6891 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
6892 }
6893 // should do something here with the namespace of specified type?
6894 }
6895 } elseif ('arrayType' == $key_localpart) {
6896 $this->message[$pos]['type'] = 'array';
6897 /* do arrayType ereg here
6898 [1] arrayTypeValue ::= atype asize
6899 [2] atype ::= QName rank*
6900 [3] rank ::= '[' (',')* ']'
6901 [4] asize ::= '[' length~ ']'
6902 [5] length ::= nextDimension* Digit+
6903 [6] nextDimension ::= Digit+ ','
6904 */
6905 $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6906 if (preg_match($expr, $value, $regs)) {
6907 $this->message[$pos]['typePrefix'] = $regs[1];
6908 $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6909 if (isset($this->namespaces[$regs[1]])) {
6910 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6911 } elseif (isset($attrs['xmlns:'.$regs[1]])) {
6912 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
6913 }
6914 $this->message[$pos]['arrayType'] = $regs[2];
6915 $this->message[$pos]['arraySize'] = $regs[3];
6916 $this->message[$pos]['arrayCols'] = $regs[4];
6917 }
6918 // specifies nil value (or not)
6919 } elseif ('nil' == $key_localpart) {
6920 $this->message[$pos]['nil'] = ('true' == $value || '1' == $value);
6921 // some other attribute
6922 } elseif ('href' != $key && 'xmlns' != $key && 'encodingStyle' != $key_localpart && 'root' != $key_localpart) {
6923 $this->message[$pos]['xattrs']['!' . $key] = $value;
6924 }
6925
6926 if ('xmlns' == $key) {
6927 $this->default_namespace = $value;
6928 }
6929 // log id
6930 if ('id' == $key) {
6931 $this->ids[$value] = $pos;
6932 }
6933 // root
6934 if ('root' == $key_localpart && 1 == $value) {
6935 $this->status = 'method';
6936 $this->root_struct_name = $name;
6937 $this->root_struct = $pos;
6938 $this->debug("found root struct $this->root_struct_name, pos $pos");
6939 }
6940 // for doclit
6941 $attstr .= " $key=\"$value\"";
6942 }
6943 // get namespace - must be done after namespace atts are processed
6944 if (isset($prefix)) {
6945 $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6946 $this->default_namespace = $this->namespaces[$prefix];
6947 } else {
6948 $this->message[$pos]['namespace'] = $this->default_namespace;
6949 }
6950 if ('header' == $this->status) {
6951 if ($this->root_header != $pos) {
6952 $this->responseHeaders .= '<' . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6953 }
6954 } elseif ('' != $this->root_struct_name) {
6955 $this->document .= '<' . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6956 }
6957 }
6958
6966 public function end_element($parser, $name)
6967 {
6968 // position of current element is equal to the last value left in depth_array for my depth
6969 $pos = $this->depth_array[$this->depth--];
6970
6971 // get element prefix
6972 if (strpos($name, ':')) {
6973 // get ns prefix
6974 $prefix = substr($name, 0, strpos($name, ':'));
6975 // get unqualified name
6976 $name = substr(strstr($name, ':'), 1);
6977 }
6978
6979 // build to native type
6980 if (isset($this->body_position) && $pos > $this->body_position) {
6981 // deal w/ multirefs
6982 if (isset($this->message[$pos]['attrs']['href'])) {
6983 // get id
6984 $id = substr($this->message[$pos]['attrs']['href'], 1);
6985 // add placeholder to href array
6986 $this->multirefs[$id][$pos] = 'placeholder';
6987 // add set a reference to it as the result value
6988 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6989 // build complexType values
6990 } elseif ('' != $this->message[$pos]['children']) {
6991 // if result has already been generated (struct/array)
6992 if (!isset($this->message[$pos]['result'])) {
6993 $this->message[$pos]['result'] = $this->buildVal($pos);
6994 }
6995 // build complexType values of attributes and possibly simpleContent
6996 } elseif (isset($this->message[$pos]['xattrs'])) {
6997 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6998 $this->message[$pos]['xattrs']['!'] = null;
6999 } elseif (isset($this->message[$pos]['cdata']) && '' != trim($this->message[$pos]['cdata'])) {
7000 if (isset($this->message[$pos]['type'])) {
7001 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], $this->message[$pos]['type_namespace'] ?? '');
7002 } else {
7003 $parent = $this->message[$pos]['parent'];
7004 if (isset($this->message[$parent]['type']) && ('array' == $this->message[$parent]['type']) && isset($this->message[$parent]['arrayType'])) {
7005 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], $this->message[$parent]['arrayTypeNamespace'] ?? '');
7006 } else {
7007 $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
7008 }
7009 }
7010 }
7011 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
7012 // set value of simpleType (or nil complexType)
7013 } else {
7014 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
7015 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7016 $this->message[$pos]['xattrs']['!'] = null;
7017 } elseif (isset($this->message[$pos]['type'])) {
7018 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], $this->message[$pos]['type_namespace'] ?? '');
7019 } else {
7020 $parent = $this->message[$pos]['parent'];
7021 if (isset($this->message[$parent]['type']) && ('array' == $this->message[$parent]['type']) && isset($this->message[$parent]['arrayType'])) {
7022 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], $this->message[$parent]['arrayTypeNamespace'] ?? '');
7023 } else {
7024 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
7025 }
7026 }
7027
7028 /* add value to parent's result, if parent is struct/array
7029 $parent = $this->message[$pos]['parent'];
7030 if($this->message[$parent]['type'] != 'map'){
7031 if(strtolower($this->message[$parent]['type']) == 'array'){
7032 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
7033 } else {
7034 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
7035 }
7036 }
7037 */
7038 }
7039 }
7040
7041 // for doclit
7042 if ('header' == $this->status) {
7043 if ($this->root_header != $pos) {
7044 $this->responseHeaders .= '</' . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7045 }
7046 } elseif ($pos >= $this->root_struct) {
7047 $this->document .= '</' . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7048 }
7049 // switch status
7050 if ($pos == $this->root_struct) {
7051 $this->status = 'body';
7052 $this->root_struct_namespace = $this->message[$pos]['namespace'];
7053 } elseif ($pos == $this->root_header) {
7054 $this->status = 'envelope';
7055 } elseif ('Body' == $name && 'body' == $this->status) {
7056 $this->status = 'envelope';
7057 } elseif ('Header' == $name && 'header' == $this->status) { // will never happen
7058 $this->status = 'envelope';
7059 } elseif ('Envelope' == $name && 'envelope' == $this->status) {
7060 $this->status = '';
7061 }
7062 // set parent back to my parent
7063 $this->parent = $this->message[$pos]['parent'];
7064 }
7065
7073 public function character_data($parser, $data)
7074 {
7075 $pos = $this->depth_array[$this->depth];
7076 if ('UTF-8' == $this->xml_encoding) {
7077 // TODO: add an option to disable this for folks who want
7078 // raw UTF-8 that, e.g., might not map to iso-8859-1
7079 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
7080 if ($this->decode_utf8) {
7081 $data = utf8_decode($data);
7082 }
7083 }
7084 $this->message[$pos]['cdata'] .= $data;
7085 // for doclit
7086 if ('header' == $this->status) {
7087 $this->responseHeaders .= $data;
7088 } else {
7089 $this->document .= $data;
7090 }
7091 }
7092
7100 public function get_response()
7101 {
7102 return $this->soapresponse;
7103 }
7104
7111 public function get_soapbody()
7112 {
7113 return $this->soapresponse;
7114 }
7115
7122 public function get_soapheader()
7123 {
7124 return $this->soapheader;
7125 }
7126
7133 public function getHeaders()
7134 {
7135 return $this->responseHeaders;
7136 }
7137
7147 public function decodeSimple($value, $type, $typens)
7148 {
7149 // TODO: use the namespace!
7150 if ((!isset($type)) || 'string' == $type || 'long' == $type || 'unsignedLong' == $type) {
7151 return (string) $value;
7152 }
7153 if ('int' == $type || 'integer' == $type || 'short' == $type || 'byte' == $type) {
7154 return (int) $value;
7155 }
7156 if ('float' == $type || 'double' == $type || 'decimal' == $type) {
7157 return (double) $value;
7158 }
7159 if ('boolean' == $type) {
7160 if ('false' == strtolower($value) || 'f' == strtolower($value)) {
7161 return false;
7162 }
7163 return (boolean) $value;
7164 }
7165 if ('base64' == $type || 'base64Binary' == $type) {
7166 $this->debug('Decode base64 value');
7167 return base64_decode($value);
7168 }
7169 // obscure numeric types
7170 if ('nonPositiveInteger' == $type || 'negativeInteger' == $type
7171 || 'nonNegativeInteger' == $type
7172 || 'positiveInteger' == $type
7173 || 'unsignedInt' == $type
7174 || 'unsignedShort' == $type
7175 || 'unsignedByte' == $type) {
7176 return (int) $value;
7177 }
7178 // bogus: parser treats array with no elements as a simple type
7179 if ('array' == $type) {
7180 return [];
7181 }
7182 // everything else
7183 return (string) $value;
7184 }
7185
7194 public function buildVal($pos)
7195 {
7196 $params = [];
7197 if (!isset($this->message[$pos]['type'])) {
7198 $this->message[$pos]['type'] = '';
7199 }
7200 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
7201 // if there are children...
7202 if ('' != $this->message[$pos]['children']) {
7203 $this->debug('in buildVal, there are children');
7204 $children = explode('|', $this->message[$pos]['children']);
7205 array_shift($children); // knock off empty
7206 // md array
7207 if (isset($this->message[$pos]['arrayCols']) && '' != $this->message[$pos]['arrayCols']) {
7208 $r=0; // rowcount
7209 $c=0; // colcount
7210 foreach ($children as $child_pos) {
7211 $this->debug("in buildVal, got an MD array element: $r, $c");
7212 $params[$r][] = $this->message[$child_pos]['result'];
7213 $c++;
7214 if ($c == $this->message[$pos]['arrayCols']) {
7215 $c = 0;
7216 $r++;
7217 }
7218 }
7219 // array
7220 } elseif ('array' == $this->message[$pos]['type'] || 'Array' == $this->message[$pos]['type']) {
7221 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
7222 foreach ($children as $child_pos) {
7223 $params[] = &$this->message[$child_pos]['result'];
7224 }
7225 // apache Map type: java hashtable
7226 } elseif ('Map' == $this->message[$pos]['type'] && 'https://xml.apache.org/xml-soap' == $this->message[$pos]['type_namespace']) {
7227 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
7228 foreach ($children as $child_pos) {
7229 $kv = explode('|', $this->message[$child_pos]['children']);
7230 $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
7231 }
7232 // generic compound type
7233 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
7234 } else {
7235 // Apache Vector type: treat as an array
7236 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
7237 if ('Vector' == $this->message[$pos]['type'] && 'https://xml.apache.org/xml-soap' == $this->message[$pos]['type_namespace']) {
7238 $notstruct = 1;
7239 } else {
7240 $notstruct = 0;
7241 }
7242 //
7243 foreach ($children as $child_pos) {
7244 if ($notstruct) {
7245 $params[] = &$this->message[$child_pos]['result'];
7246 } else {
7247 if (isset($params[$this->message[$child_pos]['name']])) {
7248 // de-serialize repeated element name into an array
7249 if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
7250 $params[$this->message[$child_pos]['name']] = [$params[$this->message[$child_pos]['name']]];
7251 }
7252 $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
7253 } else {
7254 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
7255 }
7256 }
7257 }
7258 }
7259 if (isset($this->message[$pos]['xattrs'])) {
7260 $this->debug('in buildVal, handling attributes');
7261 foreach ($this->message[$pos]['xattrs'] as $n => $v) {
7262 $params[$n] = $v;
7263 }
7264 }
7265 // handle simpleContent
7266 if (isset($this->message[$pos]['cdata']) && '' != trim($this->message[$pos]['cdata'])) {
7267 $this->debug('in buildVal, handling simpleContent');
7268 if (isset($this->message[$pos]['type'])) {
7269 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], $this->message[$pos]['type_namespace'] ?? '');
7270 } else {
7271 $parent = $this->message[$pos]['parent'];
7272 if (isset($this->message[$parent]['type']) && ('array' == $this->message[$parent]['type']) && isset($this->message[$parent]['arrayType'])) {
7273 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], $this->message[$parent]['arrayTypeNamespace'] ?? '');
7274 } else {
7275 $params['!'] = $this->message[$pos]['cdata'];
7276 }
7277 }
7278 }
7279 $ret = is_array($params) ? $params : [];
7280 $this->debug('in buildVal, return:');
7281 $this->appendDebug($this->varDump($ret));
7282 return $ret;
7283 } else {
7284 $this->debug('in buildVal, no children, building scalar');
7285 $cdata = $this->message[$pos]['cdata'] ?? '';
7286 if (isset($this->message[$pos]['type'])) {
7287 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], $this->message[$pos]['type_namespace'] ?? '');
7288 $this->debug("in buildVal, return: $ret");
7289 return $ret;
7290 }
7291 $parent = $this->message[$pos]['parent'];
7292 if (isset($this->message[$parent]['type']) && ('array' == $this->message[$parent]['type']) && isset($this->message[$parent]['arrayType'])) {
7293 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], $this->message[$parent]['arrayTypeNamespace'] ?? '');
7294 $this->debug("in buildVal, return: $ret");
7295 return $ret;
7296 }
7297 $ret = $this->message[$pos]['cdata'];
7298 $this->debug("in buildVal, return: $ret");
7299 return $ret;
7300 }
7301 }
7302}
7303
7308{
7309}
7310
7311?><?php
7312
7313
7314
7336{
7337
7338 public $username = ''; // Username for HTTP authentication
7339 public $password = ''; // Password for HTTP authentication
7340 public $authtype = ''; // Type of HTTP authentication
7341 public $certRequest = []; // Certificate for HTTP SSL authentication
7342 public $requestHeaders = false; // SOAP headers in request (text)
7343 public $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7344 public $responseHeader = null; // SOAP Header from response (parsed)
7345 public $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7346 public $endpoint;
7347 public $forceEndpoint = ''; // overrides WSDL endpoint
7348 public $proxyhost = '';
7349 public $proxyport = '';
7350 public $proxyusername = '';
7351 public $proxypassword = '';
7352 public $portName = ''; // port name to use in WSDL
7353 public $xml_encoding = ''; // character set encoding of incoming (response) messages
7354 public $http_encoding = false;
7355 public $timeout = 0; // HTTP connection timeout
7356 public $response_timeout = 30; // HTTP response timeout
7357 public $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7358 public $persistentConnection = false;
7359 public $defaultRpcParams = false; // This is no longer used
7360 public $request = ''; // HTTP request
7361 public $response = ''; // HTTP response
7362 public $responseData = ''; // SOAP payload of response
7363 public $cookies = []; // Cookies from response or for request
7364 public $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7365 public $operations = []; // WSDL operations, empty for WSDL initialization error
7366 public $curl_options = []; // User-specified cURL options
7367 public $bindingType = ''; // WSDL operation binding type
7368 public $use_curl = false; // whether to always try to use cURL
7369
7370 /*
7371 * fault related variables
7372 */
7377 public $fault;
7382 public $faultcode;
7387 public $faultstring;
7392 public $faultdetail;
7393
7408 public function __construct($endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = '')
7409 {
7410 parent::__construct();
7411 $this->endpoint = $endpoint;
7412 $this->proxyhost = $proxyhost;
7413 $this->proxyport = $proxyport;
7414 $this->proxyusername = $proxyusername;
7415 $this->proxypassword = $proxypassword;
7416 $this->timeout = $timeout;
7417 $this->response_timeout = $response_timeout;
7418 $this->portName = $portName;
7419
7420 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7421 $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7422
7423 // make values
7424 if ($wsdl) {
7425 if (is_object($endpoint) && ('wsdl' == get_class($endpoint))) {
7426 $this->wsdl = $endpoint;
7427 $this->endpoint = $this->wsdl->wsdl;
7428 $this->wsdlFile = $this->endpoint;
7429 $this->debug('existing wsdl instance created from ' . $this->endpoint);
7430 $this->checkWSDL();
7431 } else {
7432 $this->wsdlFile = $this->endpoint;
7433 $this->wsdl = null;
7434 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7435 }
7436 $this->endpointType = 'wsdl';
7437 } else {
7438 $this->debug("instantiate SOAP with endpoint at $endpoint");
7439 $this->endpointType = 'soap';
7440 }
7441 }
7442
7468 public function call($operation, $params= [], $namespace='https://tempuri.org', $soapAction='', $headers=false, $rpcParams=null, $style='rpc', $use='encoded')
7469 {
7470 $this->operation = $operation;
7471 $this->fault = false;
7472 $this->setError('');
7473 $this->request = '';
7474 $this->response = '';
7475 $this->responseData = '';
7476 $this->faultstring = '';
7477 $this->faultcode = '';
7478 $this->opData = [];
7479
7480 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7481 $this->appendDebug('params=' . $this->varDump($params));
7482 $this->appendDebug('headers=' . $this->varDump($headers));
7483 if ($headers) {
7484 $this->requestHeaders = $headers;
7485 }
7486 if ('wsdl' == $this->endpointType && null === $this->wsdl) {
7487 $this->loadWSDL();
7488 if ($this->getError()) {
7489 return false;
7490 }
7491 }
7492 // serialize parameters
7493 if ('wsdl' == $this->endpointType && $opData = $this->getOperationData($operation)) {
7494 // use WSDL for operation
7495 $this->opData = $opData;
7496 $this->debug('found operation');
7497 $this->appendDebug('opData=' . $this->varDump($opData));
7498 if (isset($opData['soapAction'])) {
7499 $soapAction = $opData['soapAction'];
7500 }
7501 if (! $this->forceEndpoint) {
7502 $this->endpoint = $opData['endpoint'];
7503 } else {
7504 $this->endpoint = $this->forceEndpoint;
7505 }
7506 $namespace = $opData['input']['namespace'] ?? $namespace;
7507 $style = $opData['style'];
7508 $use = $opData['input']['use'];
7509 // add ns to ns array
7510 if ('' != $namespace && !isset($this->wsdl->namespaces[$namespace])) {
7511 $nsPrefix = 'ns' . random_int(1000, 9999);
7512 $this->wsdl->namespaces[$nsPrefix] = $namespace;
7513 }
7514 $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7515 // serialize payload
7516 if (is_string($params)) {
7517 $this->debug("serializing param string for WSDL operation $operation");
7518 $payload = $params;
7519 } elseif (is_array($params)) {
7520 $this->debug("serializing param array for WSDL operation $operation");
7521 $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType);
7522 } else {
7523 $this->debug('params must be array or string');
7524 $this->setError('params must be array or string');
7525 return false;
7526 }
7527 $usedNamespaces = $this->wsdl->usedNamespaces;
7528 if (isset($opData['input']['encodingStyle'])) {
7529 $encodingStyle = $opData['input']['encodingStyle'];
7530 } else {
7531 $encodingStyle = '';
7532 }
7533 $this->appendDebug($this->wsdl->getDebug());
7534 $this->wsdl->clearDebug();
7535 if ($errstr = $this->wsdl->getError()) {
7536 $this->debug('got wsdl error: '.$errstr);
7537 $this->setError('wsdl error: '.$errstr);
7538 return false;
7539 }
7540 } elseif ('wsdl' == $this->endpointType) {
7541 // operation not in WSDL
7542 $this->appendDebug($this->wsdl->getDebug());
7543 $this->wsdl->clearDebug();
7544 $this->setError('operation '.$operation.' not present in WSDL.');
7545 $this->debug("operation '$operation' not present in WSDL.");
7546 return false;
7547 } else {
7548 // no WSDL
7549 //$this->namespaces['ns1'] = $namespace;
7550 $nsPrefix = 'ns' . random_int(1000, 9999);
7551 // serialize
7552 $payload = '';
7553 if (is_string($params)) {
7554 $this->debug("serializing param string for operation $operation");
7555 $payload = $params;
7556 } elseif (is_array($params)) {
7557 $this->debug("serializing param array for operation $operation");
7558 foreach ($params as $k => $v) {
7559 $payload .= $this->serialize_val($v, $k, false, false, false, false, $use);
7560 }
7561 } else {
7562 $this->debug('params must be array or string');
7563 $this->setError('params must be array or string');
7564 return false;
7565 }
7566 $usedNamespaces = [];
7567 if ('encoded' == $use) {
7568 $encodingStyle = 'https://schemas.xmlsoap.org/soap/encoding/';
7569 } else {
7570 $encodingStyle = '';
7571 }
7572 }
7573 // wrap RPC calls with method element
7574 if ('rpc' == $style) {
7575 if ('literal' == $use) {
7576 $this->debug('wrapping RPC request with literal method element');
7577 if ($namespace) {
7578 // https://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
7579 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7580 $payload .
7581 "</$nsPrefix:$operation>";
7582 } else {
7583 $payload = "<$operation>" . $payload . "</$operation>";
7584 }
7585 } else {
7586 $this->debug('wrapping RPC request with encoded method element');
7587 if ($namespace) {
7588 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7589 $payload .
7590 "</$nsPrefix:$operation>";
7591 } else {
7592 $payload = "<$operation>" .
7593 $payload .
7594 "</$operation>";
7595 }
7596 }
7597 }
7598 // serialize envelope
7599 $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle);
7600 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7601 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7602 // send
7603 $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout);
7604 if ($errstr = $this->getError()) {
7605 $this->debug('Error: '.$errstr);
7606 return false;
7607 } else {
7608 $this->return = $return;
7609 $this->debug('sent message successfully and got a(n) '.gettype($return));
7610 $this->appendDebug('return=' . $this->varDump($return));
7611
7612 // fault?
7613 if (is_array($return) && isset($return['faultcode'])) {
7614 $this->debug('got fault');
7615 $this->setError($return['faultcode'].': '.$return['faultstring']);
7616 $this->fault = true;
7617 foreach ($return as $k => $v) {
7618 $this->$k = $v;
7619 $this->debug("$k = $v<br>");
7620 }
7621 return $return;
7622 } elseif ('document' == $style) {
7623 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7624 // we are only going to return the first part here...sorry about that
7625 return $return;
7626 } else {
7627 // array of return values
7628 if (is_array($return)) {
7629 // multiple 'out' parameters, which we return wrapped up
7630 // in the array
7631 if (count($return) > 1) {
7632 return $return;
7633 }
7634 // single 'out' parameter (normally the return value)
7635 $return = array_shift($return);
7636 $this->debug('return shifted value: ');
7637 $this->appendDebug($this->varDump($return));
7638 return $return;
7639 // nothing returned (ie, echoVoid)
7640 } else {
7641 return '';
7642 }
7643 }
7644 }
7645 }
7646
7652 public function checkWSDL()
7653 {
7654 $this->appendDebug($this->wsdl->getDebug());
7655 $this->wsdl->clearDebug();
7656 $this->debug('checkWSDL');
7657 // catch errors
7658 if ($errstr = $this->wsdl->getError()) {
7659 $this->appendDebug($this->wsdl->getDebug());
7660 $this->wsdl->clearDebug();
7661 $this->debug('got wsdl error: '.$errstr);
7662 $this->setError('wsdl error: '.$errstr);
7663 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
7664 $this->appendDebug($this->wsdl->getDebug());
7665 $this->wsdl->clearDebug();
7666 $this->bindingType = 'soap';
7667 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7668 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
7669 $this->appendDebug($this->wsdl->getDebug());
7670 $this->wsdl->clearDebug();
7671 $this->bindingType = 'soap12';
7672 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7673 $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7674 } else {
7675 $this->appendDebug($this->wsdl->getDebug());
7676 $this->wsdl->clearDebug();
7677 $this->debug('getOperations returned false');
7678 $this->setError('no operations defined in the WSDL document!');
7679 }
7680 }
7681
7687 public function loadWSDL()
7688 {
7689 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
7690 $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl);
7691 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7692 $this->wsdl->fetchWSDL($this->wsdlFile);
7693 $this->checkWSDL();
7694 }
7695
7703 public function getOperationData($operation)
7704 {
7705 if ('wsdl' == $this->endpointType && null === $this->wsdl) {
7706 $this->loadWSDL();
7707 if ($this->getError()) {
7708 return false;
7709 }
7710 }
7711 if (isset($this->operations[$operation])) {
7712 return $this->operations[$operation];
7713 }
7714 $this->debug("No data for operation: $operation");
7715 }
7716
7731 public function send($msg, $soapaction = '', $timeout=0, $response_timeout=30)
7732 {
7733 $this->checkCookies();
7734 // detect transport
7735 switch (true) {
7736 // http(s)
7737 case preg_match('/^http/', $this->endpoint):
7738 $this->debug('transporting via HTTP');
7739 if (true == $this->persistentConnection && is_object($this->persistentConnection)) {
7740 $http =& $this->persistentConnection;
7741 } else {
7742 $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7743 if ($this->persistentConnection) {
7744 $http->usePersistentConnection();
7745 }
7746 }
7747 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7748 $http->setSOAPAction($soapaction);
7749 if ($this->proxyhost && $this->proxyport) {
7750 $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
7751 }
7752 if ('' != $this->authtype) {
7753 $http->setCredentials($this->username, $this->password, $this->authtype, [], $this->certRequest);
7754 }
7755 if ('' != $this->http_encoding) {
7756 $http->setEncoding($this->http_encoding);
7757 }
7758 $this->debug('sending message, length='.strlen($msg));
7759 if (preg_match('/^http:/', $this->endpoint)) {
7760 //if(strpos($this->endpoint,'http:')){
7761 $this->responseData = $http->send($msg, $timeout, $response_timeout, $this->cookies);
7762 } elseif (preg_match('/^https/', $this->endpoint)) {
7763 //} elseif(strpos($this->endpoint,'https:')){
7764 //if(phpversion() == '4.3.0-dev'){
7765 //$response = $http->send($msg,$timeout,$response_timeout);
7766 //$this->request = $http->outgoing_payload;
7767 //$this->response = $http->incoming_payload;
7768 //} else
7769 $this->responseData = $http->sendHTTPS($msg, $timeout, $response_timeout, $this->cookies);
7770 } else {
7771 $this->setError('no http/s in endpoint url');
7772 }
7773 $this->request = $http->outgoing_payload;
7774 $this->response = $http->incoming_payload;
7775 $this->appendDebug($http->getDebug());
7776 $this->UpdateCookies($http->incoming_cookies);
7777
7778 // save transport object if using persistent connections
7779 if ($this->persistentConnection) {
7780 $http->clearDebug();
7781 if (!is_object($this->persistentConnection)) {
7782 $this->persistentConnection = $http;
7783 }
7784 }
7785
7786 if ($err = $http->getError()) {
7787 $this->setError('HTTP Error: '.$err);
7788 return false;
7789 } elseif ($this->getError()) {
7790 return false;
7791 } else {
7792 $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
7793 return $this->parseResponse($http->incoming_headers, $this->responseData);
7794 }
7795 break;
7796 default:
7797 $this->setError('no transport found, or selected transport is not yet supported!');
7798 return false;
7799 break;
7800 }
7801 }
7802
7811 public function parseResponse($headers, $data)
7812 {
7813 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7814 $this->appendDebug($this->varDump($headers));
7815 if (!isset($headers['content-type'])) {
7816 $this->setError('Response not of type text/xml (no content-type header)');
7817 return false;
7818 }
7819 if (!strstr($headers['content-type'], 'text/xml')) {
7820 $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7821 return false;
7822 }
7823 if (strpos($headers['content-type'], '=')) {
7824 $enc = str_replace('"', '', substr(strstr($headers['content-type'], '='), 1));
7825 $this->debug('Got response encoding: ' . $enc);
7826 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
7827 $this->xml_encoding = strtoupper($enc);
7828 } else {
7829 $this->xml_encoding = 'US-ASCII';
7830 }
7831 } else {
7832 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7833 $this->xml_encoding = 'ISO-8859-1';
7834 }
7835 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7836 $parser = new nusoap_parser($data, $this->xml_encoding, $this->operation, $this->decode_utf8);
7837 // add parser debug data to our debug
7838 $this->appendDebug($parser->getDebug());
7839 // if parse errors
7840 if ($errstr = $parser->getError()) {
7841 $this->setError($errstr);
7842 // destroy the parser object
7843 unset($parser);
7844 return false;
7845 } else {
7846 // get SOAP headers
7847 $this->responseHeaders = $parser->getHeaders();
7848 // get SOAP headers
7849 $this->responseHeader = $parser->get_soapheader();
7850 // get decoded message
7851 $return = $parser->get_soapbody();
7852 // add document for doclit support
7853 $this->document = $parser->document;
7854 // destroy the parser object
7855 unset($parser);
7856 // return decode message
7857 return $return;
7858 }
7859 }
7860
7868 public function setCurlOption($option, $value)
7869 {
7870 $this->debug("setCurlOption option=$option, value=");
7871 $this->appendDebug($this->varDump($value));
7872 $this->curl_options[$option] = $value;
7873 }
7874
7881 public function setEndpoint($endpoint)
7882 {
7883 $this->debug("setEndpoint(\"$endpoint\")");
7884 $this->forceEndpoint = $endpoint;
7885 }
7886
7893 public function setHeaders($headers)
7894 {
7895 $this->debug('setHeaders headers=');
7896 $this->appendDebug($this->varDump($headers));
7897 $this->requestHeaders = $headers;
7898 }
7899
7906 public function getHeaders()
7907 {
7908 return $this->responseHeaders;
7909 }
7910
7917 public function getHeader()
7918 {
7919 return $this->responseHeader;
7920 }
7921
7931 public function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
7932 {
7933 $this->proxyhost = $proxyhost;
7934 $this->proxyport = $proxyport;
7935 $this->proxyusername = $proxyusername;
7936 $this->proxypassword = $proxypassword;
7937 }
7938
7948 public function setCredentials($username, $password, $authtype = 'basic', $certRequest = [])
7949 {
7950 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7951 $this->appendDebug($this->varDump($certRequest));
7952 $this->username = $username;
7953 $this->password = $password;
7954 $this->authtype = $authtype;
7955 $this->certRequest = $certRequest;
7956 }
7957
7964 public function setHTTPEncoding($enc='gzip, deflate')
7965 {
7966 $this->debug("setHTTPEncoding(\"$enc\")");
7967 $this->http_encoding = $enc;
7968 }
7969
7976 public function setUseCURL($use)
7977 {
7978 $this->debug("setUseCURL($use)");
7979 $this->use_curl = $use;
7980 }
7981
7988 {
7989 $this->debug('useHTTPPersistentConnection');
7990 $this->persistentConnection = true;
7991 }
7992
8004 public function getDefaultRpcParams()
8005 {
8006 return $this->defaultRpcParams;
8007 }
8008
8020 public function setDefaultRpcParams($rpcParams)
8021 {
8022 $this->defaultRpcParams = $rpcParams;
8023 }
8024
8032 public function getProxy()
8033 {
8034 $proxy = null;
8035 $r = random_int(0, mt_getrandmax());
8036 $evalStr = $this->_getProxyClassCode($r);
8037 //$this->debug("proxy class: $evalStr");
8038 if ($this->getError()) {
8039 $this->debug('Error from _getProxyClassCode, so return NULL');
8040 return null;
8041 }
8042 // eval the class
8043 eval($evalStr);
8044 // instantiate proxy object
8045 eval("\$proxy = new nusoap_proxy_()$r('');");
8046 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
8047 $proxy->endpointType = 'wsdl';
8048 $proxy->wsdlFile = $this->wsdlFile;
8049 $proxy->wsdl = $this->wsdl;
8050 $proxy->operations = $this->operations;
8051 $proxy->defaultRpcParams = $this->defaultRpcParams;
8052 // transfer other state
8053 $proxy->soap_defencoding = $this->soap_defencoding;
8054 $proxy->username = $this->username;
8055 $proxy->password = $this->password;
8056 $proxy->authtype = $this->authtype;
8057 $proxy->certRequest = $this->certRequest;
8058 $proxy->requestHeaders = $this->requestHeaders;
8059 $proxy->endpoint = $this->endpoint;
8060 $proxy->forceEndpoint = $this->forceEndpoint;
8061 $proxy->proxyhost = $this->proxyhost;
8062 $proxy->proxyport = $this->proxyport;
8063 $proxy->proxyusername = $this->proxyusername;
8064 $proxy->proxypassword = $this->proxypassword;
8065 $proxy->http_encoding = $this->http_encoding;
8066 $proxy->timeout = $this->timeout;
8067 $proxy->response_timeout = $this->response_timeout;
8068 $proxy->persistentConnection = &$this->persistentConnection;
8069 $proxy->decode_utf8 = $this->decode_utf8;
8070 $proxy->curl_options = $this->curl_options;
8071 $proxy->bindingType = $this->bindingType;
8072 $proxy->use_curl = $this->use_curl;
8073 return $proxy;
8074 }
8075
8083 public function _getProxyClassCode($r)
8084 {
8085 $this->debug("in getProxy endpointType=$this->endpointType");
8086 $this->appendDebug('wsdl=' . $this->varDump($this->wsdl));
8087 if ('wsdl' != $this->endpointType) {
8088 $evalStr = 'A proxy can only be created for a WSDL client';
8089 $this->setError($evalStr);
8090 $evalStr = "echo \"$evalStr\";";
8091 return $evalStr;
8092 }
8093 if ('wsdl' == $this->endpointType && null === $this->wsdl) {
8094 $this->loadWSDL();
8095 if ($this->getError()) {
8096 return 'echo "' . $this->getError() . '";';
8097 }
8098 }
8099 $evalStr = '';
8100 foreach ($this->operations as $operation => $opData) {
8101 if ('' != $operation) {
8102 // create param string and param comment string
8103 if ((is_countable($opData['input']['parts']) ? count($opData['input']['parts']) : 0) > 0) {
8104 $paramStr = '';
8105 $paramArrayStr = '';
8106 $paramCommentStr = '';
8107 foreach ($opData['input']['parts'] as $name => $type) {
8108 $paramStr .= "\$$name, ";
8109 $paramArrayStr .= "'$name' => \$$name, ";
8110 $paramCommentStr .= "$type \$$name, ";
8111 }
8112 $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
8113 $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
8114 $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
8115 } else {
8116 $paramStr = '';
8117 $paramArrayStr = '';
8118 $paramCommentStr = 'void';
8119 }
8120 $opData['namespace'] = !isset($opData['namespace']) ? 'https://testuri.com' : $opData['namespace'];
8121 $evalStr .= "// $paramCommentStr
8122 function " . str_replace('.', '__', $operation) . "($paramStr) {
8123 \$params = array($paramArrayStr);
8124 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".($opData['soapAction'] ?? '')."');
8125 }
8126 ";
8127 unset($paramStr);
8128 unset($paramCommentStr);
8129 }
8130 }
8131 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
8132 '.$evalStr.'
8133}';
8134 return $evalStr;
8135 }
8136
8143 public function getProxyClassCode()
8144 {
8145 $r = random_int(0, mt_getrandmax());
8146 return $this->_getProxyClassCode($r);
8147 }
8148
8156 public function getHTTPBody($soapmsg)
8157 {
8158 return $soapmsg;
8159 }
8160
8169 public function getHTTPContentType()
8170 {
8171 return 'text/xml';
8172 }
8173
8184 {
8185 return $this->soap_defencoding;
8186 }
8187
8188 /*
8189 * whether or not parser should decode utf8 element content
8190 *
8191 * @return always returns true
8192 * @access public
8193 */
8194 public function decodeUTF8($bool)
8195 {
8196 $this->decode_utf8 = $bool;
8197 return true;
8198 }
8199
8208 public function setCookie($name, $value)
8209 {
8210 if (0 == strlen($name)) {
8211 return false;
8212 }
8213 $this->cookies[] = ['name' => $name, 'value' => $value];
8214 return true;
8215 }
8216
8223 public function getCookies()
8224 {
8225 return $this->cookies;
8226 }
8227
8234 public function checkCookies()
8235 {
8236 if (0 == count($this->cookies)) {
8237 return true;
8238 }
8239 $this->debug('checkCookie: check ' . count($this->cookies) . ' cookies');
8240 $curr_cookies = $this->cookies;
8241 $this->cookies = [];
8242 foreach ($curr_cookies as $cookie) {
8243 if (! is_array($cookie)) {
8244 $this->debug('Remove cookie that is not an array');
8245 continue;
8246 }
8247 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
8248 if (strtotime($cookie['expires']) > time()) {
8249 $this->cookies[] = $cookie;
8250 } else {
8251 $this->debug('Remove expired cookie ' . $cookie['name']);
8252 }
8253 } else {
8254 $this->cookies[] = $cookie;
8255 }
8256 }
8257 $this->debug('checkCookie: ' . count($this->cookies) . ' cookies left in array');
8258 return true;
8259 }
8260
8268 public function UpdateCookies($cookies)
8269 {
8270 if (0 == count($this->cookies)) {
8271 // no existing cookies: take whatever is new
8272 if (count($cookies) > 0) {
8273 $this->debug('Setting new cookie(s)');
8274 $this->cookies = $cookies;
8275 }
8276 return true;
8277 }
8278 if (0 == count($cookies)) {
8279 // no new cookies: keep what we've got
8280 return true;
8281 }
8282 // merge
8283 foreach ($cookies as $newCookie) {
8284 if (!is_array($newCookie)) {
8285 continue;
8286 }
8287 if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
8288 continue;
8289 }
8290 $newName = $newCookie['name'];
8291
8292 $found = false;
8293 for ($i = 0; $i < count($this->cookies); $i++) {
8294 $cookie = $this->cookies[$i];
8295 if (!is_array($cookie)) {
8296 continue;
8297 }
8298 if (!isset($cookie['name'])) {
8299 continue;
8300 }
8301 if ($newName != $cookie['name']) {
8302 continue;
8303 }
8304 $newDomain = $newCookie['domain'] ?? 'NODOMAIN';
8305 $domain = $cookie['domain'] ?? 'NODOMAIN';
8306 if ($newDomain != $domain) {
8307 continue;
8308 }
8309 $newPath = $newCookie['path'] ?? 'NOPATH';
8310 $path = $cookie['path'] ?? 'NOPATH';
8311 if ($newPath != $path) {
8312 continue;
8313 }
8314 $this->cookies[$i] = $newCookie;
8315 $found = true;
8316 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
8317 break;
8318 }
8319 if (! $found) {
8320 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
8321 $this->cookies[] = $newCookie;
8322 }
8323 }
8324 return true;
8325 }
8326}
8327
8328if (!extension_loaded('soap')) {
8332 class soapclient extends nusoap_client
8333 {
8334 }
8335}
8336
varDump($data)
Definition nusoap.php:903
setGlobalDebugLevel($level)
Definition nusoap.php:253
getDebugLevel()
Definition nusoap.php:264
formatDump($str)
Definition nusoap.php:750
isArraySimpleOrStruct($val)
Definition nusoap.php:403
getPrefix($str)
Definition nusoap.php:833
expandQname($qname)
Definition nusoap.php:789
& getDebug()
Definition nusoap.php:326
setDebugLevel($level)
Definition nusoap.php:275
appendDebug($string)
Definition nusoap.php:299
& getDebugAsXMLComment()
Definition nusoap.php:340
contractQname($qname)
Definition nusoap.php:763
setError($str)
Definition nusoap.php:391
serialize_val($val, $name=false, $type=false, $name_ns=false, $type_ns=false, $attributes=false, $use='encoded', $soapval=false)
Definition nusoap.php:429
getNamespaceFromPrefix($prefix)
Definition nusoap.php:849
getPrefixFromNamespace($ns)
Definition nusoap.php:866
debug($string)
Definition nusoap.php:286
getGlobalDebugLevel()
Definition nusoap.php:242
getLocalPart($str)
Definition nusoap.php:815
expandEntities($val)
Definition nusoap.php:358
serializeEnvelope($body, $headers=false, $namespaces=[], $style='rpc', $use='encoded', $encodingStyle='https://schemas.xmlsoap.org/soap/encoding/')
Definition nusoap.php:697
send($msg, $soapaction='', $timeout=0, $response_timeout=30)
Definition nusoap.php:7731
__construct($endpoint, $wsdl=false, $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30, $portName='')
Definition nusoap.php:7408
_getProxyClassCode($r)
Definition nusoap.php:8083
setCurlOption($option, $value)
Definition nusoap.php:7868
setCookie($name, $value)
Definition nusoap.php:8208
setCredentials($username, $password, $authtype='basic', $certRequest=[])
Definition nusoap.php:7948
useHTTPPersistentConnection()
Definition nusoap.php:7987
call($operation, $params=[], $namespace='https://tempuri.org', $soapAction='', $headers=false, $rpcParams=null, $style='rpc', $use='encoded')
Definition nusoap.php:7468
setHTTPProxy($proxyhost, $proxyport, $proxyusername='', $proxypassword='')
Definition nusoap.php:7931
getHTTPContentTypeCharset()
Definition nusoap.php:8183
setHTTPEncoding($enc='gzip, deflate')
Definition nusoap.php:7964
getDefaultRpcParams()
Definition nusoap.php:8004
setDefaultRpcParams($rpcParams)
Definition nusoap.php:8020
getHTTPBody($soapmsg)
Definition nusoap.php:8156
setEndpoint($endpoint)
Definition nusoap.php:7881
setHeaders($headers)
Definition nusoap.php:7893
parseResponse($headers, $data)
Definition nusoap.php:7811
getOperationData($operation)
Definition nusoap.php:7703
UpdateCookies($cookies)
Definition nusoap.php:8268
setUseCURL($use)
Definition nusoap.php:7976
__construct($faultcode, $faultactor='', $faultstring='', $faultdetail='')
Definition nusoap.php:1074
character_data($parser, $data)
Definition nusoap.php:7073
buildVal($pos)
Definition nusoap.php:7194
decodeSimple($value, $type, $typens)
Definition nusoap.php:7147
start_element($parser, $name, $attrs)
Definition nusoap.php:6810
__construct($xml, $encoding='UTF-8', $method='', $decode_utf8=true)
Definition nusoap.php:6715
end_element($parser, $name)
Definition nusoap.php:6966
__construct($wsdl=false)
Definition nusoap.php:3725
verify_method($operation, $request)
Definition nusoap.php:4391
parseRequest($headers, $data)
Definition nusoap.php:4411
getHTTPContentTypeCharset()
Definition nusoap.php:4495
getHTTPBody($soapmsg)
Definition nusoap.php:4468
parse_request($data='')
Definition nusoap.php:4003
fault($faultcode, $faultstring, $faultactor='', $faultdetail='')
Definition nusoap.php:4600
add_to_map($methodname, $in, $out)
Definition nusoap.php:4509
configureWSDL($serviceName, $namespace=false, $endpoint=false, $style='rpc', $transport='https://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace=false)
Definition nusoap.php:4620
service($data)
Definition nusoap.php:3789
addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=[])
Definition nusoap.php:2062
addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements=[], $attrs=[], $arrayType='')
Definition nusoap.php:2033
parseFile($xml, $type)
Definition nusoap.php:1204
getTypeDef($type)
Definition nusoap.php:1845
serializeTypeDef($type)
Definition nusoap.php:1926
addElement($attrs)
Definition nusoap.php:2083
schemaEndElement($parser, $name)
Definition nusoap.php:1625
CreateTypeName($ename)
Definition nusoap.php:1279
__construct($schema='', $xml='', $namespaces=[])
Definition nusoap.php:1171
schemaStartElement($parser, $name, $attrs)
Definition nusoap.php:1296
parseString($xml, $type)
Definition nusoap.php:1231
typeToForm($name, $type)
Definition nusoap.php:1964
getPHPType($type, $ns)
Definition nusoap.php:1811
schemaCharacterData($parser, $data)
Definition nusoap.php:1665
xdebug($string)
Definition nusoap.php:1794
buildPayload($data, $cookie_str='')
Definition nusoap.php:2925
setContentType($type, $charset=false)
Definition nusoap.php:3414
sendRequest($data, $cookies=null)
Definition nusoap.php:2975
__construct($url, $curl_options=null, $use_curl=false)
Definition nusoap.php:2270
setCurlOption($option, $value)
Definition nusoap.php:2291
setHeader($name, $value)
Definition nusoap.php:2305
getCookiesForRequest($cookies, $secure=false)
Definition nusoap.php:3512
decodeChunked($buffer, $lb)
Definition nusoap.php:2867
setSOAPAction($soapaction)
Definition nusoap.php:2769
send($data, $timeout=0, $response_timeout=30, $cookies=null)
Definition nusoap.php:2638
connect($connection_timeout=0, $response_timeout=30)
Definition nusoap.php:2395
setEncoding($enc='gzip, deflate')
Definition nusoap.php:2780
setProxy($proxyhost, $proxyport, $proxyusername='', $proxypassword='', $proxyauthtype='basic')
Definition nusoap.php:2805
sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies)
Definition nusoap.php:2679
setCredentials($username, $password, $authtype='basic', $digestRequest=[], $certRequest=[])
Definition nusoap.php:2694
parseCookie($cookie_str)
Definition nusoap.php:3446
isSkippableCurlHeader(&$data)
Definition nusoap.php:2834
__construct($name='soapval', $type=false, $value=-1, $element_ns=false, $type_ns=false, $attributes=false)
Definition nusoap.php:2174
serialize($use='encoded')
Definition nusoap.php:2192
serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
Definition nusoap.php:6005
serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
Definition nusoap.php:6324
addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=[])
Definition nusoap.php:6545
serialize($debug=0)
Definition nusoap.php:5602
getOperationData($operation, $bindingType='soap')
Definition nusoap.php:5335
addComplexType($name, $typeClass='complexType', $phpType='array', $compositor='', $restrictionBase='', $elements=[], $attrs=[], $arrayType='')
Definition nusoap.php:6497
getTypeDef($type, $ns)
Definition nusoap.php:5406
webDescription()
Definition nusoap.php:5467
character_data($parser, $data)
Definition nusoap.php:5249
parametersMatchWrapped($type, &$parameters)
Definition nusoap.php:5741
setCredentials($username, $password, $authtype='basic', $certRequest=[])
Definition nusoap.php:5269
addElement($attrs)
Definition nusoap.php:6560
getOperationDataForSoapAction($soapAction, $bindingType='soap')
Definition nusoap.php:5367
serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false)
Definition nusoap.php:6388
fetchWSDL($wsdl)
Definition nusoap.php:4795
parseWSDL($wsdl='')
Definition nusoap.php:4900
start_element($parser, $name, $attrs)
Definition nusoap.php:5005
serializeRPCParameters($operation, $direction, $parameters, $bindingType='soap')
Definition nusoap.php:5825
__construct($wsdl='', $proxyhost=false, $proxyport=false, $proxyusername=false, $proxypassword=false, $timeout=0, $response_timeout=30, $curl_options=null, $use_curl=false)
Definition nusoap.php:4772
end_element($parser, $name)
Definition nusoap.php:5218
addOperation($name, $in=false, $out=false, $namespace=false, $soapaction=false, $style='rpc', $use='encoded', $documentation='', $encodingStyle='')
Definition nusoap.php:6581
getOperations($portName='', $bindingType='soap')
Definition nusoap.php:5294
serializeParameters($operation, $direction, $parameters)
Definition nusoap.php:5927