ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
nusoap.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4 $Id: nusoap.php 28404 2011-04-07 05:44:49Z hschottm $
5 
6 NuSOAP - Web Services Toolkit for PHP
7 
8 Copyright (c) 2002 NuSphere Corporation
9 
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14 
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 
24 The NuSOAP project home is:
25 http://sourceforge.net/projects/nusoap/
26 
27 The primary support for NuSOAP is the mailing list:
28 nusoap-general@lists.sourceforge.net
29 
30 If you have any questions or comments, please email:
31 
32 Dietrich Ayala
33 dietrich@ganx4.com
34 http://dietrich.ganx4.com/nusoap
35 
36 NuSphere Corporation
37 http://www.nusphere.com
38 
39 */
40 
41 /*
42  * Some of the standards implmented in whole or part by NuSOAP:
43  *
44  * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
45  * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
46  * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
47  * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
48  * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
49  * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
50  * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
51  * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
52  * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
53  */
54 
55 /* load classes
56 
57 // necessary classes
58 require_once('class.soapclient.php');
59 require_once('class.soap_val.php');
60 require_once('class.soap_parser.php');
61 require_once('class.soap_fault.php');
62 
63 // transport classes
64 require_once('class.soap_transport_http.php');
65 
66 // optional add-on classes
67 require_once('class.xmlschema.php');
68 require_once('class.wsdl.php');
69 
70 // server class
71 require_once('class.soap_server.php');*/
72 
73 // class variable emulation
74 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
75 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 0;
76 
86 class nusoap_base {
93  var $title = 'NuSOAP';
100  var $version = '0.7.3';
107  var $revision = '$Revision: 28404 $';
114  var $error_str = '';
121  var $debug_str = '';
129  var $charencoding = true;
137 
144  var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
145 
152  //var $soap_defencoding = 'ISO-8859-1';
153  var $soap_defencoding = 'UTF-8';
154 
163  var $namespaces = array(
164  'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
165  'xsd' => 'http://www.w3.org/2001/XMLSchema',
166  'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
167  'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
168  );
169 
176  var $usedNamespaces = array();
177 
185  var $typemap = array(
186  'http://www.w3.org/2001/XMLSchema' => array(
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  'http://www.w3.org/2000/10/XMLSchema' => array(
198  'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
199  'float'=>'double','dateTime'=>'string',
200  'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
201  'http://www.w3.org/1999/XMLSchema' => array(
202  'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
203  'float'=>'double','dateTime'=>'string',
204  'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
205  'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
206  'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
207  'http://xml.apache.org/xml-soap' => array('Map')
208  );
209 
218  var $xmlEntities = array('quot' => '"','amp' => '&',
219  'lt' => '<','gt' => '>','apos' => "'");
220 
226  function nusoap_base() {
227  $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
228  }
229 
236  function getGlobalDebugLevel() {
237  return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
238  }
239 
246  function setGlobalDebugLevel($level) {
247  $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
248  }
249 
256  function getDebugLevel() {
257  return $this->debugLevel;
258  }
259 
266  function setDebugLevel($level) {
267  $this->debugLevel = $level;
268  }
269 
276  function debug($string){
277  if ($this->debugLevel > 0) {
278  $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
279  }
280  }
281 
288  function appendDebug($string){
289  if ($this->debugLevel > 0) {
290  // it would be nice to use a memory stream here to use
291  // memory more efficiently
292  $this->debug_str .= $string;
293  }
294  }
295 
301  function clearDebug() {
302  // it would be nice to use a memory stream here to use
303  // memory more efficiently
304  $this->debug_str = '';
305  }
306 
313  function &getDebug() {
314  // it would be nice to use a memory stream here to use
315  // memory more efficiently
316  return $this->debug_str;
317  }
318 
326  function &getDebugAsXMLComment() {
327  // it would be nice to use a memory stream here to use
328  // memory more efficiently
329  while (strpos($this->debug_str, '--')) {
330  $this->debug_str = str_replace('--', '- -', $this->debug_str);
331  }
332  $ret = "<!--\n" . $this->debug_str . "\n-->";
333  return $ret;
334  }
335 
342  function expandEntities($val) {
343  if ($this->charencoding) {
344  $val = str_replace('&', '&amp;', $val);
345  $val = str_replace("'", '&apos;', $val);
346  $val = str_replace('"', '&quot;', $val);
347  $val = str_replace('<', '&lt;', $val);
348  $val = str_replace('>', '&gt;', $val);
349  }
350  return $val;
351  }
352 
359  function getError(){
360  if($this->error_str != ''){
361  return $this->error_str;
362  }
363  return false;
364  }
365 
372  function setError($str){
373  $this->error_str = $str;
374  }
375 
383  function isArraySimpleOrStruct($val) {
384  $keyList = array_keys($val);
385  foreach ($keyList as $keyListValue) {
386  if (!is_int($keyListValue)) {
387  return 'arrayStruct';
388  }
389  }
390  return 'arraySimple';
391  }
392 
408  function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
409  $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
410  $this->appendDebug('value=' . $this->varDump($val));
411  $this->appendDebug('attributes=' . $this->varDump($attributes));
412 
413  if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
414  $this->debug("serialize_val: serialize soapval");
415  $xml = $val->serialize($use);
416  $this->appendDebug($val->getDebug());
417  $val->clearDebug();
418  $this->debug("serialize_val of soapval returning $xml");
419  return $xml;
420  }
421  // force valid name if necessary
422  if (is_numeric($name)) {
423  $name = '__numeric_' . $name;
424  } elseif (! $name) {
425  $name = 'noname';
426  }
427  // if name has ns, add ns prefix to name
428  $xmlns = '';
429  if($name_ns){
430  $prefix = 'nu'.rand(1000,9999);
431  $name = $prefix.':'.$name;
432  $xmlns .= " xmlns:$prefix=\"$name_ns\"";
433  }
434  // if type is prefixed, create type prefix
435  if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
436  // need to fix this. shouldn't default to xsd if no ns specified
437  // w/o checking against typemap
438  $type_prefix = 'xsd';
439  } elseif($type_ns){
440  $type_prefix = 'ns'.rand(1000,9999);
441  $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
442  }
443  // serialize attributes if present
444  $atts = '';
445  if($attributes){
446  foreach($attributes as $k => $v){
447  $atts .= " $k=\"".$this->expandEntities($v).'"';
448  }
449  }
450  // serialize null value
451  if (is_null($val)) {
452  $this->debug("serialize_val: serialize null");
453  if ($use == 'literal') {
454  // TODO: depends on minOccurs
455  $xml = "<$name$xmlns$atts/>";
456  $this->debug("serialize_val returning $xml");
457  return $xml;
458  } else {
459  if (isset($type) && isset($type_prefix)) {
460  $type_str = " xsi:type=\"$type_prefix:$type\"";
461  } else {
462  $type_str = '';
463  }
464  $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
465  $this->debug("serialize_val returning $xml");
466  return $xml;
467  }
468  }
469  // serialize if an xsd built-in primitive type
470  if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
471  $this->debug("serialize_val: serialize xsd built-in primitive type");
472  if (is_bool($val)) {
473  if ($type == 'boolean') {
474  $val = $val ? 'true' : 'false';
475  } elseif (! $val) {
476  $val = 0;
477  }
478  } else if (is_string($val)) {
479  $val = $this->expandEntities($val);
480  }
481  if ($use == 'literal') {
482  $xml = "<$name$xmlns$atts>$val</$name>";
483  $this->debug("serialize_val returning $xml");
484  return $xml;
485  } else {
486  $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
487  $this->debug("serialize_val returning $xml");
488  return $xml;
489  }
490  }
491  // detect type and serialize
492  $xml = '';
493  switch(true) {
494  case (is_bool($val) || $type == 'boolean'):
495  $this->debug("serialize_val: serialize boolean");
496  if ($type == 'boolean') {
497  $val = $val ? 'true' : 'false';
498  } elseif (! $val) {
499  $val = 0;
500  }
501  if ($use == 'literal') {
502  $xml .= "<$name$xmlns$atts>$val</$name>";
503  } else {
504  $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
505  }
506  break;
507  case (is_int($val) || is_long($val) || $type == 'int'):
508  $this->debug("serialize_val: serialize int");
509  if ($use == 'literal') {
510  $xml .= "<$name$xmlns$atts>$val</$name>";
511  } else {
512  $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
513  }
514  break;
515  case (is_float($val)|| is_double($val) || $type == 'float'):
516  $this->debug("serialize_val: serialize float");
517  if ($use == 'literal') {
518  $xml .= "<$name$xmlns$atts>$val</$name>";
519  } else {
520  $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
521  }
522  break;
523  case (is_string($val) || $type == 'string'):
524  $this->debug("serialize_val: serialize string");
525  $val = $this->expandEntities($val);
526  if ($use == 'literal') {
527  $xml .= "<$name$xmlns$atts>$val</$name>";
528  } else {
529  $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
530  }
531  break;
532  case is_object($val):
533  $this->debug("serialize_val: serialize object");
534  if (get_class($val) == 'soapval') {
535  $this->debug("serialize_val: serialize soapval object");
536  $pXml = $val->serialize($use);
537  $this->appendDebug($val->getDebug());
538  $val->clearDebug();
539  } else {
540  if (! $name) {
541  $name = get_class($val);
542  $this->debug("In serialize_val, used class name $name as element name");
543  } else {
544  $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
545  }
546  foreach(get_object_vars($val) as $k => $v){
547  $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
548  }
549  }
550  if(isset($type) && isset($type_prefix)){
551  $type_str = " xsi:type=\"$type_prefix:$type\"";
552  } else {
553  $type_str = '';
554  }
555  if ($use == 'literal') {
556  $xml .= "<$name$xmlns$atts>$pXml</$name>";
557  } else {
558  $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
559  }
560  break;
561  break;
562  case (is_array($val) || $type):
563  // detect if struct or array
564  $valueType = $this->isArraySimpleOrStruct($val);
565  if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){
566  $this->debug("serialize_val: serialize array");
567  $i = 0;
568  if(is_array($val) && count($val)> 0){
569  foreach($val as $v){
570  if(is_object($v) && get_class($v) == 'soapval'){
571  $tt_ns = $v->type_ns;
572  $tt = $v->type;
573  } elseif (is_array($v)) {
574  $tt = $this->isArraySimpleOrStruct($v);
575  } else {
576  $tt = gettype($v);
577  }
578  $array_types[$tt] = 1;
579  // TODO: for literal, the name should be $name
580  $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
581  ++$i;
582  }
583  if(count($array_types) > 1){
584  $array_typename = 'xsd:anyType';
585  } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
586  if ($tt == 'integer') {
587  $tt = 'int';
588  }
589  $array_typename = 'xsd:'.$tt;
590  } elseif(isset($tt) && $tt == 'arraySimple'){
591  $array_typename = 'SOAP-ENC:Array';
592  } elseif(isset($tt) && $tt == 'arrayStruct'){
593  $array_typename = 'unnamed_struct_use_soapval';
594  } else {
595  // if type is prefixed, create type prefix
596  if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
597  $array_typename = 'xsd:' . $tt;
598  } elseif ($tt_ns) {
599  $tt_prefix = 'ns' . rand(1000, 9999);
600  $array_typename = "$tt_prefix:$tt";
601  $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
602  } else {
603  $array_typename = $tt;
604  }
605  }
606  $array_type = $i;
607  if ($use == 'literal') {
608  $type_str = '';
609  } else if (isset($type) && isset($type_prefix)) {
610  $type_str = " xsi:type=\"$type_prefix:$type\"";
611  } else {
612  $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
613  }
614  // empty array
615  } else {
616  if ($use == 'literal') {
617  $type_str = '';
618  } else if (isset($type) && isset($type_prefix)) {
619  $type_str = " xsi:type=\"$type_prefix:$type\"";
620  } else {
621  $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
622  }
623  }
624  // TODO: for array in literal, there is no wrapper here
625  $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
626  } else {
627  // got a struct
628  $this->debug("serialize_val: serialize struct");
629  if(isset($type) && isset($type_prefix)){
630  $type_str = " xsi:type=\"$type_prefix:$type\"";
631  } else {
632  $type_str = '';
633  }
634  if ($use == 'literal') {
635  $xml .= "<$name$xmlns$atts>";
636  } else {
637  $xml .= "<$name$xmlns$type_str$atts>";
638  }
639  foreach($val as $k => $v){
640  // Apache Map
641  if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
642  $xml .= '<item>';
643  $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
644  $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
645  $xml .= '</item>';
646  } else {
647  $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
648  }
649  }
650  $xml .= "</$name>";
651  }
652  break;
653  default:
654  $this->debug("serialize_val: serialize unknown");
655  $xml .= 'not detected, got '.gettype($val).' for '.$val;
656  break;
657  }
658  $this->debug("serialize_val returning $xml");
659  return $xml;
660  }
661 
674  function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
675  // TODO: add an option to automatically run utf8_encode on $body and $headers
676  // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
677  // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
678 
679  $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
680  $this->debug("headers:");
681  $this->appendDebug($this->varDump($headers));
682  $this->debug("namespaces:");
683  $this->appendDebug($this->varDump($namespaces));
684 
685  // serialize namespaces
686  $ns_string = '';
687  foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
688  $ns_string .= " xmlns:$k=\"$v\"";
689  }
690  if($encodingStyle) {
691  $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
692  }
693 
694  // serialize headers
695  if($headers){
696  if (is_array($headers)) {
697  $xml = '';
698  foreach ($headers as $k => $v) {
699  if (is_object($v) && get_class($v) == 'soapval') {
700  $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
701  } else {
702  $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
703  }
704  }
705  $headers = $xml;
706  $this->debug("In serializeEnvelope, serialized array of headers to $headers");
707  }
708  $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
709  }
710  // serialize envelope
711  return
712  '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
713  '<SOAP-ENV:Envelope'.$ns_string.">".
714  $headers.
715  "<SOAP-ENV:Body>".
716  $body.
717  "</SOAP-ENV:Body>".
718  "</SOAP-ENV:Envelope>";
719  }
720 
729  function formatDump($str){
730  $str = htmlspecialchars($str);
731  return nl2br($str);
732  }
733 
741  function contractQname($qname){
742  // get element namespace
743  //$this->xdebug("Contract $qname");
744  if (strrpos($qname, ':')) {
745  // get unqualified name
746  $name = substr($qname, strrpos($qname, ':') + 1);
747  // get ns
748  $ns = substr($qname, 0, strrpos($qname, ':'));
749  $p = $this->getPrefixFromNamespace($ns);
750  if ($p) {
751  return $p . ':' . $name;
752  }
753  return $qname;
754  } else {
755  return $qname;
756  }
757  }
758 
766  function expandQname($qname){
767  // get element prefix
768  if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){
769  // get unqualified name
770  $name = substr(strstr($qname,':'),1);
771  // get ns prefix
772  $prefix = substr($qname,0,strpos($qname,':'));
773  if(isset($this->namespaces[$prefix])){
774  return $this->namespaces[$prefix].':'.$name;
775  } else {
776  return $qname;
777  }
778  } else {
779  return $qname;
780  }
781  }
782 
791  function getLocalPart($str){
792  if($sstr = strrchr($str,':')){
793  // get unqualified name
794  return substr( $sstr, 1 );
795  } else {
796  return $str;
797  }
798  }
799 
808  function getPrefix($str){
809  if($pos = strrpos($str,':')){
810  // get prefix
811  return substr($str,0,$pos);
812  }
813  return false;
814  }
815 
823  function getNamespaceFromPrefix($prefix){
824  if (isset($this->namespaces[$prefix])) {
825  return $this->namespaces[$prefix];
826  }
827  //$this->setError("No namespace registered for prefix '$prefix'");
828  return false;
829  }
830 
839  function getPrefixFromNamespace($ns) {
840  foreach ($this->namespaces as $p => $n) {
841  if ($ns == $n || $ns == $p) {
842  $this->usedNamespaces[$p] = $n;
843  return $p;
844  }
845  }
846  return false;
847  }
848 
855  function getmicrotime() {
856  if (function_exists('gettimeofday')) {
857  $tod = gettimeofday();
858  $sec = $tod['sec'];
859  $usec = $tod['usec'];
860  } else {
861  $sec = time();
862  $usec = 0;
863  }
864  return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
865  }
866 
874  function varDump($data) {
875  ob_start();
876  var_dump($data);
877  $ret_val = ob_get_contents();
878  ob_end_clean();
879  return $ret_val;
880  }
881 
888  function __toString() {
889  return $this->varDump($this);
890  }
891 }
892 
893 // XML Schema Datatype Helper Functions
894 
895 //xsd:dateTime helpers
896 
904 function timestamp_to_iso8601($timestamp,$utc=true){
905  $datestr = date('Y-m-d\TH:i:sO',$timestamp);
906  if($utc){
907  $pattern = '/'.
908  '([0-9]{4})-'. // centuries & years CCYY-
909  '([0-9]{2})-'. // months MM-
910  '([0-9]{2})'. // days DD
911  'T'. // separator T
912  '([0-9]{2}):'. // hours hh:
913  '([0-9]{2}):'. // minutes mm:
914  '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
915  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
916  '/';
917 
918  if(preg_match($pattern,$datestr,$regs)){
919  return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
920  }
921  return false;
922  } else {
923  return $datestr;
924  }
925 }
926 
933 function iso8601_to_timestamp($datestr){
934  $pattern = '/'.
935  '([0-9]{4})-'. // centuries & years CCYY-
936  '([0-9]{2})-'. // months MM-
937  '([0-9]{2})'. // days DD
938  'T'. // separator T
939  '([0-9]{2}):'. // hours hh:
940  '([0-9]{2}):'. // minutes mm:
941  '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
942  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
943  '/';
944 
945  if(preg_match($pattern,$datestr,$regs)){
946  // not utc
947  if($regs[8] != 'Z'){
948  $op = substr($regs[8],0,1);
949  $h = substr($regs[8],1,2);
950  $m = substr($regs[8],strlen($regs[8])-2,2);
951  if($op == '-'){
952  $regs[4] = $regs[4] + $h;
953  $regs[5] = $regs[5] + $m;
954  } elseif($op == '+'){
955  $regs[4] = $regs[4] - $h;
956  $regs[5] = $regs[5] - $m;
957  }
958  }
959  return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
960 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
961  } else {
962  return false;
963  }
964 }
965 
973 function usleepWindows($usec)
974 {
975  $start = gettimeofday();
976 
977  do
978  {
979  $stop = gettimeofday();
980  $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
981  + $stop['usec'] - $start['usec'];
982  }
983  while ($timePassed < $usec);
984 }
985 
986 ?><?php
987 
988 
989 
998 class nusoap_fault extends nusoap_base {
1023 
1034  $this->faultcode = $faultcode;
1035  $this->faultactor = $faultactor;
1036  $this->faultstring = $faultstring;
1037  $this->faultdetail = $faultdetail;
1038  }
1039 
1046  function serialize(){
1047  $ns_string = '';
1048  foreach($this->namespaces as $k => $v){
1049  $ns_string .= "\n xmlns:$k=\"$v\"";
1050  }
1051  $return_msg =
1052  '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1053  '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1054  '<SOAP-ENV:Body>'.
1055  '<SOAP-ENV:Fault>'.
1056  $this->serialize_val($this->faultcode, 'faultcode').
1057  $this->serialize_val($this->faultactor, 'faultactor').
1058  $this->serialize_val($this->faultstring, 'faultstring').
1059  $this->serialize_val($this->faultdetail, 'detail').
1060  '</SOAP-ENV:Fault>'.
1061  '</SOAP-ENV:Body>'.
1062  '</SOAP-ENV:Envelope>';
1063  return $return_msg;
1064  }
1065 }
1066 
1070 class soap_fault extends nusoap_fault {
1071 }
1072 
1073 ?><?php
1074 
1075 
1076 
1087 
1088  // files
1089  var $schema = '';
1090  var $xml = '';
1091  // namespaces
1093  // schema info
1094  var $schemaInfo = array();
1096  // types, elements, attributes defined by the schema
1097  var $attributes = array();
1098  var $complexTypes = array();
1099  var $complexTypeStack = array();
1101  var $elements = array();
1102  var $elementStack = array();
1103  var $currentElement = null;
1104  var $simpleTypes = array();
1105  var $simpleTypeStack = array();
1107  // imports
1108  var $imports = array();
1109  // parser vars
1110  var $parser;
1111  var $position = 0;
1112  var $depth = 0;
1113  var $depth_array = array();
1114  var $message = array();
1115  var $defaultNamespace = array();
1116 
1125  function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
1127  $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1128  // files
1129  $this->schema = $schema;
1130  $this->xml = $xml;
1131 
1132  // namespaces
1133  $this->enclosingNamespaces = $namespaces;
1134  $this->namespaces = array_merge($this->namespaces, $namespaces);
1135 
1136  // parse schema file
1137  if($schema != ''){
1138  $this->debug('initial schema file: '.$schema);
1139  $this->parseFile($schema, 'schema');
1140  }
1141 
1142  // parse xml file
1143  if($xml != ''){
1144  $this->debug('initial xml file: '.$xml);
1145  $this->parseFile($xml, 'xml');
1146  }
1147 
1148  }
1149 
1158  function parseFile($xml,$type){
1159  // parse xml file
1160  if($xml != ""){
1161  $xmlStr = @join("",@file($xml));
1162  if($xmlStr == ""){
1163  $msg = 'Error reading XML from '.$xml;
1164  $this->setError($msg);
1165  $this->debug($msg);
1166  return false;
1167  } else {
1168  $this->debug("parsing $xml");
1169  $this->parseString($xmlStr,$type);
1170  $this->debug("done parsing $xml");
1171  return true;
1172  }
1173  }
1174  return false;
1175  }
1176 
1185  // parse xml string
1186  if($xml != ""){
1187 
1188  // Create an XML parser.
1189  $this->parser = xml_parser_create();
1190  // Set the options for parsing the XML data.
1191  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1192 
1193  // Set the object for the parser.
1194  xml_set_object($this->parser, $this);
1195 
1196  // Set the element handlers for the parser.
1197  if($type == "schema"){
1198  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1199  xml_set_character_data_handler($this->parser,'schemaCharacterData');
1200  } elseif($type == "xml"){
1201  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1202  xml_set_character_data_handler($this->parser,'xmlCharacterData');
1203  }
1204 
1205  // Parse the XML file.
1206  if(!xml_parse($this->parser,$xml,true)){
1207  // Display an error message.
1208  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1209  xml_get_current_line_number($this->parser),
1210  xml_error_string(xml_get_error_code($this->parser))
1211  );
1212  $this->debug($errstr);
1213  $this->debug("XML payload:\n" . $xml);
1214  $this->setError($errstr);
1215  }
1216 
1217  xml_parser_free($this->parser);
1218  } else{
1219  $this->debug('no xml passed to parseString()!!');
1220  $this->setError('no xml passed to parseString()!!');
1221  }
1222  }
1223 
1231  function CreateTypeName($ename) {
1232  $scope = '';
1233  for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1234  $scope .= $this->complexTypeStack[$i] . '_';
1235  }
1236  return $scope . $ename . '_ContainedType';
1237  }
1238 
1247  function schemaStartElement($parser, $name, $attrs) {
1248 
1249  // position in the total number of elements, starting from 0
1250  $pos = $this->position++;
1251  $depth = $this->depth++;
1252  // set self as current value for this depth
1253  $this->depth_array[$depth] = $pos;
1254  $this->message[$pos] = array('cdata' => '');
1255  if ($depth > 0) {
1256  $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1257  } else {
1258  $this->defaultNamespace[$pos] = false;
1259  }
1260 
1261  // get element prefix
1262  if($prefix = $this->getPrefix($name)){
1263  // get unqualified name
1264  $name = $this->getLocalPart($name);
1265  } else {
1266  $prefix = '';
1267  }
1268 
1269  // loop thru attributes, expanding, and registering namespace declarations
1270  if(count($attrs) > 0){
1271  foreach($attrs as $k => $v){
1272  // if ns declarations, add to class level array of valid namespaces
1273  if(preg_match('/^xmlns/',$k)){
1274  //$this->xdebug("$k: $v");
1275  //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1276  if($ns_prefix = substr(strrchr($k,':'),1)){
1277  //$this->xdebug("Add namespace[$ns_prefix] = $v");
1278  $this->namespaces[$ns_prefix] = $v;
1279  } else {
1280  $this->defaultNamespace[$pos] = $v;
1281  if (! $this->getPrefixFromNamespace($v)) {
1282  $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1283  }
1284  }
1285  if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1286  $this->XMLSchemaVersion = $v;
1287  $this->namespaces['xsi'] = $v.'-instance';
1288  }
1289  }
1290  }
1291  foreach($attrs as $k => $v){
1292  // expand each attribute
1293  $k = strpos($k,':') ? $this->expandQname($k) : $k;
1294  $v = strpos($v,':') ? $this->expandQname($v) : $v;
1295  $eAttrs[$k] = $v;
1296  }
1297  $attrs = $eAttrs;
1298  } else {
1299  $attrs = array();
1300  }
1301  // find status, register data
1302  switch($name){
1303  case 'all': // (optional) compositor content for a complexType
1304  case 'choice':
1305  case 'group':
1306  case 'sequence':
1307  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1308  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1309  //if($name == 'all' || $name == 'sequence'){
1310  // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1311  //}
1312  break;
1313  case 'attribute': // complexType attribute
1314  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1315  $this->xdebug("parsing attribute:");
1316  $this->appendDebug($this->varDump($attrs));
1317  if (!isset($attrs['form'])) {
1318  $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1319  }
1320  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1321  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1322  if (!strpos($v, ':')) {
1323  // no namespace in arrayType attribute value...
1324  if ($this->defaultNamespace[$pos]) {
1325  // ...so use the default
1326  $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1327  }
1328  }
1329  }
1330  if(isset($attrs['name'])){
1331  $this->attributes[$attrs['name']] = $attrs;
1332  $aname = $attrs['name'];
1333  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1334  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1335  $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1336  } else {
1337  $aname = '';
1338  }
1339  } elseif(isset($attrs['ref'])){
1340  $aname = $attrs['ref'];
1341  $this->attributes[$attrs['ref']] = $attrs;
1342  }
1343 
1344  if($this->currentComplexType){ // This should *always* be
1345  $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1346  }
1347  // arrayType attribute
1348  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1349  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1350  $prefix = $this->getPrefix($aname);
1351  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1352  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1353  } else {
1354  $v = '';
1355  }
1356  if(strpos($v,'[,]')){
1357  $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1358  }
1359  $v = substr($v,0,strpos($v,'[')); // clip the []
1360  if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1361  $v = $this->XMLSchemaVersion.':'.$v;
1362  }
1363  $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1364  }
1365  break;
1366  case 'complexContent': // (optional) content for a complexType
1367  break;
1368  case 'complexType':
1369  array_push($this->complexTypeStack, $this->currentComplexType);
1370  if(isset($attrs['name'])){
1371  // TODO: what is the scope of named complexTypes that appear
1372  // nested within other c complexTypes?
1373  $this->xdebug('processing named complexType '.$attrs['name']);
1374  //$this->currentElement = false;
1375  $this->currentComplexType = $attrs['name'];
1376  $this->complexTypes[$this->currentComplexType] = $attrs;
1377  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1378  // This is for constructs like
1379  // <complexType name="ListOfString" base="soap:Array">
1380  // <sequence>
1381  // <element name="string" type="xsd:string"
1382  // minOccurs="0" maxOccurs="unbounded" />
1383  // </sequence>
1384  // </complexType>
1385  if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
1386  $this->xdebug('complexType is unusual array');
1387  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1388  } else {
1389  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1390  }
1391  } else {
1392  $name = $this->CreateTypeName($this->currentElement);
1393  $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1394  $this->currentComplexType = $name;
1395  //$this->currentElement = false;
1396  $this->complexTypes[$this->currentComplexType] = $attrs;
1397  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1398  // This is for constructs like
1399  // <complexType name="ListOfString" base="soap:Array">
1400  // <sequence>
1401  // <element name="string" type="xsd:string"
1402  // minOccurs="0" maxOccurs="unbounded" />
1403  // </sequence>
1404  // </complexType>
1405  if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
1406  $this->xdebug('complexType is unusual array');
1407  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1408  } else {
1409  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1410  }
1411  }
1412  break;
1413  case 'element':
1414  array_push($this->elementStack, $this->currentElement);
1415  if (!isset($attrs['form'])) {
1416  $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1417  }
1418  if(isset($attrs['type'])){
1419  $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1420  if (! $this->getPrefix($attrs['type'])) {
1421  if ($this->defaultNamespace[$pos]) {
1422  $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1423  $this->xdebug('used default namespace to make type ' . $attrs['type']);
1424  }
1425  }
1426  // This is for constructs like
1427  // <complexType name="ListOfString" base="soap:Array">
1428  // <sequence>
1429  // <element name="string" type="xsd:string"
1430  // minOccurs="0" maxOccurs="unbounded" />
1431  // </sequence>
1432  // </complexType>
1433  if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1434  $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1435  $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1436  }
1437  $this->currentElement = $attrs['name'];
1438  $ename = $attrs['name'];
1439  } elseif(isset($attrs['ref'])){
1440  $this->xdebug("processing element as ref to ".$attrs['ref']);
1441  $this->currentElement = "ref to ".$attrs['ref'];
1442  $ename = $this->getLocalPart($attrs['ref']);
1443  } else {
1444  $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1445  $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1446  $this->currentElement = $attrs['name'];
1447  $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1448  $ename = $attrs['name'];
1449  }
1450  if (isset($ename) && $this->currentComplexType) {
1451  $this->xdebug("add element $ename to complexType $this->currentComplexType");
1452  $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1453  } elseif (!isset($attrs['ref'])) {
1454  $this->xdebug("add element $ename to elements array");
1455  $this->elements[ $attrs['name'] ] = $attrs;
1456  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1457  }
1458  break;
1459  case 'enumeration': // restriction value list member
1460  $this->xdebug('enumeration ' . $attrs['value']);
1461  if ($this->currentSimpleType) {
1462  $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1463  } elseif ($this->currentComplexType) {
1464  $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1465  }
1466  break;
1467  case 'extension': // simpleContent or complexContent type extension
1468  $this->xdebug('extension ' . $attrs['base']);
1469  if ($this->currentComplexType) {
1470  $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1471  }
1472  break;
1473  case 'import':
1474  if (isset($attrs['schemaLocation'])) {
1475  //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1476  $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1477  } else {
1478  //$this->xdebug('import namespace ' . $attrs['namespace']);
1479  $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1480  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1481  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1482  }
1483  }
1484  break;
1485  case 'list': // simpleType value list
1486  break;
1487  case 'restriction': // simpleType, simpleContent or complexContent value restriction
1488  $this->xdebug('restriction ' . $attrs['base']);
1489  if($this->currentSimpleType){
1490  $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1491  } elseif($this->currentComplexType){
1492  $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1493  if(strstr($attrs['base'],':') == ':Array'){
1494  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1495  }
1496  }
1497  break;
1498  case 'schema':
1499  $this->schemaInfo = $attrs;
1500  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1501  if (isset($attrs['targetNamespace'])) {
1502  $this->schemaTargetNamespace = $attrs['targetNamespace'];
1503  }
1504  if (!isset($attrs['elementFormDefault'])) {
1505  $this->schemaInfo['elementFormDefault'] = 'unqualified';
1506  }
1507  if (!isset($attrs['attributeFormDefault'])) {
1508  $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1509  }
1510  break;
1511  case 'simpleContent': // (optional) content for a complexType
1512  break;
1513  case 'simpleType':
1514  array_push($this->simpleTypeStack, $this->currentSimpleType);
1515  if(isset($attrs['name'])){
1516  $this->xdebug("processing simpleType for name " . $attrs['name']);
1517  $this->currentSimpleType = $attrs['name'];
1518  $this->simpleTypes[ $attrs['name'] ] = $attrs;
1519  $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1520  $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1521  } else {
1522  $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1523  $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1524  $this->currentSimpleType = $name;
1525  //$this->currentElement = false;
1526  $this->simpleTypes[$this->currentSimpleType] = $attrs;
1527  $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1528  }
1529  break;
1530  case 'union': // simpleType type list
1531  break;
1532  default:
1533  //$this->xdebug("do not have anything to do for element $name");
1534  }
1535  }
1536 
1545  // bring depth down a notch
1546  $this->depth--;
1547  // position of current element is equal to the last value left in depth_array for my depth
1548  if(isset($this->depth_array[$this->depth])){
1549  $pos = $this->depth_array[$this->depth];
1550  }
1551  // get element prefix
1552  if ($prefix = $this->getPrefix($name)){
1553  // get unqualified name
1554  $name = $this->getLocalPart($name);
1555  } else {
1556  $prefix = '';
1557  }
1558  // move on...
1559  if($name == 'complexType'){
1560  $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1561  $this->currentComplexType = array_pop($this->complexTypeStack);
1562  //$this->currentElement = false;
1563  }
1564  if($name == 'element'){
1565  $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1566  $this->currentElement = array_pop($this->elementStack);
1567  }
1568  if($name == 'simpleType'){
1569  $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1570  $this->currentSimpleType = array_pop($this->simpleTypeStack);
1571  }
1572  }
1573 
1582  $pos = $this->depth_array[$this->depth - 1];
1583  $this->message[$pos]['cdata'] .= $data;
1584  }
1585 
1591  function serializeSchema(){
1592 
1593  $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1594  $xml = '';
1595  // imports
1596  if (sizeof($this->imports) > 0) {
1597  foreach($this->imports as $ns => $list) {
1598  foreach ($list as $ii) {
1599  if ($ii['location'] != '') {
1600  $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1601  } else {
1602  $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1603  }
1604  }
1605  }
1606  }
1607  // complex types
1608  foreach($this->complexTypes as $typeName => $attrs){
1609  $contentStr = '';
1610  // serialize child elements
1611  if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1612  foreach($attrs['elements'] as $element => $eParts){
1613  if(isset($eParts['ref'])){
1614  $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1615  } else {
1616  $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1617  foreach ($eParts as $aName => $aValue) {
1618  // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1619  if ($aName != 'name' && $aName != 'type') {
1620  $contentStr .= " $aName=\"$aValue\"";
1621  }
1622  }
1623  $contentStr .= "/>\n";
1624  }
1625  }
1626  // compositor wraps elements
1627  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1628  $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
1629  }
1630  }
1631  // attributes
1632  if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1633  foreach($attrs['attrs'] as $attr => $aParts){
1634  $contentStr .= " <$schemaPrefix:attribute";
1635  foreach ($aParts as $a => $v) {
1636  if ($a == 'ref' || $a == 'type') {
1637  $contentStr .= " $a=\"".$this->contractQName($v).'"';
1638  } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1639  $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1640  $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1641  } else {
1642  $contentStr .= " $a=\"$v\"";
1643  }
1644  }
1645  $contentStr .= "/>\n";
1646  }
1647  }
1648  // if restriction
1649  if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1650  $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
1651  // complex or simple content
1652  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1653  $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
1654  }
1655  }
1656  // finalize complex type
1657  if($contentStr != ''){
1658  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1659  } else {
1660  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1661  }
1662  $xml .= $contentStr;
1663  }
1664  // simple types
1665  if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1666  foreach($this->simpleTypes as $typeName => $eParts){
1667  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
1668  if (isset($eParts['enumeration'])) {
1669  foreach ($eParts['enumeration'] as $e) {
1670  $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1671  }
1672  }
1673  $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1674  }
1675  }
1676  // elements
1677  if(isset($this->elements) && count($this->elements) > 0){
1678  foreach($this->elements as $element => $eParts){
1679  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1680  }
1681  }
1682  // attributes
1683  if(isset($this->attributes) && count($this->attributes) > 0){
1684  foreach($this->attributes as $attr => $aParts){
1685  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1686  }
1687  }
1688  // finish 'er up
1689  $attr = '';
1690  foreach ($this->schemaInfo as $k => $v) {
1691  if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1692  $attr .= " $k=\"$v\"";
1693  }
1694  }
1695  $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1696  foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1697  $el .= " xmlns:$nsp=\"$ns\"";
1698  }
1699  $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1700  return $xml;
1701  }
1702 
1709  function xdebug($string){
1710  $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1711  }
1712 
1725  function getPHPType($type,$ns){
1726  if(isset($this->typemap[$ns][$type])){
1727  //print "found type '$type' and ns $ns in typemap<br>";
1728  return $this->typemap[$ns][$type];
1729  } elseif(isset($this->complexTypes[$type])){
1730  //print "getting type '$type' and ns $ns from complexTypes array<br>";
1731  return $this->complexTypes[$type]['phpType'];
1732  }
1733  return false;
1734  }
1735 
1758  function getTypeDef($type){
1759  //$this->debug("in getTypeDef for type $type");
1760  if (substr($type, -1) == '^') {
1761  $is_element = 1;
1762  $type = substr($type, 0, -1);
1763  } else {
1764  $is_element = 0;
1765  }
1766 
1767  if((! $is_element) && isset($this->complexTypes[$type])){
1768  $this->xdebug("in getTypeDef, found complexType $type");
1769  return $this->complexTypes[$type];
1770  } elseif((! $is_element) && isset($this->simpleTypes[$type])){
1771  $this->xdebug("in getTypeDef, found simpleType $type");
1772  if (!isset($this->simpleTypes[$type]['phpType'])) {
1773  // get info for type to tack onto the simple type
1774  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1775  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1776  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1777  $etype = $this->getTypeDef($uqType);
1778  if ($etype) {
1779  $this->xdebug("in getTypeDef, found type for simpleType $type:");
1780  $this->xdebug($this->varDump($etype));
1781  if (isset($etype['phpType'])) {
1782  $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1783  }
1784  if (isset($etype['elements'])) {
1785  $this->simpleTypes[$type]['elements'] = $etype['elements'];
1786  }
1787  }
1788  }
1789  return $this->simpleTypes[$type];
1790  } elseif(isset($this->elements[$type])){
1791  $this->xdebug("in getTypeDef, found element $type");
1792  if (!isset($this->elements[$type]['phpType'])) {
1793  // get info for type to tack onto the element
1794  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1795  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1796  $etype = $this->getTypeDef($uqType);
1797  if ($etype) {
1798  $this->xdebug("in getTypeDef, found type for element $type:");
1799  $this->xdebug($this->varDump($etype));
1800  if (isset($etype['phpType'])) {
1801  $this->elements[$type]['phpType'] = $etype['phpType'];
1802  }
1803  if (isset($etype['elements'])) {
1804  $this->elements[$type]['elements'] = $etype['elements'];
1805  }
1806  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1807  $this->xdebug("in getTypeDef, element $type is an XSD type");
1808  $this->elements[$type]['phpType'] = 'scalar';
1809  }
1810  }
1811  return $this->elements[$type];
1812  } elseif(isset($this->attributes[$type])){
1813  $this->xdebug("in getTypeDef, found attribute $type");
1814  return $this->attributes[$type];
1815  } elseif (preg_match('/_ContainedType$/', $type)) {
1816  $this->xdebug("in getTypeDef, have an untyped element $type");
1817  $typeDef['typeClass'] = 'simpleType';
1818  $typeDef['phpType'] = 'scalar';
1819  $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1820  return $typeDef;
1821  }
1822  $this->xdebug("in getTypeDef, did not find $type");
1823  return false;
1824  }
1825 
1835  //print "in sTD() for type $type<br>";
1836  if($typeDef = $this->getTypeDef($type)){
1837  $str .= '<'.$type;
1838  if(is_array($typeDef['attrs'])){
1839  foreach($typeDef['attrs'] as $attName => $data){
1840  $str .= " $attName=\"{type = ".$data['type']."}\"";
1841  }
1842  }
1843  $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1844  if(count($typeDef['elements']) > 0){
1845  $str .= ">";
1846  foreach($typeDef['elements'] as $element => $eData){
1847  $str .= $this->serializeTypeDef($element);
1848  }
1849  $str .= "</$type>";
1850  } elseif($typeDef['typeClass'] == 'element') {
1851  $str .= "></$type>";
1852  } else {
1853  $str .= "/>";
1854  }
1855  return $str;
1856  }
1857  return false;
1858  }
1859 
1871  // get typedef
1872  if($typeDef = $this->getTypeDef($type)){
1873  // if struct
1874  if($typeDef['phpType'] == 'struct'){
1875  $buffer .= '<table>';
1876  foreach($typeDef['elements'] as $child => $childDef){
1877  $buffer .= "
1878  <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1879  <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1880  }
1881  $buffer .= '</table>';
1882  // if array
1883  } elseif($typeDef['phpType'] == 'array'){
1884  $buffer .= '<table>';
1885  for($i=0;$i < 3; $i++){
1886  $buffer .= "
1887  <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1888  <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1889  }
1890  $buffer .= '</table>';
1891  // if scalar
1892  } else {
1893  $buffer .= "<input type='text' name='parameters[$name]'>";
1894  }
1895  } else {
1896  $buffer .= "<input type='text' name='parameters[$name]'>";
1897  }
1898  return $buffer;
1899  }
1900 
1942  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1943  $this->complexTypes[$name] = array(
1944  'name' => $name,
1945  'typeClass' => $typeClass,
1946  'phpType' => $phpType,
1947  'compositor'=> $compositor,
1948  'restrictionBase' => $restrictionBase,
1949  'elements' => $elements,
1950  'attrs' => $attrs,
1951  'arrayType' => $arrayType
1952  );
1953 
1954  $this->xdebug("addComplexType $name:");
1955  $this->appendDebug($this->varDump($this->complexTypes[$name]));
1956  }
1957 
1970  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1971  $this->simpleTypes[$name] = array(
1972  'name' => $name,
1973  'typeClass' => $typeClass,
1974  'phpType' => $phpType,
1975  'type' => $restrictionBase,
1976  'enumeration' => $enumeration
1977  );
1978 
1979  $this->xdebug("addSimpleType $name:");
1980  $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1981  }
1982 
1990  function addElement($attrs) {
1991  if (! $this->getPrefix($attrs['type'])) {
1992  $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
1993  }
1994  $this->elements[ $attrs['name'] ] = $attrs;
1995  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1996 
1997  $this->xdebug("addElement " . $attrs['name']);
1998  $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
1999  }
2000 }
2001 
2005 class XMLSchema extends nusoap_xmlschema {
2006 }
2007 
2008 ?><?php
2009 
2010 
2011 
2023 class soapval extends nusoap_base {
2030  var $name;
2037  var $type;
2044  var $value;
2066 
2078  function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
2080  $this->name = $name;
2081  $this->type = $type;
2082  $this->value = $value;
2083  $this->element_ns = $element_ns;
2084  $this->type_ns = $type_ns;
2085  $this->attributes = $attributes;
2086  }
2087 
2095  function serialize($use='encoded') {
2096  return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2097  }
2098 
2105  function decode(){
2106  return $this->value;
2107  }
2108 }
2109 
2110 
2111 
2112 ?><?php
2113 
2114 
2115 
2125 class soap_transport_http extends nusoap_base {
2126 
2127  var $url = '';
2128  var $uri = '';
2129  var $digest_uri = '';
2130  var $scheme = '';
2131  var $host = '';
2132  var $port = '';
2133  var $path = '';
2134  var $request_method = 'POST';
2135  var $protocol_version = '1.0';
2136  var $encoding = '';
2137  var $outgoing_headers = array();
2138  var $incoming_headers = array();
2139  var $incoming_cookies = array();
2140  var $outgoing_payload = '';
2141  var $incoming_payload = '';
2142  var $response_status_line; // HTTP response status line
2143  var $useSOAPAction = true;
2144  var $persistentConnection = false;
2145  var $ch = false; // cURL handle
2146  var $ch_options = array(); // cURL custom options
2147  var $use_curl = false; // force cURL use
2148  var $proxy = null; // proxy information (associative array)
2149  var $username = '';
2150  var $password = '';
2151  var $authtype = '';
2152  var $digestRequest = array();
2153  var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2154  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2155  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2156  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2157  // passphrase: SSL key password/passphrase
2158  // certpassword: SSL certificate password
2159  // verifypeer: default is 1
2160  // verifyhost: default is 1
2161 
2170  function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
2172  $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2173  $this->appendDebug($this->varDump($curl_options));
2174  $this->setURL($url);
2175  if (is_array($curl_options)) {
2176  $this->ch_options = $curl_options;
2177  }
2178  $this->use_curl = $use_curl;
2179  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2180  $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
2181  }
2182 
2190  function setCurlOption($option, $value) {
2191  $this->debug("setCurlOption option=$option, value=");
2192  $this->appendDebug($this->varDump($value));
2193  curl_setopt($this->ch, $option, $value);
2194  }
2195 
2203  function setHeader($name, $value) {
2204  $this->outgoing_headers[$name] = $value;
2205  $this->debug("set header $name: $value");
2206  }
2207 
2214  function unsetHeader($name) {
2215  if (isset($this->outgoing_headers[$name])) {
2216  $this->debug("unset header $name");
2217  unset($this->outgoing_headers[$name]);
2218  }
2219  }
2220 
2227  function setURL($url) {
2228  $this->url = $url;
2229 
2230  $u = parse_url($url);
2231  foreach($u as $k => $v){
2232  $this->debug("parsed URL $k = $v");
2233  $this->$k = $v;
2234  }
2235 
2236  // add any GET params to path
2237  if(isset($u['query']) && $u['query'] != ''){
2238  $this->path .= '?' . $u['query'];
2239  }
2240 
2241  // set default port
2242  if(!isset($u['port'])){
2243  if($u['scheme'] == 'https'){
2244  $this->port = 443;
2245  } else {
2246  $this->port = 80;
2247  }
2248  }
2249 
2250  $this->uri = $this->path;
2251  $this->digest_uri = $this->uri;
2252 
2253  // build headers
2254  if (!isset($u['port'])) {
2255  $this->setHeader('Host', $this->host);
2256  } else {
2257  $this->setHeader('Host', $this->host.':'.$this->port);
2258  }
2259 
2260  if (isset($u['user']) && $u['user'] != '') {
2261  $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2262  }
2263  }
2264 
2271  function io_method() {
2272  if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
2273  return 'curl';
2274  if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
2275  return 'socket';
2276  return 'unknown';
2277  }
2278 
2287  function connect($connection_timeout=0,$response_timeout=30){
2288  // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2289  // "regular" socket.
2290  // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2291  // loaded), and until PHP5 stream_get_wrappers is not available.
2292 // if ($this->scheme == 'https') {
2293 // if (version_compare(phpversion(), '4.3.0') >= 0) {
2294 // if (extension_loaded('openssl')) {
2295 // $this->scheme = 'ssl';
2296 // $this->debug('Using SSL over OpenSSL');
2297 // }
2298 // }
2299 // }
2300  $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2301  if ($this->io_method() == 'socket') {
2302  if (!is_array($this->proxy)) {
2303  $host = $this->host;
2304  $port = $this->port;
2305  } else {
2306  $host = $this->proxy['host'];
2307  $port = $this->proxy['port'];
2308  }
2309 
2310  // use persistent connection
2311  if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
2312  if (!feof($this->fp)) {
2313  $this->debug('Re-use persistent connection');
2314  return true;
2315  }
2316  fclose($this->fp);
2317  $this->debug('Closed persistent connection at EOF');
2318  }
2319 
2320  // munge host if using OpenSSL
2321  if ($this->scheme == 'ssl') {
2322  $host = 'ssl://' . $host;
2323  }
2324  $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2325 
2326  // open socket
2327  if($connection_timeout > 0){
2328  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2329  } else {
2330  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
2331  }
2332 
2333  // test pointer
2334  if(!$this->fp) {
2335  $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2336  if ($this->errno) {
2337  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2338  } else {
2339  $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2340  }
2341  $this->debug($msg);
2342  $this->setError($msg);
2343  return false;
2344  }
2345 
2346  // set response timeout
2347  $this->debug('set response timeout to ' . $response_timeout);
2348  socket_set_timeout( $this->fp, $response_timeout);
2349 
2350  $this->debug('socket connected');
2351  return true;
2352  } else if ($this->io_method() == 'curl') {
2353  if (!extension_loaded('curl')) {
2354 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2355  $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to included cURL.');
2356  return false;
2357  }
2358  // Avoid warnings when PHP does not have these options
2359  if (defined('CURLOPT_CONNECTIONTIMEOUT'))
2360  $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2361  else
2362  $CURLOPT_CONNECTIONTIMEOUT = 78;
2363  if (defined('CURLOPT_HTTPAUTH'))
2364  $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2365  else
2366  $CURLOPT_HTTPAUTH = 107;
2367  if (defined('CURLOPT_PROXYAUTH'))
2368  $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2369  else
2370  $CURLOPT_PROXYAUTH = 111;
2371  if (defined('CURLAUTH_BASIC'))
2372  $CURLAUTH_BASIC = CURLAUTH_BASIC;
2373  else
2374  $CURLAUTH_BASIC = 1;
2375  if (defined('CURLAUTH_DIGEST'))
2376  $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2377  else
2378  $CURLAUTH_DIGEST = 2;
2379  if (defined('CURLAUTH_NTLM'))
2380  $CURLAUTH_NTLM = CURLAUTH_NTLM;
2381  else
2382  $CURLAUTH_NTLM = 8;
2383 
2384  $this->debug('connect using cURL');
2385  // init CURL
2386  $this->ch = curl_init();
2387  // set url
2388  $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2389  // add path
2390  $hostURL .= $this->path;
2391  $this->setCurlOption(CURLOPT_URL, $hostURL);
2392  // follow location headers (re-directs)
2393  if (ini_get('safe_mode') || ini_get('open_basedir')) {
2394  $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2395  $this->debug('safe_mode = ');
2396  $this->appendDebug($this->varDump(ini_get('safe_mode')));
2397  $this->debug('open_basedir = ');
2398  $this->appendDebug($this->varDump(ini_get('open_basedir')));
2399  } else {
2400  $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2401  }
2402  // ask for headers in the response output
2403  $this->setCurlOption(CURLOPT_HEADER, 1);
2404  // ask for the response output as the return value
2405  $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2406  // encode
2407  // We manage this ourselves through headers and encoding
2408 // if(function_exists('gzuncompress')){
2409 // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2410 // }
2411  // persistent connection
2412  if ($this->persistentConnection) {
2413  // I believe the following comment is now bogus, having applied to
2414  // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2415  // The way we send data, we cannot use persistent connections, since
2416  // there will be some "junk" at the end of our request.
2417  //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2418  $this->persistentConnection = false;
2419  $this->setHeader('Connection', 'close');
2420  }
2421  // set timeouts
2422  if ($connection_timeout != 0) {
2423  $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2424  }
2425  if ($response_timeout != 0) {
2426  $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2427  }
2428 
2429  if ($this->scheme == 'https') {
2430  $this->debug('set cURL SSL verify options');
2431  // recent versions of cURL turn on peer/host checking by default,
2432  // while PHP binaries are not compiled with a default location for the
2433  // CA cert bundle, so disable peer/host checking.
2434  //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2435  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2436  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2437 
2438  // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2439  if ($this->authtype == 'certificate') {
2440  $this->debug('set cURL certificate options');
2441  if (isset($this->certRequest['cainfofile'])) {
2442  $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2443  }
2444  if (isset($this->certRequest['verifypeer'])) {
2445  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2446  } else {
2447  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2448  }
2449  if (isset($this->certRequest['verifyhost'])) {
2450  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2451  } else {
2452  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2453  }
2454  if (isset($this->certRequest['sslcertfile'])) {
2455  $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2456  }
2457  if (isset($this->certRequest['sslkeyfile'])) {
2458  $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2459  }
2460  if (isset($this->certRequest['passphrase'])) {
2461  $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2462  }
2463  if (isset($this->certRequest['certpassword'])) {
2464  $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2465  }
2466  }
2467  }
2468  if ($this->authtype && ($this->authtype != 'certificate')) {
2469  if ($this->username) {
2470  $this->debug('set cURL username/password');
2471  $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2472  }
2473  if ($this->authtype == 'basic') {
2474  $this->debug('set cURL for Basic authentication');
2475  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2476  }
2477  if ($this->authtype == 'digest') {
2478  $this->debug('set cURL for digest authentication');
2479  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2480  }
2481  if ($this->authtype == 'ntlm') {
2482  $this->debug('set cURL for NTLM authentication');
2483  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2484  }
2485  }
2486  if (is_array($this->proxy)) {
2487  $this->debug('set cURL proxy options');
2488  if ($this->proxy['port'] != '') {
2489  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
2490  } else {
2491  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2492  }
2493  if ($this->proxy['username'] || $this->proxy['password']) {
2494  $this->debug('set cURL proxy authentication options');
2495  $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
2496  if ($this->proxy['authtype'] == 'basic') {
2497  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2498  }
2499  if ($this->proxy['authtype'] == 'ntlm') {
2500  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2501  }
2502  }
2503  }
2504  $this->debug('cURL connection set up');
2505  return true;
2506  } else {
2507  $this->setError('Unknown scheme ' . $this->scheme);
2508  $this->debug('Unknown scheme ' . $this->scheme);
2509  return false;
2510  }
2511  }
2512 
2523  function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
2524 
2525  $this->debug('entered send() with data of length: '.strlen($data));
2526 
2527  $this->tryagain = true;
2528  $tries = 0;
2529  while ($this->tryagain) {
2530  $this->tryagain = false;
2531  if ($tries++ < 2) {
2532  // make connnection
2533  if (!$this->connect($timeout, $response_timeout)){
2534  return false;
2535  }
2536 
2537  // send request
2538  if (!$this->sendRequest($data, $cookies)){
2539  return false;
2540  }
2541 
2542  // get response
2543  $respdata = $this->getResponse();
2544  } else {
2545  $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2546  }
2547  }
2548  $this->debug('end of send()');
2549  return $respdata;
2550  }
2551 
2552 
2564  function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
2565  return $this->send($data, $timeout, $response_timeout, $cookies);
2566  }
2567 
2578  function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
2579  $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2580  $this->appendDebug($this->varDump($digestRequest));
2581  $this->debug("certRequest=");
2582  $this->appendDebug($this->varDump($certRequest));
2583  // cf. RFC 2617
2584  if ($authtype == 'basic') {
2585  $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
2586  } elseif ($authtype == 'digest') {
2587  if (isset($digestRequest['nonce'])) {
2588  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2589 
2590  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2591 
2592  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2593  $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2594 
2595  // H(A1) = MD5(A1)
2596  $HA1 = md5($A1);
2597 
2598  // A2 = Method ":" digest-uri-value
2599  $A2 = $this->request_method . ':' . $this->digest_uri;
2600 
2601  // H(A2)
2602  $HA2 = md5($A2);
2603 
2604  // KD(secret, data) = H(concat(secret, ":", data))
2605  // if qop == auth:
2606  // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2607  // ":" nc-value
2608  // ":" unq(cnonce-value)
2609  // ":" unq(qop-value)
2610  // ":" H(A2)
2611  // ) <">
2612  // if qop is missing,
2613  // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2614 
2615  $unhashedDigest = '';
2616  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2617  $cnonce = $nonce;
2618  if ($digestRequest['qop'] != '') {
2619  $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2620  } else {
2621  $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2622  }
2623 
2624  $hashedDigest = md5($unhashedDigest);
2625 
2626  $opaque = '';
2627  if (isset($digestRequest['opaque'])) {
2628  $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2629  }
2630 
2631  $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 . '"');
2632  }
2633  } elseif ($authtype == 'certificate') {
2634  $this->certRequest = $certRequest;
2635  $this->debug('Authorization header not set for certificate');
2636  } elseif ($authtype == 'ntlm') {
2637  // do nothing
2638  $this->debug('Authorization header not set for ntlm');
2639  }
2640  $this->username = $username;
2641  $this->password = $password;
2642  $this->authtype = $authtype;
2643  $this->digestRequest = $digestRequest;
2644  }
2645 
2652  function setSOAPAction($soapaction) {
2653  $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2654  }
2655 
2662  function setEncoding($enc='gzip, deflate') {
2663  if (function_exists('gzdeflate')) {
2664  $this->protocol_version = '1.1';
2665  $this->setHeader('Accept-Encoding', $enc);
2666  if (!isset($this->outgoing_headers['Connection'])) {
2667  $this->setHeader('Connection', 'close');
2668  $this->persistentConnection = false;
2669  }
2670  set_magic_quotes_runtime(0);
2671  // deprecated
2672  $this->encoding = $enc;
2673  }
2674  }
2675 
2686  function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
2687  if ($proxyhost) {
2688  $this->proxy = array(
2689  'host' => $proxyhost,
2690  'port' => $proxyport,
2691  'username' => $proxyusername,
2692  'password' => $proxypassword,
2693  'authtype' => $proxyauthtype
2694  );
2695  if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2696  $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
2697  }
2698  } else {
2699  $this->debug('remove proxy');
2700  $proxy = null;
2701  unsetHeader('Proxy-Authorization');
2702  }
2703  }
2704 
2705 
2715  $skipHeaders = array( 'HTTP/1.1 100',
2716  'HTTP/1.0 301',
2717  'HTTP/1.1 301',
2718  'HTTP/1.0 302',
2719  'HTTP/1.1 302',
2720  'HTTP/1.0 401',
2721  'HTTP/1.1 401',
2722  'HTTP/1.0 200 Connection established');
2723  foreach ($skipHeaders as $hd) {
2724  $prefix = substr($data, 0, strlen($hd));
2725  if ($prefix == $hd) return true;
2726  }
2727 
2728  return false;
2729  }
2730 
2741  function decodeChunked($buffer, $lb){
2742  // length := 0
2743  $length = 0;
2744  $new = '';
2745 
2746  // read chunk-size, chunk-extension (if any) and CRLF
2747  // get the position of the linebreak
2748  $chunkend = strpos($buffer, $lb);
2749  if ($chunkend == FALSE) {
2750  $this->debug('no linebreak found in decodeChunked');
2751  return $new;
2752  }
2753  $temp = substr($buffer,0,$chunkend);
2754  $chunk_size = hexdec( trim($temp) );
2755  $chunkstart = $chunkend + strlen($lb);
2756  // while (chunk-size > 0) {
2757  while ($chunk_size > 0) {
2758  $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2759  $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2760 
2761  // Just in case we got a broken connection
2762  if ($chunkend == FALSE) {
2763  $chunk = substr($buffer,$chunkstart);
2764  // append chunk-data to entity-body
2765  $new .= $chunk;
2766  $length += strlen($chunk);
2767  break;
2768  }
2769 
2770  // read chunk-data and CRLF
2771  $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2772  // append chunk-data to entity-body
2773  $new .= $chunk;
2774  // length := length + chunk-size
2775  $length += strlen($chunk);
2776  // read chunk-size and CRLF
2777  $chunkstart = $chunkend + strlen($lb);
2778 
2779  $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2780  if ($chunkend == FALSE) {
2781  break; //Just in case we got a broken connection
2782  }
2783  $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2784  $chunk_size = hexdec( trim($temp) );
2785  $chunkstart = $chunkend;
2786  }
2787  return $new;
2788  }
2789 
2798  function buildPayload($data, $cookie_str = '') {
2799  // Note: for cURL connections, $this->outgoing_payload is ignored,
2800  // as is the Content-Length header, but these are still created as
2801  // debugging guides.
2802 
2803  // add content-length header
2804  $this->setHeader('Content-Length', strlen($data));
2805 
2806  // start building outgoing payload:
2807  if ($this->proxy) {
2808  $uri = $this->url;
2809  } else {
2810  $uri = $this->uri;
2811  }
2812  $req = "$this->request_method $uri HTTP/$this->protocol_version";
2813  $this->debug("HTTP request: $req");
2814  $this->outgoing_payload = "$req\r\n";
2815 
2816  // loop thru headers, serializing
2817  foreach($this->outgoing_headers as $k => $v){
2818  $hdr = $k.': '.$v;
2819  $this->debug("HTTP header: $hdr");
2820  $this->outgoing_payload .= "$hdr\r\n";
2821  }
2822 
2823  // add any cookies
2824  if ($cookie_str != '') {
2825  $hdr = 'Cookie: '.$cookie_str;
2826  $this->debug("HTTP header: $hdr");
2827  $this->outgoing_payload .= "$hdr\r\n";
2828  }
2829 
2830  // header/body separator
2831  $this->outgoing_payload .= "\r\n";
2832 
2833  // add data
2834  $this->outgoing_payload .= $data;
2835  }
2836 
2845  function sendRequest($data, $cookies = NULL) {
2846  // build cookie string
2847  $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2848 
2849  // build payload
2850  $this->buildPayload($data, $cookie_str);
2851 
2852  if ($this->io_method() == 'socket') {
2853  // send payload
2854  if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2855  $this->setError('couldn\'t write message data to socket');
2856  $this->debug('couldn\'t write message data to socket');
2857  return false;
2858  }
2859  $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2860  return true;
2861  } else if ($this->io_method() == 'curl') {
2862  // set payload
2863  // cURL does say this should only be the verb, and in fact it
2864  // turns out that the URI and HTTP version are appended to this, which
2865  // some servers refuse to work with (so we no longer use this method!)
2866  //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2867  $curl_headers = array();
2868  foreach($this->outgoing_headers as $k => $v){
2869  if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2870  $this->debug("Skip cURL header $k: $v");
2871  } else {
2872  $curl_headers[] = "$k: $v";
2873  }
2874  }
2875  if ($cookie_str != '') {
2876  $curl_headers[] = 'Cookie: ' . $cookie_str;
2877  }
2878  $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
2879  $this->debug('set cURL HTTP headers');
2880  if ($this->request_method == "POST") {
2881  $this->setCurlOption(CURLOPT_POST, 1);
2882  $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
2883  $this->debug('set cURL POST data');
2884  } else {
2885  }
2886  // insert custom user-set cURL options
2887  foreach ($this->ch_options as $key => $val) {
2888  $this->setCurlOption($key, $val);
2889  }
2890 
2891  $this->debug('set cURL payload');
2892  return true;
2893  }
2894  }
2895 
2902  function getResponse(){
2903  $this->incoming_payload = '';
2904 
2905  if ($this->io_method() == 'socket') {
2906  // loop until headers have been retrieved
2907  $data = '';
2908  while (!isset($lb)){
2909 
2910  // We might EOF during header read.
2911  if(feof($this->fp)) {
2912  $this->incoming_payload = $data;
2913  $this->debug('found no headers before EOF after length ' . strlen($data));
2914  $this->debug("received before EOF:\n" . $data);
2915  $this->setError('server failed to send headers');
2916  return false;
2917  }
2918 
2919  $tmp = fgets($this->fp, 256);
2920  $tmplen = strlen($tmp);
2921  $this->debug("read line of $tmplen bytes: " . trim($tmp));
2922 
2923  if ($tmplen == 0) {
2924  $this->incoming_payload = $data;
2925  $this->debug('socket read of headers timed out after length ' . strlen($data));
2926  $this->debug("read before timeout: " . $data);
2927  $this->setError('socket read of headers timed out');
2928  return false;
2929  }
2930 
2931  $data .= $tmp;
2932  $pos = strpos($data,"\r\n\r\n");
2933  if($pos > 1){
2934  $lb = "\r\n";
2935  } else {
2936  $pos = strpos($data,"\n\n");
2937  if($pos > 1){
2938  $lb = "\n";
2939  }
2940  }
2941  // remove 100 headers
2942  if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) {
2943  unset($lb);
2944  $data = '';
2945  }//
2946  }
2947  // store header data
2948  $this->incoming_payload .= $data;
2949  $this->debug('found end of headers after length ' . strlen($data));
2950  // process headers
2951  $header_data = trim(substr($data,0,$pos));
2952  $header_array = explode($lb,$header_data);
2953  $this->incoming_headers = array();
2954  $this->incoming_cookies = array();
2955  foreach($header_array as $header_line){
2956  $arr = explode(':',$header_line, 2);
2957  if(count($arr) > 1){
2958  $header_name = strtolower(trim($arr[0]));
2959  $this->incoming_headers[$header_name] = trim($arr[1]);
2960  if ($header_name == 'set-cookie') {
2961  // TODO: allow multiple cookies from parseCookie
2962  $cookie = $this->parseCookie(trim($arr[1]));
2963  if ($cookie) {
2964  $this->incoming_cookies[] = $cookie;
2965  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2966  } else {
2967  $this->debug('did not find cookie in ' . trim($arr[1]));
2968  }
2969  }
2970  } else if (isset($header_name)) {
2971  // append continuation line to previous header
2972  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2973  }
2974  }
2975 
2976  // loop until msg has been received
2977  if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2978  $content_length = 2147483647; // ignore any content-length header
2979  $chunked = true;
2980  $this->debug("want to read chunked content");
2981  } elseif (isset($this->incoming_headers['content-length'])) {
2982  $content_length = $this->incoming_headers['content-length'];
2983  $chunked = false;
2984  $this->debug("want to read content of length $content_length");
2985  } else {
2986  $content_length = 2147483647;
2987  $chunked = false;
2988  $this->debug("want to read content to EOF");
2989  }
2990  $data = '';
2991  do {
2992  if ($chunked) {
2993  $tmp = fgets($this->fp, 256);
2994  $tmplen = strlen($tmp);
2995  $this->debug("read chunk line of $tmplen bytes");
2996  if ($tmplen == 0) {
2997  $this->incoming_payload = $data;
2998  $this->debug('socket read of chunk length timed out after length ' . strlen($data));
2999  $this->debug("read before timeout:\n" . $data);
3000  $this->setError('socket read of chunk length timed out');
3001  return false;
3002  }
3003  $content_length = hexdec(trim($tmp));
3004  $this->debug("chunk length $content_length");
3005  }
3006  $strlen = 0;
3007  while (($strlen < $content_length) && (!feof($this->fp))) {
3008  $readlen = min(8192, $content_length - $strlen);
3009  $tmp = fread($this->fp, $readlen);
3010  $tmplen = strlen($tmp);
3011  $this->debug("read buffer of $tmplen bytes");
3012  if (($tmplen == 0) && (!feof($this->fp))) {
3013  $this->incoming_payload = $data;
3014  $this->debug('socket read of body timed out after length ' . strlen($data));
3015  $this->debug("read before timeout:\n" . $data);
3016  $this->setError('socket read of body timed out');
3017  return false;
3018  }
3019  $strlen += $tmplen;
3020  $data .= $tmp;
3021  }
3022  if ($chunked && ($content_length > 0)) {
3023  $tmp = fgets($this->fp, 256);
3024  $tmplen = strlen($tmp);
3025  $this->debug("read chunk terminator of $tmplen bytes");
3026  if ($tmplen == 0) {
3027  $this->incoming_payload = $data;
3028  $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3029  $this->debug("read before timeout:\n" . $data);
3030  $this->setError('socket read of chunk terminator timed out');
3031  return false;
3032  }
3033  }
3034  } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3035  if (feof($this->fp)) {
3036  $this->debug('read to EOF');
3037  }
3038  $this->debug('read body of length ' . strlen($data));
3039  $this->incoming_payload .= $data;
3040  $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
3041 
3042  // close filepointer
3043  if(
3044  (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
3045  (! $this->persistentConnection) || feof($this->fp)){
3046  fclose($this->fp);
3047  $this->fp = false;
3048  $this->debug('closed socket');
3049  }
3050 
3051  // connection was closed unexpectedly
3052  if($this->incoming_payload == ''){
3053  $this->setError('no response from server');
3054  return false;
3055  }
3056 
3057  // decode transfer-encoding
3058 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3059 // if(!$data = $this->decodeChunked($data, $lb)){
3060 // $this->setError('Decoding of chunked data failed');
3061 // return false;
3062 // }
3063  //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3064  // set decoded payload
3065 // $this->incoming_payload = $header_data.$lb.$lb.$data;
3066 // }
3067 
3068  } else if ($this->io_method() == 'curl') {
3069  // send and receive
3070  $this->debug('send and receive with cURL');
3071  $this->incoming_payload = curl_exec($this->ch);
3073 
3074  $cErr = curl_error($this->ch);
3075  if ($cErr != '') {
3076  $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
3077  // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3078  foreach(curl_getinfo($this->ch) as $k => $v){
3079  $err .= "$k: $v<br>";
3080  }
3081  $this->debug($err);
3082  $this->setError($err);
3083  curl_close($this->ch);
3084  return false;
3085  } else {
3086  //echo '<pre>';
3087  //var_dump(curl_getinfo($this->ch));
3088  //echo '</pre>';
3089  }
3090  // close curl
3091  $this->debug('No cURL error, closing cURL');
3092  curl_close($this->ch);
3093 
3094  // try removing skippable headers
3095  $savedata = $data;
3096  while ($this->isSkippableCurlHeader($data)) {
3097  $this->debug("Found HTTP header to skip");
3098  if ($pos = strpos($data,"\r\n\r\n")) {
3099  $data = ltrim(substr($data,$pos));
3100  } elseif($pos = strpos($data,"\n\n") ) {
3101  $data = ltrim(substr($data,$pos));
3102  }
3103  }
3104 
3105  if ($data == '') {
3106  // have nothing left; just remove 100 header(s)
3107  $data = $savedata;
3108  while (preg_match('/^HTTP\/1.1 100/',$data)) {
3109  if ($pos = strpos($data,"\r\n\r\n")) {
3110  $data = ltrim(substr($data,$pos));
3111  } elseif($pos = strpos($data,"\n\n") ) {
3112  $data = ltrim(substr($data,$pos));
3113  }
3114  }
3115  }
3116 
3117  // separate content from HTTP headers
3118  if ($pos = strpos($data,"\r\n\r\n")) {
3119  $lb = "\r\n";
3120  } elseif( $pos = strpos($data,"\n\n")) {
3121  $lb = "\n";
3122  } else {
3123  $this->debug('no proper separation of headers and document');
3124  $this->setError('no proper separation of headers and document');
3125  return false;
3126  }
3127  $header_data = trim(substr($data,0,$pos));
3128  $header_array = explode($lb,$header_data);
3129  $data = ltrim(substr($data,$pos));
3130  $this->debug('found proper separation of headers and document');
3131  $this->debug('cleaned data, stringlen: '.strlen($data));
3132  // clean headers
3133  foreach ($header_array as $header_line) {
3134  $arr = explode(':',$header_line,2);
3135  if(count($arr) > 1){
3136  $header_name = strtolower(trim($arr[0]));
3137  $this->incoming_headers[$header_name] = trim($arr[1]);
3138  if ($header_name == 'set-cookie') {
3139  // TODO: allow multiple cookies from parseCookie
3140  $cookie = $this->parseCookie(trim($arr[1]));
3141  if ($cookie) {
3142  $this->incoming_cookies[] = $cookie;
3143  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3144  } else {
3145  $this->debug('did not find cookie in ' . trim($arr[1]));
3146  }
3147  }
3148  } else if (isset($header_name)) {
3149  // append continuation line to previous header
3150  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3151  }
3152  }
3153  }
3154 
3155  $this->response_status_line = $header_array[0];
3156  $arr = explode(' ', $this->response_status_line, 3);
3157  $http_version = $arr[0];
3158  $http_status = intval($arr[1]);
3159  $http_reason = count($arr) > 2 ? $arr[2] : '';
3160 
3161  // see if we need to resend the request with http digest authentication
3162  if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3163  $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3164  $this->setURL($this->incoming_headers['location']);
3165  $this->tryagain = true;
3166  return false;
3167  }
3168 
3169  // see if we need to resend the request with http digest authentication
3170  if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3171  $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3172  if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3173  $this->debug('Server wants digest authentication');
3174  // remove "Digest " from our elements
3175  $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3176 
3177  // parse elements into array
3178  $digestElements = explode(',', $digestString);
3179  foreach ($digestElements as $val) {
3180  $tempElement = explode('=', trim($val), 2);
3181  $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3182  }
3183 
3184  // should have (at least) qop, realm, nonce
3185  if (isset($digestRequest['nonce'])) {
3186  $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3187  $this->tryagain = true;
3188  return false;
3189  }
3190  }
3191  $this->debug('HTTP authentication failed');
3192  $this->setError('HTTP authentication failed');
3193  return false;
3194  }
3195 
3196  if (
3197  ($http_status >= 300 && $http_status <= 307) ||
3198  ($http_status >= 400 && $http_status <= 417) ||
3199  ($http_status >= 501 && $http_status <= 505)
3200  ) {
3201  $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3202  return false;
3203  }
3204 
3205  // decode content-encoding
3206  if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
3207  if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
3208  // if decoding works, use it. else assume data wasn't gzencoded
3209  if(function_exists('gzinflate')){
3210  //$timer->setMarker('starting decoding of gzip/deflated content');
3211  // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3212  // this means there are no Zlib headers, although there should be
3213  $this->debug('The gzinflate function exists');
3214  $datalen = strlen($data);
3215  if ($this->incoming_headers['content-encoding'] == 'deflate') {
3216  if ($degzdata = @gzinflate($data)) {
3217  $data = $degzdata;
3218  $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3219  if (strlen($data) < $datalen) {
3220  // test for the case that the payload has been compressed twice
3221  $this->debug('The inflated payload is smaller than the gzipped one; try again');
3222  if ($degzdata = @gzinflate($data)) {
3223  $data = $degzdata;
3224  $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3225  }
3226  }
3227  } else {
3228  $this->debug('Error using gzinflate to inflate the payload');
3229  $this->setError('Error using gzinflate to inflate the payload');
3230  }
3231  } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3232  if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3233  $data = $degzdata;
3234  $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3235  if (strlen($data) < $datalen) {
3236  // test for the case that the payload has been compressed twice
3237  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3238  if ($degzdata = @gzinflate(substr($data, 10))) {
3239  $data = $degzdata;
3240  $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3241  }
3242  }
3243  } else {
3244  $this->debug('Error using gzinflate to un-gzip the payload');
3245  $this->setError('Error using gzinflate to un-gzip the payload');
3246  }
3247  }
3248  //$timer->setMarker('finished decoding of gzip/deflated content');
3249  //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3250  // set decoded payload
3251  $this->incoming_payload = $header_data.$lb.$lb.$data;
3252  } else {
3253  $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3254  $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3255  }
3256  } else {
3257  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3258  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3259  }
3260  } else {
3261  $this->debug('No Content-Encoding header');
3262  }
3263 
3264  if(strlen($data) == 0){
3265  $this->debug('no data after headers!');
3266  $this->setError('no data present after HTTP headers');
3267  return false;
3268  }
3269 
3270  return $data;
3271  }
3272 
3280  function setContentType($type, $charset = false) {
3281  $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3282  }
3283 
3291  if (isset($this->outgoing_headers['Accept-Encoding'])) {
3292  return false;
3293  }
3294  $this->protocol_version = '1.1';
3295  $this->persistentConnection = true;
3296  $this->setHeader('Connection', 'Keep-Alive');
3297  return true;
3298  }
3299 
3307  /*
3308  * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3309  */
3310  function parseCookie($cookie_str) {
3311  $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3312  $data = split(';', $cookie_str);
3313  $value_str = $data[0];
3314 
3315  $cookie_param = 'domain=';
3316  $start = strpos($cookie_str, $cookie_param);
3317  if ($start > 0) {
3318  $domain = substr($cookie_str, $start + strlen($cookie_param));
3319  $domain = substr($domain, 0, strpos($domain, ';'));
3320  } else {
3321  $domain = '';
3322  }
3323 
3324  $cookie_param = 'expires=';
3325  $start = strpos($cookie_str, $cookie_param);
3326  if ($start > 0) {
3327  $expires = substr($cookie_str, $start + strlen($cookie_param));
3328  $expires = substr($expires, 0, strpos($expires, ';'));
3329  } else {
3330  $expires = '';
3331  }
3332 
3333  $cookie_param = 'path=';
3334  $start = strpos($cookie_str, $cookie_param);
3335  if ( $start > 0 ) {
3336  $path = substr($cookie_str, $start + strlen($cookie_param));
3337  $path = substr($path, 0, strpos($path, ';'));
3338  } else {
3339  $path = '/';
3340  }
3341 
3342  $cookie_param = ';secure;';
3343  if (strpos($cookie_str, $cookie_param) !== FALSE) {
3344  $secure = true;
3345  } else {
3346  $secure = false;
3347  }
3348 
3349  $sep_pos = strpos($value_str, '=');
3350 
3351  if ($sep_pos) {
3352  $name = substr($value_str, 0, $sep_pos);
3353  $value = substr($value_str, $sep_pos + 1);
3354  $cookie= array( 'name' => $name,
3355  'value' => $value,
3356  'domain' => $domain,
3357  'path' => $path,
3358  'expires' => $expires,
3359  'secure' => $secure
3360  );
3361  return $cookie;
3362  }
3363  return false;
3364  }
3365 
3374  function getCookiesForRequest($cookies, $secure=false) {
3375  $cookie_str = '';
3376  if ((! is_null($cookies)) && (is_array($cookies))) {
3377  foreach ($cookies as $cookie) {
3378  if (! is_array($cookie)) {
3379  continue;
3380  }
3381  $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
3382  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3383  if (strtotime($cookie['expires']) <= time()) {
3384  $this->debug('cookie has expired');
3385  continue;
3386  }
3387  }
3388  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3389  $domain = preg_quote($cookie['domain']);
3390  if (! preg_match("'.*$domain$'i", $this->host)) {
3391  $this->debug('cookie has different domain');
3392  continue;
3393  }
3394  }
3395  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3396  $path = preg_quote($cookie['path']);
3397  if (! preg_match("'^$path.*'i", $this->path)) {
3398  $this->debug('cookie is for a different path');
3399  continue;
3400  }
3401  }
3402  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3403  $this->debug('cookie is secure, transport is not');
3404  continue;
3405  }
3406  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3407  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3408  }
3409  }
3410  return $cookie_str;
3411  }
3412 }
3413 
3414 ?><?php
3415 
3416 
3417 
3434  var $headers = array();
3440  var $request = '';
3452  var $requestHeader = NULL;
3458  var $document = '';
3464  var $requestSOAP = '';
3470  var $methodURI = '';
3476  var $methodname = '';
3482  var $methodparams = array();
3488  var $SOAPAction = '';
3494  var $xml_encoding = '';
3500  var $decode_utf8 = true;
3501 
3507  var $outgoing_headers = array();
3513  var $response = '';
3525  var $responseSOAP = '';
3531  var $methodreturn = false;
3543  var $fault = false;
3549  var $result = 'successful';
3550 
3557  var $operations = array();
3563  var $wsdl = false;
3569  var $externalWSDLURL = false;
3575  var $debug_flag = false;
3576 
3577 
3585  function nusoap_server($wsdl=false){
3587  // turn on debugging?
3588  global $debug;
3589  global $HTTP_SERVER_VARS;
3590 
3591  if (isset($_SERVER)) {
3592  $this->debug("_SERVER is defined:");
3593  $this->appendDebug($this->varDump($_SERVER));
3594  } elseif (isset($HTTP_SERVER_VARS)) {
3595  $this->debug("HTTP_SERVER_VARS is defined:");
3596  $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3597  } else {
3598  $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3599  }
3600 
3601  if (isset($debug)) {
3602  $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3603  $this->debug_flag = $debug;
3604  } elseif (isset($_SERVER['QUERY_STRING'])) {
3605  $qs = explode('&', $_SERVER['QUERY_STRING']);
3606  foreach ($qs as $v) {
3607  if (substr($v, 0, 6) == 'debug=') {
3608  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3609  $this->debug_flag = substr($v, 6);
3610  }
3611  }
3612  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3613  $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3614  foreach ($qs as $v) {
3615  if (substr($v, 0, 6) == 'debug=') {
3616  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3617  $this->debug_flag = substr($v, 6);
3618  }
3619  }
3620  }
3621 
3622  // wsdl
3623  if($wsdl){
3624  $this->debug("In nusoap_server, WSDL is specified");
3625  if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3626  $this->wsdl = $wsdl;
3627  $this->externalWSDLURL = $this->wsdl->wsdl;
3628  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3629  } else {
3630  $this->debug('Create wsdl from ' . $wsdl);
3631  $this->wsdl = new wsdl($wsdl);
3632  $this->externalWSDLURL = $wsdl;
3633  }
3634  $this->appendDebug($this->wsdl->getDebug());
3635  $this->wsdl->clearDebug();
3636  if($err = $this->wsdl->getError()){
3637  die('WSDL ERROR: '.$err);
3638  }
3639  }
3640  }
3641 
3648  function service($data){
3649  global $HTTP_SERVER_VARS;
3650 
3651  if (isset($_SERVER['QUERY_STRING'])) {
3652  $qs = $_SERVER['QUERY_STRING'];
3653  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3654  $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3655  } else {
3656  $qs = '';
3657  }
3658  $this->debug("In service, query string=$qs");
3659 
3660  if (preg_match('/wsdl/', $qs) ){
3661  $this->debug("In service, this is a request for WSDL");
3662  if($this->externalWSDLURL){
3663  if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
3664  header('Location: '.$this->externalWSDLURL);
3665  } else { // assume file
3666  header("Content-Type: text/xml\r\n");
3667  $fp = fopen($this->externalWSDLURL, 'r');
3668  fpassthru($fp);
3669  }
3670  } elseif ($this->wsdl) {
3671  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3672  print $this->wsdl->serialize($this->debug_flag);
3673  if ($this->debug_flag) {
3674  $this->debug('wsdl:');
3675  $this->appendDebug($this->varDump($this->wsdl));
3676  print $this->getDebugAsXMLComment();
3677  }
3678  } else {
3679  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3680  print "This service does not provide WSDL";
3681  }
3682  } elseif ($data == '' && $this->wsdl) {
3683  $this->debug("In service, there is no data, so return Web description");
3684  print $this->wsdl->webDescription();
3685  } else {
3686  $this->debug("In service, invoke the request");
3687  $this->parse_request($data);
3688  if (! $this->fault) {
3689  $this->invoke_method();
3690  }
3691  if (! $this->fault) {
3692  $this->serialize_return();
3693  }
3694  $this->send_response();
3695  }
3696  }
3697 
3710  function parse_http_headers() {
3711  global $HTTP_SERVER_VARS;
3712 
3713  $this->request = '';
3714  $this->SOAPAction = '';
3715  if(function_exists('getallheaders')){
3716  $this->debug("In parse_http_headers, use getallheaders");
3717  $headers = getallheaders();
3718  foreach($headers as $k=>$v){
3719  $k = strtolower($k);
3720  $this->headers[$k] = $v;
3721  $this->request .= "$k: $v\r\n";
3722  $this->debug("$k: $v");
3723  }
3724  // get SOAPAction header
3725  if(isset($this->headers['soapaction'])){
3726  $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
3727  }
3728  // get the character encoding of the incoming request
3729  if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
3730  $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
3731  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
3732  $this->xml_encoding = strtoupper($enc);
3733  } else {
3734  $this->xml_encoding = 'US-ASCII';
3735  }
3736  } else {
3737  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3738  $this->xml_encoding = 'ISO-8859-1';
3739  }
3740  } elseif(isset($_SERVER) && is_array($_SERVER)){
3741  $this->debug("In parse_http_headers, use _SERVER");
3742  foreach ($_SERVER as $k => $v) {
3743  if (substr($k, 0, 5) == 'HTTP_') {
3744  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3745  } else {
3746  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3747  }
3748  if ($k == 'soapaction') {
3749  // get SOAPAction header
3750  $k = 'SOAPAction';
3751  $v = str_replace('"', '', $v);
3752  $v = str_replace('\\', '', $v);
3753  $this->SOAPAction = $v;
3754  } else if ($k == 'content-type') {
3755  // get the character encoding of the incoming request
3756  if (strpos($v, '=')) {
3757  $enc = substr(strstr($v, '='), 1);
3758  $enc = str_replace('"', '', $enc);
3759  $enc = str_replace('\\', '', $enc);
3760  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
3761  $this->xml_encoding = strtoupper($enc);
3762  } else {
3763  $this->xml_encoding = 'US-ASCII';
3764  }
3765  } else {
3766  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3767  $this->xml_encoding = 'ISO-8859-1';
3768  }
3769  }
3770  $this->headers[$k] = $v;
3771  $this->request .= "$k: $v\r\n";
3772  $this->debug("$k: $v");
3773  }
3774  } elseif (is_array($HTTP_SERVER_VARS)) {
3775  $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3776  foreach ($HTTP_SERVER_VARS as $k => $v) {
3777  if (substr($k, 0, 5) == 'HTTP_') {
3778  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5));
3779  } else {
3780  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k);
3781  }
3782  if ($k == 'soapaction') {
3783  // get SOAPAction header
3784  $k = 'SOAPAction';
3785  $v = str_replace('"', '', $v);
3786  $v = str_replace('\\', '', $v);
3787  $this->SOAPAction = $v;
3788  } else if ($k == 'content-type') {
3789  // get the character encoding of the incoming request
3790  if (strpos($v, '=')) {
3791  $enc = substr(strstr($v, '='), 1);
3792  $enc = str_replace('"', '', $enc);
3793  $enc = str_replace('\\', '', $enc);
3794  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
3795  $this->xml_encoding = strtoupper($enc);
3796  } else {
3797  $this->xml_encoding = 'US-ASCII';
3798  }
3799  } else {
3800  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3801  $this->xml_encoding = 'ISO-8859-1';
3802  }
3803  }
3804  $this->headers[$k] = $v;
3805  $this->request .= "$k: $v\r\n";
3806  $this->debug("$k: $v");
3807  }
3808  } else {
3809  $this->debug("In parse_http_headers, HTTP headers not accessible");
3810  $this->setError("HTTP headers not accessible");
3811  }
3812  }
3813 
3836  function parse_request($data='') {
3837  $this->debug('entering parse_request()');
3838  $this->parse_http_headers();
3839  $this->debug('got character encoding: '.$this->xml_encoding);
3840  // uncompress if necessary
3841  if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3842  $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3843  if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3844  // if decoding works, use it. else assume data wasn't gzencoded
3845  if (function_exists('gzuncompress')) {
3846  if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3847  $data = $degzdata;
3848  } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3849  $data = $degzdata;
3850  } else {
3851  $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3852  return;
3853  }
3854  } else {
3855  $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3856  return;
3857  }
3858  }
3859  }
3860  $this->request .= "\r\n".$data;
3861  $data = $this->parseRequest($this->headers, $data);
3862  $this->requestSOAP = $data;
3863  $this->debug('leaving parse_request');
3864  }
3865 
3883  function invoke_method() {
3884  $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3885 
3886  if ($this->wsdl) {
3887  if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3888  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3889  $this->appendDebug('opData=' . $this->varDump($this->opData));
3890  } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3891  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3892  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3893  $this->appendDebug('opData=' . $this->varDump($this->opData));
3894  $this->methodname = $this->opData['name'];
3895  } else {
3896  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3897  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3898  return;
3899  }
3900  } else {
3901  $this->debug('in invoke_method, no WSDL to validate method');
3902  }
3903 
3904  // if a . is present in $this->methodname, we see if there is a class in scope,
3905  // which could be referred to. We will also distinguish between two deliminators,
3906  // to allow methods to be called a the class or an instance
3907  $class = '';
3908  $method = '';
3909  if (strpos($this->methodname, '..') > 0) {
3910  $delim = '..';
3911  } else if (strpos($this->methodname, '.') > 0) {
3912  $delim = '.';
3913  } else {
3914  $delim = '';
3915  }
3916 
3917  if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3918  class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3919  // get the class and method name
3920  $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3921  $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3922  $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3923  }
3924  // set class handler
3925  // added to support single operations
3926  if ($class == '' && $this->class !='')
3927  {
3928  $class = $this->class;
3929  $delim = "..";
3930  $method = $this->methodname;
3931  }
3932 
3933  // does method exist?
3934  if ($class == '') {
3935  if (!function_exists($this->methodname)) {
3936  $this->debug("in invoke_method, function '$this->methodname' not found!");
3937  $this->result = 'fault: method not found';
3938  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3939  return;
3940  }
3941  } else {
3942  $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
3943  if (!in_array($method_to_compare, get_class_methods($class))) {
3944  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
3945  $this->result = 'fault: method not found';
3946  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3947  return;
3948  }
3949  }
3950 
3951  // evaluate message, getting back parameters
3952  // verify that request parameters match the method's signature
3953  if(! $this->verify_method($this->methodname,$this->methodparams)){
3954  // debug
3955  $this->debug('ERROR: request not verified against method signature');
3956  $this->result = 'fault: request failed validation against method signature';
3957  // return fault
3958  $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
3959  return;
3960  }
3961 
3962  // if there are parameters to pass
3963  $this->debug('in invoke_method, params:');
3964  $this->appendDebug($this->varDump($this->methodparams));
3965  $this->debug("in invoke_method, calling '$this->methodname'");
3966  if (!function_exists('call_user_func_array')) {
3967  if ($class == '') {
3968  $this->debug('in invoke_method, calling function using eval()');
3969  $funcCall = "\$this->methodreturn = $this->methodname(";
3970  } else {
3971  if ($delim == '..') {
3972  $this->debug('in invoke_method, calling class method using eval()');
3973  $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
3974  } else {
3975  $this->debug('in invoke_method, calling instance method using eval()');
3976  // generate unique instance name
3977  $instname = "\$inst_".time();
3978  $funcCall = $instname." = new ".$class."(); ";
3979  $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
3980  }
3981  }
3982  if ($this->methodparams) {
3983  foreach ($this->methodparams as $param) {
3984  if (is_array($param) || is_object($param)) {
3985  $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
3986  return;
3987  }
3988  $funcCall .= "\"$param\",";
3989  }
3990  $funcCall = substr($funcCall, 0, -1);
3991  }
3992  $funcCall .= ');';
3993  $this->debug('in invoke_method, function call: '.$funcCall);
3994  @eval($funcCall);
3995  } else {
3996  if ($class == '') {
3997  $this->debug('in invoke_method, calling function using call_user_func_array()');
3998  $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
3999  } elseif ($delim == '..') {
4000  $this->debug('in invoke_method, calling class method using call_user_func_array()');
4001  $call_arg = array ($class, $method);
4002  } else {
4003  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4004  $instance = new $class ();
4005  $call_arg = array(&$instance, $method);
4006  }
4007  if (is_array($this->methodparams)) {
4008  $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4009  } else {
4010  $this->methodreturn = call_user_func_array($call_arg, array());
4011  }
4012  }
4013  $this->debug('in invoke_method, methodreturn:');
4014  $this->appendDebug($this->varDump($this->methodreturn));
4015  $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
4016  }
4017 
4029  function serialize_return() {
4030  $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4031  // if fault
4032  if (isset($this->methodreturn) && ((get_class((object)$this->methodreturn) == 'soap_fault') || (get_class((object)$this->methodreturn) == 'nusoap_fault'))) {
4033  $this->debug('got a fault object from method');
4034  $this->fault = $this->methodreturn;
4035  return;
4036  } elseif ($this->methodreturnisliteralxml) {
4037  $return_val = $this->methodreturn;
4038  // returned value(s)
4039  } else {
4040  $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
4041  $this->debug('serializing return value');
4042  if($this->wsdl){
4043  if (sizeof($this->opData['output']['parts']) > 1) {
4044  $this->debug('more than one output part, so use the method return unchanged');
4045  $opParams = $this->methodreturn;
4046  } elseif (sizeof($this->opData['output']['parts']) == 1) {
4047  $this->debug('exactly one output part, so wrap the method return in a simple array');
4048  // TODO: verify that it is not already wrapped!
4049  //foreach ($this->opData['output']['parts'] as $name => $type) {
4050  // $this->debug('wrap in element named ' . $name);
4051  //}
4052  $opParams = array($this->methodreturn);
4053  }
4054  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
4055  $this->appendDebug($this->wsdl->getDebug());
4056  $this->wsdl->clearDebug();
4057  if($errstr = $this->wsdl->getError()){
4058  $this->debug('got wsdl error: '.$errstr);
4059  $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4060  return;
4061  }
4062  } else {
4063  if (isset($this->methodreturn)) {
4064  $return_val = $this->serialize_val($this->methodreturn, 'return');
4065  } else {
4066  $return_val = '';
4067  $this->debug('in absence of WSDL, assume void return for backward compatibility');
4068  }
4069  }
4070  }
4071  $this->debug('return value:');
4072  $this->appendDebug($this->varDump($return_val));
4073 
4074  $this->debug('serializing response');
4075  if ($this->wsdl) {
4076  $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4077  if ($this->opData['style'] == 'rpc') {
4078  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4079  if ($this->opData['output']['use'] == 'literal') {
4080  // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
4081  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4082  } else {
4083  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4084  }
4085  } else {
4086  $this->debug('style is not rpc for serialization: assume document');
4087  $payload = $return_val;
4088  }
4089  } else {
4090  $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4091  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4092  }
4093  $this->result = 'successful';
4094  if($this->wsdl){
4095  //if($this->debug_flag){
4096  $this->appendDebug($this->wsdl->getDebug());
4097  // }
4098  if (isset($opData['output']['encodingStyle'])) {
4099  $encodingStyle = $opData['output']['encodingStyle'];
4100  } else {
4101  $encodingStyle = '';
4102  }
4103  // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4104  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
4105  } else {
4106  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
4107  }
4108  $this->debug("Leaving serialize_return");
4109  }
4110 
4121  function send_response() {
4122  $this->debug('Enter send_response');
4123  if ($this->fault) {
4124  $payload = $this->fault->serialize();
4125  $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4126  $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4127  } else {
4128  $payload = $this->responseSOAP;
4129  // Some combinations of PHP+Web server allow the Status
4130  // to come through as a header. Since OK is the default
4131  // just do nothing.
4132  // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4133  // $this->outgoing_headers[] = "Status: 200 OK";
4134  }
4135  // add debug data if in debug mode
4136  if(isset($this->debug_flag) && $this->debug_flag){
4137  $payload .= $this->getDebugAsXMLComment();
4138  }
4139  $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4140  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4141  $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
4142  // Let the Web server decide about this
4143  //$this->outgoing_headers[] = "Connection: Close\r\n";
4144  $payload = $this->getHTTPBody($payload);
4145  $type = $this->getHTTPContentType();
4146  $charset = $this->getHTTPContentTypeCharset();
4147  $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4148  //begin code to compress payload - by John
4149  // NOTE: there is no way to know whether the Web server will also compress
4150  // this data.
4151  if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4152  if (strstr($this->headers['accept-encoding'], 'gzip')) {
4153  if (function_exists('gzencode')) {
4154  if (isset($this->debug_flag) && $this->debug_flag) {
4155  $payload .= "<!-- Content being gzipped -->";
4156  }
4157  $this->outgoing_headers[] = "Content-Encoding: gzip";
4158  $payload = gzencode($payload);
4159  } else {
4160  if (isset($this->debug_flag) && $this->debug_flag) {
4161  $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4162  }
4163  }
4164  } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4165  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4166  // instead of gzcompress output,
4167  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4168  if (function_exists('gzdeflate')) {
4169  if (isset($this->debug_flag) && $this->debug_flag) {
4170  $payload .= "<!-- Content being deflated -->";
4171  }
4172  $this->outgoing_headers[] = "Content-Encoding: deflate";
4173  $payload = gzdeflate($payload);
4174  } else {
4175  if (isset($this->debug_flag) && $this->debug_flag) {
4176  $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4177  }
4178  }
4179  }
4180  }
4181  //end code
4182  $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
4183  reset($this->outgoing_headers);
4184  foreach($this->outgoing_headers as $hdr){
4185  header($hdr, false);
4186  }
4187  print $payload;
4188  $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
4189  }
4190 
4200  function verify_method($operation,$request){
4201  if(isset($this->wsdl) && is_object($this->wsdl)){
4202  if($this->wsdl->getOperationData($operation)){
4203  return true;
4204  }
4205  } elseif(isset($this->operations[$operation])){
4206  return true;
4207  }
4208  return false;
4209  }
4210 
4220  $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
4221  if (!strstr($headers['content-type'], 'text/xml')) {
4222  $this->setError('Request not of type text/xml');
4223  return false;
4224  }
4225  if (strpos($headers['content-type'], '=')) {
4226  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4227  $this->debug('Got response encoding: ' . $enc);
4228  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
4229  $this->xml_encoding = strtoupper($enc);
4230  } else {
4231  $this->xml_encoding = 'US-ASCII';
4232  }
4233  } else {
4234  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4235  $this->xml_encoding = 'ISO-8859-1';
4236  }
4237  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4238  // parse response, get soap parser obj
4239  $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
4240  // parser debug
4241  $this->debug("parser debug: \n".$parser->getDebug());
4242  // if fault occurred during message parsing
4243  if($err = $parser->getError()){
4244  $this->result = 'fault: error in msg parsing: '.$err;
4245  $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
4246  // else successfully parsed request into soapval object
4247  } else {
4248  // get/set methodname
4249  $this->methodURI = $parser->root_struct_namespace;
4250  $this->methodname = $parser->root_struct_name;
4251  $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
4252  $this->debug('calling parser->get_soapbody()');
4253  $this->methodparams = $parser->get_soapbody();
4254  // get SOAP headers
4255  $this->requestHeaders = $parser->getHeaders();
4256  // get SOAP Header
4257  $this->requestHeader = $parser->get_soapheader();
4258  // add document for doclit support
4259  $this->document = $parser->document;
4260  }
4261  }
4262 
4270  function getHTTPBody($soapmsg) {
4271  return $soapmsg;
4272  }
4273 
4282  function getHTTPContentType() {
4283  return 'text/xml';
4284  }
4285 
4296  return $this->soap_defencoding;
4297  }
4298 
4309  $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
4310  }
4311 
4326  function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
4327  global $HTTP_SERVER_VARS;
4328 
4329  if($this->externalWSDLURL){
4330  die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4331  }
4332  if (! $name) {
4333  die('You must specify a name when you register an operation');
4334  }
4335  if (!is_array($in)) {
4336  die('You must provide an array for operation inputs');
4337  }
4338  if (!is_array($out)) {
4339  die('You must provide an array for operation outputs');
4340  }
4341  if(false == $namespace) {
4342  }
4343  if(false == $soapaction) {
4344  if (isset($_SERVER)) {
4345  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4346  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4347  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4348  } elseif (isset($HTTP_SERVER_VARS)) {
4349  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4350  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4351  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4352  } else {
4353  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4354  }
4355  if ($HTTPS == '1' || $HTTPS == 'on') {
4356  $SCHEME = 'https';
4357  } else {
4358  $SCHEME = 'http';
4359  }
4360  $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4361  }
4362  if(false == $style) {
4363  $style = "rpc";
4364  }
4365  if(false == $use) {
4366  $use = "encoded";
4367  }
4368  if ($use == 'encoded' && $encodingStyle = '') {
4369  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4370  }
4371 
4372  $this->operations[$name] = array(
4373  'name' => $name,
4374  'in' => $in,
4375  'out' => $out,
4376  'namespace' => $namespace,
4377  'soapaction' => $soapaction,
4378  'style' => $style);
4379  if($this->wsdl){
4380  $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
4381  }
4382  return true;
4383  }
4384 
4395  function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
4396  if ($faultdetail == '' && $this->debug_flag) {
4397  $faultdetail = $this->getDebug();
4398  }
4399  $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
4400  $this->fault->soap_defencoding = $this->soap_defencoding;
4401  }
4402 
4414  function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4415  {
4416  global $HTTP_SERVER_VARS;
4417 
4418  if (isset($_SERVER)) {
4419  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4420  $SERVER_PORT = $_SERVER['SERVER_PORT'];
4421  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4422  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4423  } elseif (isset($HTTP_SERVER_VARS)) {
4424  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4425  $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4426  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4427  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4428  } else {
4429  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4430  }
4431  // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4432  $colon = strpos($SERVER_NAME,":");
4433  if ($colon) {
4434  $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4435  }
4436  if ($SERVER_PORT == 80) {
4437  $SERVER_PORT = '';
4438  } else {
4439  $SERVER_PORT = ':' . $SERVER_PORT;
4440  }
4441  if(false == $namespace) {
4442  $namespace = "http://$SERVER_NAME/soap/$serviceName";
4443  }
4444 
4445  if(false == $endpoint) {
4446  if ($HTTPS == '1' || $HTTPS == 'on') {
4447  $SCHEME = 'https';
4448  } else {
4449  $SCHEME = 'http';
4450  }
4451  $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4452  }
4453 
4454  if(false == $schemaTargetNamespace) {
4455  $schemaTargetNamespace = $namespace;
4456  }
4457 
4458  $this->wsdl = new wsdl;
4459  $this->wsdl->serviceName = $serviceName;
4460  $this->wsdl->endpoint = $endpoint;
4461  $this->wsdl->namespaces['tns'] = $namespace;
4462  $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4463  $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4464  if ($schemaTargetNamespace != $namespace) {
4465  $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4466  }
4467  $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4468  if ($style == 'document') {
4469  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4470  }
4471  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4472  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4473  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4474  $this->wsdl->bindings[$serviceName.'Binding'] = array(
4475  'name'=>$serviceName.'Binding',
4476  'style'=>$style,
4477  'transport'=>$transport,
4478  'portType'=>$serviceName.'PortType');
4479  $this->wsdl->ports[$serviceName.'Port'] = array(
4480  'binding'=>$serviceName.'Binding',
4481  'location'=>$endpoint,
4482  'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
4483  }
4484 }
4485 
4489 class soap_server extends nusoap_server {
4490 }
4491 
4492 ?><?php
4493 
4494 
4495 
4505 class wsdl extends nusoap_base {
4506  // URL or filename of the root of this WSDL
4507  var $wsdl;
4508  // define internal arrays of bindings, ports, operations, messages, etc.
4509  var $schemas = array();
4510  var $currentSchema;
4511  var $message = array();
4512  var $complexTypes = array();
4513  var $messages = array();
4514  var $currentMessage;
4515  var $currentOperation;
4516  var $portTypes = array();
4517  var $currentPortType;
4518  var $bindings = array();
4519  var $currentBinding;
4520  var $ports = array();
4521  var $currentPort;
4522  var $opData = array();
4523  var $status = '';
4524  var $documentation = false;
4525  var $endpoint = '';
4526  // array of wsdl docs to import
4527  var $import = array();
4528  // parser vars
4529  var $parser;
4530  var $position = 0;
4531  var $depth = 0;
4532  var $depth_array = array();
4533  // for getting wsdl
4534  var $proxyhost = '';
4535  var $proxyport = '';
4536  var $proxyusername = '';
4537  var $proxypassword = '';
4538  var $timeout = 0;
4539  var $response_timeout = 30;
4540  var $curl_options = array(); // User-specified cURL options
4541  var $use_curl = false; // whether to always try to use cURL
4542  // for HTTP authentication
4543  var $username = ''; // Username for HTTP authentication
4544  var $password = ''; // Password for HTTP authentication
4545  var $authtype = ''; // Type of HTTP authentication
4546  var $certRequest = array(); // Certificate for HTTP SSL authentication
4547 
4564  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4565  $this->proxyhost = $proxyhost;
4566  $this->proxyport = $proxyport;
4567  $this->proxyusername = $proxyusername;
4568  $this->proxypassword = $proxypassword;
4569  $this->timeout = $timeout;
4570  $this->response_timeout = $response_timeout;
4571  if (is_array($curl_options))
4572  $this->curl_options = $curl_options;
4573  $this->use_curl = $use_curl;
4574  $this->fetchWSDL($wsdl);
4575  }
4576 
4582  function fetchWSDL($wsdl) {
4583  $this->debug("parse and process WSDL path=$wsdl");
4584  $this->wsdl = $wsdl;
4585  // parse wsdl file
4586  if ($this->wsdl != "") {
4587  $this->parseWSDL($this->wsdl);
4588  }
4589  // imports
4590  // TODO: handle imports more properly, grabbing them in-line and nesting them
4591  $imported_urls = array();
4592  $imported = 1;
4593  while ($imported > 0) {
4594  $imported = 0;
4595  // Schema imports
4596  foreach ($this->schemas as $ns => $list) {
4597  foreach ($list as $xs) {
4598  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4599  foreach ($xs->imports as $ns2 => $list2) {
4600  for ($ii = 0; $ii < count($list2); $ii++) {
4601  if (! $list2[$ii]['loaded']) {
4602  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4603  $url = $list2[$ii]['location'];
4604  if ($url != '') {
4605  $urlparts = parse_url($url);
4606  if (!isset($urlparts['host'])) {
4607  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
4608  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4609  }
4610  if (! in_array($url, $imported_urls)) {
4611  $this->parseWSDL($url);
4612  $imported++;
4613  $imported_urls[] = $url;
4614  }
4615  } else {
4616  $this->debug("Unexpected scenario: empty URL for unloaded import");
4617  }
4618  }
4619  }
4620  }
4621  }
4622  }
4623  // WSDL imports
4624  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4625  foreach ($this->import as $ns => $list) {
4626  for ($ii = 0; $ii < count($list); $ii++) {
4627  if (! $list[$ii]['loaded']) {
4628  $this->import[$ns][$ii]['loaded'] = true;
4629  $url = $list[$ii]['location'];
4630  if ($url != '') {
4631  $urlparts = parse_url($url);
4632  if (!isset($urlparts['host'])) {
4633  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4634  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4635  }
4636  if (! in_array($url, $imported_urls)) {
4637  $this->parseWSDL($url);
4638  $imported++;
4639  $imported_urls[] = $url;
4640  }
4641  } else {
4642  $this->debug("Unexpected scenario: empty URL for unloaded import");
4643  }
4644  }
4645  }
4646  }
4647  }
4648  // add new data to operation data
4649  foreach($this->bindings as $binding => $bindingData) {
4650  if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4651  foreach($bindingData['operations'] as $operation => $data) {
4652  $this->debug('post-parse data gathering for ' . $operation);
4653  $this->bindings[$binding]['operations'][$operation]['input'] =
4654  isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4655  array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4656  $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4657  $this->bindings[$binding]['operations'][$operation]['output'] =
4658  isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4659  array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4660  $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4661  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
4662  $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4663  }
4664  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
4665  $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4666  }
4667  // Set operation style if necessary, but do not override one already provided
4668  if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4669  $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4670  }
4671  $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4672  $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4673  $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4674  }
4675  }
4676  }
4677  }
4678 
4685  function parseWSDL($wsdl = '') {
4686  $this->debug("parse WSDL at path=$wsdl");
4687 
4688  if ($wsdl == '') {
4689  $this->debug('no wsdl passed to parseWSDL()!!');
4690  $this->setError('no wsdl passed to parseWSDL()!!');
4691  return false;
4692  }
4693 
4694  // parse $wsdl for url format
4695  $wsdl_props = parse_url($wsdl);
4696 
4697  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4698  $this->debug('getting WSDL http(s) URL ' . $wsdl);
4699  // get wsdl
4700  $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4701  $tr->request_method = 'GET';
4702  $tr->useSOAPAction = false;
4703  if($this->proxyhost && $this->proxyport){
4704  $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
4705  }
4706  if ($this->authtype != '') {
4707  $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4708  }
4709  $tr->setEncoding('gzip, deflate');
4710  $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4711  //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4712  //$this->debug("WSDL response\n" . $tr->incoming_payload);
4713  $this->appendDebug($tr->getDebug());
4714  // catch errors
4715  if($err = $tr->getError() ){
4716  $errstr = 'HTTP ERROR: '.$err;
4717  $this->debug($errstr);
4718  $this->setError($errstr);
4719  unset($tr);
4720  return false;
4721  }
4722  unset($tr);
4723  $this->debug("got WSDL URL");
4724  } else {
4725  // $wsdl is not http(s), so treat it as a file URL or plain file path
4726  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4727  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4728  } else {
4729  $path = $wsdl;
4730  }
4731  $this->debug('getting WSDL file ' . $path);
4732  if ($fp = @fopen($path, 'r')) {
4733  $wsdl_string = '';
4734  while ($data = fread($fp, 32768)) {
4735  $wsdl_string .= $data;
4736  }
4737  fclose($fp);
4738  } else {
4739  $errstr = "Bad path to WSDL file $path";
4740  $this->debug($errstr);
4741  $this->setError($errstr);
4742  return false;
4743  }
4744  }
4745  $this->debug('Parse WSDL');
4746  // end new code added
4747  // Create an XML parser.
4748  $this->parser = xml_parser_create();
4749  // Set the options for parsing the XML data.
4750  // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4751  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4752  // Set the object for the parser.
4753  xml_set_object($this->parser, $this);
4754  // Set the element handlers for the parser.
4755  xml_set_element_handler($this->parser, 'start_element', 'end_element');
4756  xml_set_character_data_handler($this->parser, 'character_data');
4757  // Parse the XML file.
4758  if (!xml_parse($this->parser, $wsdl_string, true)) {
4759  // Display an error message.
4760  $errstr = sprintf(
4761  'XML error parsing WSDL from %s on line %d: %s',
4762  $wsdl,
4763  xml_get_current_line_number($this->parser),
4764  xml_error_string(xml_get_error_code($this->parser))
4765  );
4766  $this->debug($errstr);
4767  $this->debug("XML payload:\n" . $wsdl_string);
4768  $this->setError($errstr);
4769  return false;
4770  }
4771  // free the parser
4772  xml_parser_free($this->parser);
4773  $this->debug('Parsing WSDL done');
4774  // catch wsdl parse errors
4775  if($this->getError()){
4776  return false;
4777  }
4778  return true;
4779  }
4780 
4789  function start_element($parser, $name, $attrs)
4790  {
4791  if ($this->status == 'schema') {
4792  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4793  $this->appendDebug($this->currentSchema->getDebug());
4794  $this->currentSchema->clearDebug();
4795  } elseif (preg_match('/schema$/', $name)) {
4796  $this->debug('Parsing WSDL schema');
4797  // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
4798  $this->status = 'schema';
4799  $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
4800  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4801  $this->appendDebug($this->currentSchema->getDebug());
4802  $this->currentSchema->clearDebug();
4803  } else {
4804  // position in the total number of elements, starting from 0
4805  $pos = $this->position++;
4806  $depth = $this->depth++;
4807  // set self as current value for this depth
4808  $this->depth_array[$depth] = $pos;
4809  $this->message[$pos] = array('cdata' => '');
4810  // process attributes
4811  if (count($attrs) > 0) {
4812  // register namespace declarations
4813  foreach($attrs as $k => $v) {
4814  if (preg_match('/^xmlns/',$k)) {
4815  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4816  $this->namespaces[$ns_prefix] = $v;
4817  } else {
4818  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4819  }
4820  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4821  $this->XMLSchemaVersion = $v;
4822  $this->namespaces['xsi'] = $v . '-instance';
4823  }
4824  }
4825  }
4826  // expand each attribute prefix to its namespace
4827  foreach($attrs as $k => $v) {
4828  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4829  if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4830  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4831  }
4832  $eAttrs[$k] = $v;
4833  }
4834  $attrs = $eAttrs;
4835  } else {
4836  $attrs = array();
4837  }
4838  // get element prefix, namespace and name
4839  if (preg_match('/:/', $name)) {
4840  // get ns prefix
4841  $prefix = substr($name, 0, strpos($name, ':'));
4842  // get ns
4843  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
4844  // get unqualified name
4845  $name = substr(strstr($name, ':'), 1);
4846  }
4847  // process attributes, expanding any prefixes to namespaces
4848  // find status, register data
4849  switch ($this->status) {
4850  case 'message':
4851  if ($name == 'part') {
4852  if (isset($attrs['type'])) {
4853  $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
4854  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4855  }
4856  if (isset($attrs['element'])) {
4857  $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
4858  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
4859  }
4860  }
4861  break;
4862  case 'portType':
4863  switch ($name) {
4864  case 'operation':
4865  $this->currentPortOperation = $attrs['name'];
4866  $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4867  if (isset($attrs['parameterOrder'])) {
4868  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4869  }
4870  break;
4871  case 'documentation':
4872  $this->documentation = true;
4873  break;
4874  // merge input/output data
4875  default:
4876  $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4877  $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4878  break;
4879  }
4880  break;
4881  case 'binding':
4882  switch ($name) {
4883  case 'binding':
4884  // get ns prefix
4885  if (isset($attrs['style'])) {
4886  $this->bindings[$this->currentBinding]['prefix'] = $prefix;
4887  }
4888  $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
4889  break;
4890  case 'header':
4891  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
4892  break;
4893  case 'operation':
4894  if (isset($attrs['soapAction'])) {
4895  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
4896  }
4897  if (isset($attrs['style'])) {
4898  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
4899  }
4900  if (isset($attrs['name'])) {
4901  $this->currentOperation = $attrs['name'];
4902  $this->debug("current binding operation: $this->currentOperation");
4903  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
4904  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
4905  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
4906  }
4907  break;
4908  case 'input':
4909  $this->opStatus = 'input';
4910  break;
4911  case 'output':
4912  $this->opStatus = 'output';
4913  break;
4914  case 'body':
4915  if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
4916  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
4917  } else {
4918  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
4919  }
4920  break;
4921  }
4922  break;
4923  case 'service':
4924  switch ($name) {
4925  case 'port':
4926  $this->currentPort = $attrs['name'];
4927  $this->debug('current port: ' . $this->currentPort);
4928  $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
4929 
4930  break;
4931  case 'address':
4932  $this->ports[$this->currentPort]['location'] = $attrs['location'];
4933  $this->ports[$this->currentPort]['bindingType'] = $namespace;
4934  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
4935  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
4936  break;
4937  }
4938  break;
4939  }
4940  // set status
4941  switch ($name) {
4942  case 'import':
4943  if (isset($attrs['location'])) {
4944  $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
4945  $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
4946  } else {
4947  $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
4948  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
4949  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
4950  }
4951  $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
4952  }
4953  break;
4954  //wait for schema
4955  //case 'types':
4956  // $this->status = 'schema';
4957  // break;
4958  case 'message':
4959  $this->status = 'message';
4960  $this->messages[$attrs['name']] = array();
4961  $this->currentMessage = $attrs['name'];
4962  break;
4963  case 'portType':
4964  $this->status = 'portType';
4965  $this->portTypes[$attrs['name']] = array();
4966  $this->currentPortType = $attrs['name'];
4967  break;
4968  case "binding":
4969  if (isset($attrs['name'])) {
4970  // get binding name
4971  if (strpos($attrs['name'], ':')) {
4972  $this->currentBinding = $this->getLocalPart($attrs['name']);
4973  } else {
4974  $this->currentBinding = $attrs['name'];
4975  }
4976  $this->status = 'binding';
4977  $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
4978  $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
4979  }
4980  break;
4981  case 'service':
4982  $this->serviceName = $attrs['name'];
4983  $this->status = 'service';
4984  $this->debug('current service: ' . $this->serviceName);
4985  break;
4986  case 'definitions':
4987  foreach ($attrs as $name => $value) {
4988  $this->wsdl_info[$name] = $value;
4989  }
4990  break;
4991  }
4992  }
4993  }
4994 
5003  // unset schema status
5004  if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
5005  $this->status = "";
5006  $this->appendDebug($this->currentSchema->getDebug());
5007  $this->currentSchema->clearDebug();
5008  $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5009  $this->debug('Parsing WSDL schema done');
5010  }
5011  if ($this->status == 'schema') {
5012  $this->currentSchema->schemaEndElement($parser, $name);
5013  } else {
5014  // bring depth down a notch
5015  $this->depth--;
5016  }
5017  // end documentation
5018  if ($this->documentation) {
5019  //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5020  //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5021  $this->documentation = false;
5022  }
5023  }
5024 
5033  {
5034  $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5035  if (isset($this->message[$pos]['cdata'])) {
5036  $this->message[$pos]['cdata'] .= $data;
5037  }
5038  if ($this->documentation) {
5039  $this->documentation .= $data;
5040  }
5041  }
5042 
5052  function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
5053  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5054  $this->appendDebug($this->varDump($certRequest));
5055  $this->username = $username;
5056  $this->password = $password;
5057  $this->authtype = $authtype;
5058  $this->certRequest = $certRequest;
5059  }
5060 
5061  function getBindingData($binding)
5062  {
5063  if (is_array($this->bindings[$binding])) {
5064  return $this->bindings[$binding];
5065  }
5066  }
5067 
5075  function getOperations($bindingType = 'soap') {
5076  $ops = array();
5077  if ($bindingType == 'soap') {
5078  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5079  } elseif ($bindingType == 'soap12') {
5080  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5081  }
5082  // loop thru ports
5083  foreach($this->ports as $port => $portData) {
5084  // binding type of port matches parameter
5085  if ($portData['bindingType'] == $bindingType) {
5086  //$this->debug("getOperations for port $port");
5087  //$this->debug("port data: " . $this->varDump($portData));
5088  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5089  // merge bindings
5090  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5091  $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
5092  }
5093  }
5094  }
5095  return $ops;
5096  }
5097 
5106  function getOperationData($operation, $bindingType = 'soap')
5107  {
5108  if ($bindingType == 'soap') {
5109  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5110  } elseif ($bindingType == 'soap12') {
5111  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5112  }
5113  // loop thru ports
5114  foreach($this->ports as $port => $portData) {
5115  // binding type of port matches parameter
5116  if ($portData['bindingType'] == $bindingType) {
5117  // get binding
5118  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5119  foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5120  // note that we could/should also check the namespace here
5121  if ($operation == $bOperation) {
5122  $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5123  return $opData;
5124  }
5125  }
5126  }
5127  }
5128  }
5129 
5138  function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
5139  if ($bindingType == 'soap') {
5140  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5141  } elseif ($bindingType == 'soap12') {
5142  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5143  }
5144  // loop thru ports
5145  foreach($this->ports as $port => $portData) {
5146  // binding type of port matches parameter
5147  if ($portData['bindingType'] == $bindingType) {
5148  // loop through operations for the binding
5149  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5150  if ($opData['soapAction'] == $soapAction) {
5151  return $opData;
5152  }
5153  }
5154  }
5155  }
5156  }
5157 
5176  function getTypeDef($type, $ns) {
5177  $this->debug("in getTypeDef: type=$type, ns=$ns");
5178  if ((! $ns) && isset($this->namespaces['tns'])) {
5179  $ns = $this->namespaces['tns'];
5180  $this->debug("in getTypeDef: type namespace forced to $ns");
5181  }
5182  if (!isset($this->schemas[$ns])) {
5183  foreach ($this->schemas as $ns0 => $schema0) {
5184  if (strcasecmp($ns, $ns0) == 0) {
5185  $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5186  $ns = $ns0;
5187  break;
5188  }
5189  }
5190  }
5191  if (isset($this->schemas[$ns])) {
5192  $this->debug("in getTypeDef: have schema for namespace $ns");
5193  for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5194  $xs = &$this->schemas[$ns][$i];
5195  $t = $xs->getTypeDef($type);
5196  //$this->appendDebug($xs->getDebug());
5197  //$xs->clearDebug();
5198  if ($t) {
5199  if (!isset($t['phpType'])) {
5200  // get info for type to tack onto the element
5201  $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5202  $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5203  $etype = $this->getTypeDef($uqType, $ns);
5204  if ($etype) {
5205  $this->debug("found type for [element] $type:");
5206  $this->debug($this->varDump($etype));
5207  if (isset($etype['phpType'])) {
5208  $t['phpType'] = $etype['phpType'];
5209  }
5210  if (isset($etype['elements'])) {
5211  $t['elements'] = $etype['elements'];
5212  }
5213  if (isset($etype['attrs'])) {
5214  $t['attrs'] = $etype['attrs'];
5215  }
5216  }
5217  }
5218  return $t;
5219  }
5220  }
5221  } else {
5222  $this->debug("in getTypeDef: do not have schema for namespace $ns");
5223  }
5224  return false;
5225  }
5226 
5232  function webDescription(){
5233  global $HTTP_SERVER_VARS;
5234 
5235  if (isset($_SERVER)) {
5236  $PHP_SELF = $_SERVER['PHP_SELF'];
5237  } elseif (isset($HTTP_SERVER_VARS)) {
5238  $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5239  } else {
5240  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5241  }
5242 
5243  $b = '
5244  <html><head><title>NuSOAP: '.$this->serviceName.'</title>
5245  <style type="text/css">
5246  body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5247  p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5248  pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5249  ul { margin-top: 10px; margin-left: 20px; }
5250  li { list-style-type: none; margin-top: 10px; color: #000000; }
5251  .content{
5252  margin-left: 0px; padding-bottom: 2em; }
5253  .nav {
5254  padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5255  margin-top: 10px; margin-left: 0px; color: #000000;
5256  background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5257  .title {
5258  font-family: arial; font-size: 26px; color: #ffffff;
5259  background-color: #999999; width: 105%; margin-left: 0px;
5260  padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
5261  .hidden {
5262  position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5263  font-family: arial; overflow: hidden; width: 600;
5264  padding: 20px; font-size: 10px; background-color: #999999;
5265  layer-background-color:#FFFFFF; }
5266  a,a:active { color: charcoal; font-weight: bold; }
5267  a:visited { color: #666666; font-weight: bold; }
5268  a:hover { color: cc3300; font-weight: bold; }
5269  </style>
5270  <script language="JavaScript" type="text/javascript">
5271  <!--
5272  // POP-UP CAPTIONS...
5273  function lib_bwcheck(){ //Browsercheck (needed)
5274  this.ver=navigator.appVersion
5275  this.agent=navigator.userAgent
5276  this.dom=document.getElementById?1:0
5277  this.opera5=this.agent.indexOf("Opera 5")>-1
5278  this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5279  this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5280  this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5281  this.ie=this.ie4||this.ie5||this.ie6
5282  this.mac=this.agent.indexOf("Mac")>-1
5283  this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5284  this.ns4=(document.layers && !this.dom)?1:0;
5285  this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5286  return this
5287  }
5288  var bw = new lib_bwcheck()
5289  //Makes crossbrowser object.
5290  function makeObj(obj){
5291  this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5292  if(!this.evnt) return false
5293  this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5294  this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5295  this.writeIt=b_writeIt;
5296  return this
5297  }
5298  // A unit of measure that will be added when setting the position of a layer.
5299  //var px = bw.ns4||window.opera?"":"px";
5300  function b_writeIt(text){
5301  if (bw.ns4){this.wref.write(text);this.wref.close()}
5302  else this.wref.innerHTML = text
5303  }
5304  //Shows the messages
5305  var oDesc;
5306  function popup(divid){
5307  if(oDesc = new makeObj(divid)){
5308  oDesc.css.visibility = "visible"
5309  }
5310  }
5311  function popout(){ // Hides message
5312  if(oDesc) oDesc.css.visibility = "hidden"
5313  }
5314  //-->
5315  </script>
5316  </head>
5317  <body>
5318  <div class=content>
5319  <br><br>
5320  <div class=title>'.$this->serviceName.'</div>
5321  <div class=nav>
5322  <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
5323  Click on an operation name to view it&apos;s details.</p>
5324  <ul>';
5325  foreach($this->getOperations() as $op => $data){
5326  $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5327  // create hidden div
5328  $b .= "<div id='$op' class='hidden'>
5329  <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5330  foreach($data as $donnie => $marie){ // loop through opdata
5331  if($donnie == 'input' || $donnie == 'output'){ // show input/output data
5332  $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
5333  foreach($marie as $captain => $tenille){ // loop through data
5334  if($captain == 'parts'){ // loop thru parts
5335  $b .= "&nbsp;&nbsp;$captain:<br>";
5336  //if(is_array($tenille)){
5337  foreach($tenille as $joanie => $chachi){
5338  $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5339  }
5340  //}
5341  } else {
5342  $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5343  }
5344  }
5345  } else {
5346  $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
5347  }
5348  }
5349  $b .= '</div>';
5350  }
5351  $b .= '
5352  <ul>
5353  </div>
5354  </div></body></html>';
5355  return $b;
5356  }
5357 
5365  function serialize($debug = 0)
5366  {
5367  $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5368  $xml .= "\n<definitions";
5369  foreach($this->namespaces as $k => $v) {
5370  $xml .= " xmlns:$k=\"$v\"";
5371  }
5372  // 10.9.02 - add poulter fix for wsdl and tns declarations
5373  if (isset($this->namespaces['wsdl'])) {
5374  $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5375  }
5376  if (isset($this->namespaces['tns'])) {
5377  $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5378  }
5379  $xml .= '>';
5380  // imports
5381  if (sizeof($this->import) > 0) {
5382  foreach($this->import as $ns => $list) {
5383  foreach ($list as $ii) {
5384  if ($ii['location'] != '') {
5385  $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5386  } else {
5387  $xml .= '<import namespace="' . $ns . '" />';
5388  }
5389  }
5390  }
5391  }
5392  // types
5393  if (count($this->schemas)>=1) {
5394  $xml .= "\n<types>\n";
5395  foreach ($this->schemas as $ns => $list) {
5396  foreach ($list as $xs) {
5397  $xml .= $xs->serializeSchema();
5398  }
5399  }
5400  $xml .= '</types>';
5401  }
5402  // messages
5403  if (count($this->messages) >= 1) {
5404  foreach($this->messages as $msgName => $msgParts) {
5405  $xml .= "\n<message name=\"" . $msgName . '">';
5406  if(is_array($msgParts)){
5407  foreach($msgParts as $partName => $partType) {
5408  // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5409  if (strpos($partType, ':')) {
5410  $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5411  } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5412  // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5413  $typePrefix = 'xsd';
5414  } else {
5415  foreach($this->typemap as $ns => $types) {
5416  if (isset($types[$partType])) {
5417  $typePrefix = $this->getPrefixFromNamespace($ns);
5418  }
5419  }
5420  if (!isset($typePrefix)) {
5421  die("$partType has no namespace!");
5422  }
5423  }
5424  $ns = $this->getNamespaceFromPrefix($typePrefix);
5425  $localPart = $this->getLocalPart($partType);
5426  $typeDef = $this->getTypeDef($localPart, $ns);
5427  if ($typeDef['typeClass'] == 'element') {
5428  $elementortype = 'element';
5429  if (substr($localPart, -1) == '^') {
5430  $localPart = substr($localPart, 0, -1);
5431  }
5432  } else {
5433  $elementortype = 'type';
5434  }
5435  $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5436  }
5437  }
5438  $xml .= '</message>';
5439  }
5440  }
5441  // bindings & porttypes
5442  if (count($this->bindings) >= 1) {
5443  $binding_xml = '';
5444  $portType_xml = '';
5445  foreach($this->bindings as $bindingName => $attrs) {
5446  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5447  $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5448  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5449  foreach($attrs['operations'] as $opName => $opParts) {
5450  $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5451  $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
5452  if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5453  $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5454  } else {
5455  $enc_style = '';
5456  }
5457  $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5458  if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5459  $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5460  } else {
5461  $enc_style = '';
5462  }
5463  $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5464  $binding_xml .= "\n" . ' </operation>';
5465  $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5466  if (isset($opParts['parameterOrder'])) {
5467  $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5468  }
5469  $portType_xml .= '>';
5470  if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
5471  $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5472  }
5473  $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5474  $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5475  $portType_xml .= "\n" . ' </operation>';
5476  }
5477  $portType_xml .= "\n" . '</portType>';
5478  $binding_xml .= "\n" . '</binding>';
5479  }
5480  $xml .= $portType_xml . $binding_xml;
5481  }
5482  // services
5483  $xml .= "\n<service name=\"" . $this->serviceName . '">';
5484  if (count($this->ports) >= 1) {
5485  foreach($this->ports as $pName => $attrs) {
5486  $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5487  $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5488  $xml .= "\n" . ' </port>';
5489  }
5490  }
5491  $xml .= "\n" . '</service>';
5492  return $xml . "\n</definitions>";
5493  }
5494 
5504  function parametersMatchWrapped($type, &$parameters) {
5505  $this->debug("in parametersMatchWrapped type=$type, parameters=");
5506  $this->appendDebug($this->varDump($parameters));
5507 
5508  // split type into namespace:unqualified-type
5509  if (strpos($type, ':')) {
5510  $uqType = substr($type, strrpos($type, ':') + 1);
5511  $ns = substr($type, 0, strrpos($type, ':'));
5512  $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5513  if ($this->getNamespaceFromPrefix($ns)) {
5514  $ns = $this->getNamespaceFromPrefix($ns);
5515  $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5516  }
5517  } else {
5518  // TODO: should the type be compared to types in XSD, and the namespace
5519  // set to XSD if the type matches?
5520  $this->debug("in parametersMatchWrapped: No namespace for type $type");
5521  $ns = '';
5522  $uqType = $type;
5523  }
5524 
5525  // get the type information
5526  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5527  $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5528  return false;
5529  }
5530  $this->debug("in parametersMatchWrapped: found typeDef=");
5531  $this->appendDebug($this->varDump($typeDef));
5532  if (substr($uqType, -1) == '^') {
5533  $uqType = substr($uqType, 0, -1);
5534  }
5535  $phpType = $typeDef['phpType'];
5536  $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5537  $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5538 
5539  // we expect a complexType or element of complexType
5540  if ($phpType != 'struct') {
5541  $this->debug("in parametersMatchWrapped: not a struct");
5542  return false;
5543  }
5544 
5545  // see whether the parameter names match the elements
5546  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5547  $elements = 0;
5548  $matches = 0;
5549  $change = false;
5550  if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
5551  $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
5552  $change = true;
5553  }
5554  foreach ($typeDef['elements'] as $name => $attrs) {
5555  if ($change) {
5556  $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
5557  $parameters[$name] = $parameters[$elements];
5558  unset($parameters[$elements]);
5559  $matches++;
5560  } elseif (isset($parameters[$name])) {
5561  $this->debug("in parametersMatchWrapped: have parameter named $name");
5562  $matches++;
5563  } else {
5564  $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5565  }
5566  $elements++;
5567  }
5568 
5569  $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5570  if ($matches == 0) {
5571  return false;
5572  }
5573  return true;
5574  }
5575 
5576  // since there are no elements for the type, if the user passed no
5577  // parameters, the parameters match wrapped.
5578  $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5579  return count($parameters) == 0;
5580  }
5581 
5597  function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
5598  $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5599  $this->appendDebug('parameters=' . $this->varDump($parameters));
5600 
5601  if ($direction != 'input' && $direction != 'output') {
5602  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5603  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5604  return false;
5605  }
5606  if (!$opData = $this->getOperationData($operation, $bindingType)) {
5607  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5608  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5609  return false;
5610  }
5611  $this->debug('in serializeRPCParameters: opData:');
5612  $this->appendDebug($this->varDump($opData));
5613 
5614  // Get encoding style for output and set to current
5615  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5616  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5617  $encodingStyle = $opData['output']['encodingStyle'];
5618  $enc_style = $encodingStyle;
5619  }
5620 
5621  // set input params
5622  $xml = '';
5623  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5624  $parts = &$opData[$direction]['parts'];
5625  $part_count = sizeof($parts);
5626  $style = $opData['style'];
5627  $use = $opData[$direction]['use'];
5628  $this->debug("have $part_count part(s) to serialize using $style/$use");
5629  if (is_array($parameters)) {
5630  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5631  $parameter_count = count($parameters);
5632  $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5633  // check for Microsoft-style wrapped parameters
5634  if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5635  $this->debug('check whether the caller has wrapped the parameters');
5636  if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
5637  $this->debug('check whether caller\'s parameters match the wrapped ones');
5638  if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5639  $this->debug('wrap the parameters for the caller');
5640  $parameters = array('parameters' => $parameters);
5641  $parameter_count = 1;
5642  }
5643  }
5644  }
5645  foreach ($parts as $name => $type) {
5646  $this->debug("serializing part $name of type $type");
5647  // Track encoding style
5648  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5649  $encodingStyle = $opData[$direction]['encodingStyle'];
5650  $enc_style = $encodingStyle;
5651  } else {
5652  $enc_style = false;
5653  }
5654  // NOTE: add error handling here
5655  // if serializeType returns false, then catch global error and fault
5656  if ($parametersArrayType == 'arraySimple') {
5657  $p = array_shift($parameters);
5658  $this->debug('calling serializeType w/indexed param');
5659  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5660  } elseif (isset($parameters[$name])) {
5661  $this->debug('calling serializeType w/named param');
5662  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5663  } else {
5664  // TODO: only send nillable
5665  $this->debug('calling serializeType w/null param');
5666  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5667  }
5668  }
5669  } else {
5670  $this->debug('no parameters passed.');
5671  }
5672  }
5673  $this->debug("serializeRPCParameters returning: $xml");
5674  return $xml;
5675  }
5676 
5691  function serializeParameters($operation, $direction, $parameters)
5692  {
5693  $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5694  $this->appendDebug('parameters=' . $this->varDump($parameters));
5695 
5696  if ($direction != 'input' && $direction != 'output') {
5697  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5698  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5699  return false;
5700  }
5701  if (!$opData = $this->getOperationData($operation)) {
5702  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5703  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5704  return false;
5705  }
5706  $this->debug('opData:');
5707  $this->appendDebug($this->varDump($opData));
5708 
5709  // Get encoding style for output and set to current
5710  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5711  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5712  $encodingStyle = $opData['output']['encodingStyle'];
5713  $enc_style = $encodingStyle;
5714  }
5715 
5716  // set input params
5717  $xml = '';
5718  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5719 
5720  $use = $opData[$direction]['use'];
5721  $this->debug("use=$use");
5722  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5723  if (is_array($parameters)) {
5724  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5725  $this->debug('have ' . $parametersArrayType . ' parameters');
5726  foreach($opData[$direction]['parts'] as $name => $type) {
5727  $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5728  // Track encoding style
5729  if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5730  $encodingStyle = $opData[$direction]['encodingStyle'];
5731  $enc_style = $encodingStyle;
5732  } else {
5733  $enc_style = false;
5734  }
5735  // NOTE: add error handling here
5736  // if serializeType returns false, then catch global error and fault
5737  if ($parametersArrayType == 'arraySimple') {
5738  $p = array_shift($parameters);
5739  $this->debug('calling serializeType w/indexed param');
5740  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5741  } elseif (isset($parameters[$name])) {
5742  $this->debug('calling serializeType w/named param');
5743  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5744  } else {
5745  // TODO: only send nillable
5746  $this->debug('calling serializeType w/null param');
5747  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5748  }
5749  }
5750  } else {
5751  $this->debug('no parameters passed.');
5752  }
5753  }
5754  $this->debug("serializeParameters returning: $xml");
5755  return $xml;
5756  }
5757 
5770  function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
5771  {
5772  $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5773  $this->appendDebug("value=" . $this->varDump($value));
5774  if($use == 'encoded' && $encodingStyle) {
5775  $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5776  }
5777 
5778  // if a soapval has been supplied, let its type override the WSDL
5779  if (is_object($value) && get_class($value) == 'soapval') {
5780  if ($value->type_ns) {
5781  $type = $value->type_ns . ':' . $value->type;
5782  $forceType = true;
5783  $this->debug("in serializeType: soapval overrides type to $type");
5784  } elseif ($value->type) {
5785  $type = $value->type;
5786  $forceType = true;
5787  $this->debug("in serializeType: soapval overrides type to $type");
5788  } else {
5789  $forceType = false;
5790  $this->debug("in serializeType: soapval does not override type");
5791  }
5792  $attrs = $value->attributes;
5793  $value = $value->value;
5794  $this->debug("in serializeType: soapval overrides value to $value");
5795  if ($attrs) {
5796  if (!is_array($value)) {
5797  $value['!'] = $value;
5798  }
5799  foreach ($attrs as $n => $v) {
5800  $value['!' . $n] = $v;
5801  }
5802  $this->debug("in serializeType: soapval provides attributes");
5803  }
5804  } else {
5805  $forceType = false;
5806  }
5807 
5808  $xml = '';
5809  if (strpos($type, ':')) {
5810  $uqType = substr($type, strrpos($type, ':') + 1);
5811  $ns = substr($type, 0, strrpos($type, ':'));
5812  $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5813  if ($this->getNamespaceFromPrefix($ns)) {
5814  $ns = $this->getNamespaceFromPrefix($ns);
5815  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5816  }
5817 
5818  if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
5819  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5820  if ($unqualified && $use == 'literal') {
5821  $elementNS = " xmlns=\"\"";
5822  } else {
5823  $elementNS = '';
5824  }
5825  if (is_null($value)) {
5826  if ($use == 'literal') {
5827  // TODO: depends on minOccurs
5828  $xml = "<$name$elementNS/>";
5829  } else {
5830  // TODO: depends on nillable, which should be checked before calling this method
5831  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5832  }
5833  $this->debug("in serializeType: returning: $xml");
5834  return $xml;
5835  }
5836  if ($uqType == 'Array') {
5837  // JBoss/Axis does this sometimes
5838  return $this->serialize_val($value, $name, false, false, false, false, $use);
5839  }
5840  if ($uqType == 'boolean') {
5841  if ((is_string($value) && $value == 'false') || (! $value)) {
5842  $value = 'false';
5843  } else {
5844  $value = 'true';
5845  }
5846  }
5847  if ($uqType == 'string' && gettype($value) == 'string') {
5848  $value = $this->expandEntities($value);
5849  }
5850  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5851  $value = sprintf("%.0lf", $value);
5852  }
5853  // it's a scalar
5854  // TODO: what about null/nil values?
5855  // check type isn't a custom type extending xmlschema namespace
5856  if (!$this->getTypeDef($uqType, $ns)) {
5857  if ($use == 'literal') {
5858  if ($forceType) {
5859  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5860  } else {
5861  $xml = "<$name$elementNS>$value</$name>";
5862  }
5863  } else {
5864  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5865  }
5866  $this->debug("in serializeType: returning: $xml");
5867  return $xml;
5868  }
5869  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
5870  } else if ($ns == 'http://xml.apache.org/xml-soap') {
5871  $this->debug('in serializeType: appears to be Apache SOAP type');
5872  if ($uqType == 'Map') {
5873  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5874  if (! $tt_prefix) {
5875  $this->debug('in serializeType: Add namespace for Apache SOAP type');
5876  $tt_prefix = 'ns' . rand(1000, 9999);
5877  $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
5878  // force this to be added to usedNamespaces
5879  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5880  }
5881  $contents = '';
5882  foreach($value as $k => $v) {
5883  $this->debug("serializing map element: key $k, value $v");
5884  $contents .= '<item>';
5885  $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
5886  $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
5887  $contents .= '</item>';
5888  }
5889  if ($use == 'literal') {
5890  if ($forceType) {
5891  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
5892  } else {
5893  $xml = "<$name>$contents</$name>";
5894  }
5895  } else {
5896  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
5897  }
5898  $this->debug("in serializeType: returning: $xml");
5899  return $xml;
5900  }
5901  $this->debug('in serializeType: Apache SOAP type, but only support Map');
5902  }
5903  } else {
5904  // TODO: should the type be compared to types in XSD, and the namespace
5905  // set to XSD if the type matches?
5906  $this->debug("in serializeType: No namespace for type $type");
5907  $ns = '';
5908  $uqType = $type;
5909  }
5910  if(!$typeDef = $this->getTypeDef($uqType, $ns)){
5911  $this->setError("$type ($uqType) is not a supported type.");
5912  $this->debug("in serializeType: $type ($uqType) is not a supported type.");
5913  return false;
5914  } else {
5915  $this->debug("in serializeType: found typeDef");
5916  $this->appendDebug('typeDef=' . $this->varDump($typeDef));
5917  if (substr($uqType, -1) == '^') {
5918  $uqType = substr($uqType, 0, -1);
5919  }
5920  }
5921  $phpType = $typeDef['phpType'];
5922  $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
5923  // if php type == struct, map value to the <all> element names
5924  if ($phpType == 'struct') {
5925  if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
5926  $elementName = $uqType;
5927  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5928  $elementNS = " xmlns=\"$ns\"";
5929  } else {
5930  $elementNS = " xmlns=\"\"";
5931  }
5932  } else {
5933  $elementName = $name;
5934  if ($unqualified) {
5935  $elementNS = " xmlns=\"\"";
5936  } else {
5937  $elementNS = '';
5938  }
5939  }
5940  if (is_null($value)) {
5941  if ($use == 'literal') {
5942  // TODO: depends on minOccurs
5943  $xml = "<$elementName$elementNS/>";
5944  } else {
5945  $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5946  }
5947  $this->debug("in serializeType: returning: $xml");
5948  return $xml;
5949  }
5950  if (is_object($value)) {
5951  $value = get_object_vars($value);
5952  }
5953  if (is_array($value)) {
5954  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
5955  if ($use == 'literal') {
5956  if ($forceType) {
5957  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
5958  } else {
5959  $xml = "<$elementName$elementNS$elementAttrs>";
5960  }
5961  } else {
5962  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
5963  }
5964 
5965  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
5966  $xml .= "</$elementName>";
5967  } else {
5968  $this->debug("in serializeType: phpType is struct, but value is not an array");
5969  $this->setError("phpType is struct, but value is not an array: see debug output for details");
5970  $xml = '';
5971  }
5972  } elseif ($phpType == 'array') {
5973  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5974  $elementNS = " xmlns=\"$ns\"";
5975  } else {
5976  if ($unqualified) {
5977  $elementNS = " xmlns=\"\"";
5978  } else {
5979  $elementNS = '';
5980  }
5981  }
5982  if (is_null($value)) {
5983  if ($use == 'literal') {
5984  // TODO: depends on minOccurs
5985  $xml = "<$name$elementNS/>";
5986  } else {
5987  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
5988  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5989  ":Array\" " .
5990  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5991  ':arrayType="' .
5992  $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
5993  ':' .
5994  $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
5995  }
5996  $this->debug("in serializeType: returning: $xml");
5997  return $xml;
5998  }
5999  if (isset($typeDef['multidimensional'])) {
6000  $nv = array();
6001  foreach($value as $v) {
6002  $cols = ',' . sizeof($v);
6003  $nv = array_merge($nv, $v);
6004  }
6005  $value = $nv;
6006  } else {
6007  $cols = '';
6008  }
6009  if (is_array($value) && sizeof($value) >= 1) {
6010  $rows = sizeof($value);
6011  $contents = '';
6012  foreach($value as $k => $v) {
6013  $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6014  //if (strpos($typeDef['arrayType'], ':') ) {
6015  if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6016  $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6017  } else {
6018  $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6019  }
6020  }
6021  } else {
6022  $rows = 0;
6023  $contents = null;
6024  }
6025  // TODO: for now, an empty value will be serialized as a zero element
6026  // array. Revisit this when coding the handling of null/nil values.
6027  if ($use == 'literal') {
6028  $xml = "<$name$elementNS>"
6029  .$contents
6030  ."</$name>";
6031  } else {
6032  $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
6033  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6034  .':arrayType="'
6035  .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6036  .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
6037  .$contents
6038  ."</$name>";
6039  }
6040  } elseif ($phpType == 'scalar') {
6041  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6042  $elementNS = " xmlns=\"$ns\"";
6043  } else {
6044  if ($unqualified) {
6045  $elementNS = " xmlns=\"\"";
6046  } else {
6047  $elementNS = '';
6048  }
6049  }
6050  if ($use == 'literal') {
6051  if ($forceType) {
6052  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6053  } else {
6054  $xml = "<$name$elementNS>$value</$name>";
6055  }
6056  } else {
6057  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6058  }
6059  }
6060  $this->debug("in serializeType: returning: $xml");
6061  return $xml;
6062  }
6063 
6074  function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
6075  $xml = '';
6076  if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6077  $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6078  if (is_array($value)) {
6079  $xvalue = $value;
6080  } elseif (is_object($value)) {
6081  $xvalue = get_object_vars($value);
6082  } else {
6083  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6084  $xvalue = array();
6085  }
6086  foreach ($typeDef['attrs'] as $aName => $attrs) {
6087  if (isset($xvalue['!' . $aName])) {
6088  $xname = '!' . $aName;
6089  $this->debug("value provided for attribute $aName with key $xname");
6090  } elseif (isset($xvalue[$aName])) {
6091  $xname = $aName;
6092  $this->debug("value provided for attribute $aName with key $xname");
6093  } elseif (isset($attrs['default'])) {
6094  $xname = '!' . $aName;
6095  $xvalue[$xname] = $attrs['default'];
6096  $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6097  } else {
6098  $xname = '';
6099  $this->debug("no value provided for attribute $aName");
6100  }
6101  if ($xname) {
6102  $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6103  }
6104  }
6105  } else {
6106  $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6107  }
6108  if (isset($typeDef['extensionBase'])) {
6109  $ns = $this->getPrefix($typeDef['extensionBase']);
6110  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6111  if ($this->getNamespaceFromPrefix($ns)) {
6112  $ns = $this->getNamespaceFromPrefix($ns);
6113  }
6114  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6115  $this->debug("serialize attributes for extension base $ns:$uqType");
6116  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6117  } else {
6118  $this->debug("extension base $ns:$uqType is not a supported type");
6119  }
6120  }
6121  return $xml;
6122  }
6123 
6136  function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
6137  $xml = '';
6138  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6139  $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6140  if (is_array($value)) {
6141  $xvalue = $value;
6142  } elseif (is_object($value)) {
6143  $xvalue = get_object_vars($value);
6144  } else {
6145  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6146  $xvalue = array();
6147  }
6148  // toggle whether all elements are present - ideally should validate against schema
6149  if (count($typeDef['elements']) != count($xvalue)){
6150  $optionals = true;
6151  }
6152  foreach ($typeDef['elements'] as $eName => $attrs) {
6153  if (!isset($xvalue[$eName])) {
6154  if (isset($attrs['default'])) {
6155  $xvalue[$eName] = $attrs['default'];
6156  $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6157  }
6158  }
6159  // if user took advantage of a minOccurs=0, then only serialize named parameters
6160  if (isset($optionals)
6161  && (!isset($xvalue[$eName]))
6162  && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6163  ){
6164  if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6165  $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6166  }
6167  // do nothing
6168  $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6169  } else {
6170  // get value
6171  if (isset($xvalue[$eName])) {
6172  $v = $xvalue[$eName];
6173  } else {
6174  $v = null;
6175  }
6176  if (isset($attrs['form'])) {
6177  $unqualified = ($attrs['form'] == 'unqualified');
6178  } else {
6179  $unqualified = false;
6180  }
6181  if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6182  $vv = $v;
6183  foreach ($vv as $k => $v) {
6184  if (isset($attrs['type']) || isset($attrs['ref'])) {
6185  // serialize schema-defined type
6186  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6187  } else {
6188  // serialize generic type (can this ever really happen?)
6189  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6190  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6191  }
6192  }
6193  } else {
6194  if (isset($attrs['type']) || isset($attrs['ref'])) {
6195  // serialize schema-defined type
6196  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6197  } else {
6198  // serialize generic type (can this ever really happen?)
6199  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6200  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6201  }
6202  }
6203  }
6204  }
6205  } else {
6206  $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6207  }
6208  if (isset($typeDef['extensionBase'])) {
6209  $ns = $this->getPrefix($typeDef['extensionBase']);
6210  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6211  if ($this->getNamespaceFromPrefix($ns)) {
6212  $ns = $this->getNamespaceFromPrefix($ns);
6213  }
6214  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6215  $this->debug("serialize elements for extension base $ns:$uqType");
6216  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6217  } else {
6218  $this->debug("extension base $ns:$uqType is not a supported type");
6219  }
6220  }
6221  return $xml;
6222  }
6223 
6238  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
6239  if (count($elements) > 0) {
6240  $eElements = array();
6241  foreach($elements as $n => $e){
6242  // expand each element
6243  $ee = array();
6244  foreach ($e as $k => $v) {
6245  $k = strpos($k,':') ? $this->expandQname($k) : $k;
6246  $v = strpos($v,':') ? $this->expandQname($v) : $v;
6247  $ee[$k] = $v;
6248  }
6249  $eElements[$n] = $ee;
6250  }
6251  $elements = $eElements;
6252  }
6253 
6254  if (count($attrs) > 0) {
6255  foreach($attrs as $n => $a){
6256  // expand each attribute
6257  foreach ($a as $k => $v) {
6258  $k = strpos($k,':') ? $this->expandQname($k) : $k;
6259  $v = strpos($v,':') ? $this->expandQname($v) : $v;
6260  $aa[$k] = $v;
6261  }
6262  $eAttrs[$n] = $aa;
6263  }
6264  $attrs = $eAttrs;
6265  }
6266 
6267  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6268  $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
6269 
6270  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6271  $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
6272  }
6273 
6285  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
6286  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6287 
6288  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6289  $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6290  }
6291 
6299  function addElement($attrs) {
6300  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6301  $this->schemas[$typens][0]->addElement($attrs);
6302  }
6303 
6318  function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
6319  if ($use == 'encoded' && $encodingStyle == '') {
6320  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6321  }
6322 
6323  if ($style == 'document') {
6324  $elements = array();
6325  foreach ($in as $n => $t) {
6326  $elements[$n] = array('name' => $n, 'type' => $t);
6327  }
6328  $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6329  $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6330  $in = array('parameters' => 'tns:' . $name . '^');
6331 
6332  $elements = array();
6333  foreach ($out as $n => $t) {
6334  $elements[$n] = array('name' => $n, 'type' => $t);
6335  }
6336  $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6337  $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6338  $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6339  }
6340 
6341  // get binding
6342  $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6343  array(
6344  'name' => $name,
6345  'binding' => $this->serviceName . 'Binding',
6346  'endpoint' => $this->endpoint,
6347  'soapAction' => $soapaction,
6348  'style' => $style,
6349  'input' => array(
6350  'use' => $use,
6351  'namespace' => $namespace,
6352  'encodingStyle' => $encodingStyle,
6353  'message' => $name . 'Request',
6354  'parts' => $in),
6355  'output' => array(
6356  'use' => $use,
6357  'namespace' => $namespace,
6358  'encodingStyle' => $encodingStyle,
6359  'message' => $name . 'Response',
6360  'parts' => $out),
6361  'namespace' => $namespace,
6362  'transport' => 'http://schemas.xmlsoap.org/soap/http',
6363  'documentation' => $documentation);
6364  // add portTypes
6365  // add messages
6366  if($in)
6367  {
6368  foreach($in as $pName => $pType)
6369  {
6370  if(strpos($pType,':')) {
6371  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6372  }
6373  $this->messages[$name.'Request'][$pName] = $pType;
6374  }
6375  } else {
6376  $this->messages[$name.'Request']= '0';
6377  }
6378  if($out)
6379  {
6380  foreach($out as $pName => $pType)
6381  {
6382  if(strpos($pType,':')) {
6383  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6384  }
6385  $this->messages[$name.'Response'][$pName] = $pType;
6386  }
6387  } else {
6388  $this->messages[$name.'Response']= '0';
6389  }
6390  return true;
6391  }
6392 }
6393 ?><?php
6394 
6395 
6396 
6407 
6408  var $xml = '';
6409  var $xml_encoding = '';
6410  var $method = '';
6411  var $root_struct = '';
6414  var $root_header = '';
6415  var $document = ''; // incoming SOAP body (text)
6416  // determines where in the message we are (envelope,header,body,method)
6417  var $status = '';
6418  var $position = 0;
6419  var $depth = 0;
6421  var $namespaces = array();
6422  var $message = array();
6423  var $parent = '';
6424  var $fault = false;
6425  var $fault_code = '';
6426  var $fault_str = '';
6427  var $fault_detail = '';
6428  var $depth_array = array();
6429  var $debug_flag = true;
6430  var $soapresponse = NULL; // parsed SOAP Body
6431  var $soapheader = NULL; // parsed SOAP Header
6432  var $responseHeaders = ''; // incoming SOAP headers (text)
6434  // for multiref parsing:
6435  // array of id => pos
6436  var $ids = array();
6437  // array of id => hrefs => pos
6438  var $multirefs = array();
6439  // toggle for auto-decoding element content
6440  var $decode_utf8 = true;
6441 
6451  function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
6453  $this->xml = $xml;
6454  $this->xml_encoding = $encoding;
6455  $this->method = $method;
6456  $this->decode_utf8 = $decode_utf8;
6457 
6458  // Check whether content has been read.
6459  if(!empty($xml)){
6460  // Check XML encoding
6461  $pos_xml = strpos($xml, '<?xml');
6462  if ($pos_xml !== FALSE) {
6463  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6464  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6465  $xml_encoding = $res[1];
6466  if (strtoupper($xml_encoding) != $encoding) {
6467  $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6468  $this->debug($err);
6469  if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6470  $this->setError($err);
6471  return;
6472  }
6473  // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6474  } else {
6475  $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6476  }
6477  } else {
6478  $this->debug('No encoding specified in XML declaration');
6479  }
6480  } else {
6481  $this->debug('No XML declaration');
6482  }
6483  $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
6484  // Create an XML parser - why not xml_parser_create_ns?
6485  $this->parser = xml_parser_create($this->xml_encoding);
6486  // Set the options for parsing the XML data.
6487  //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6488  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6489  xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6490  // Set the object for the parser.
6491  xml_set_object($this->parser, $this);
6492  // Set the element handlers for the parser.
6493  xml_set_element_handler($this->parser, 'start_element','end_element');
6494  xml_set_character_data_handler($this->parser,'character_data');
6495 
6496  // Parse the XML file.
6497  if(!xml_parse($this->parser,$xml,true)){
6498  // Display an error message.
6499  $err = sprintf('XML error parsing SOAP payload on line %d: %s',
6500  xml_get_current_line_number($this->parser),
6501  xml_error_string(xml_get_error_code($this->parser)));
6502  $this->debug($err);
6503  $this->debug("XML payload:\n" . $xml);
6504  $this->setError($err);
6505  } else {
6506  $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
6507  // get final value
6508  $this->soapresponse = $this->message[$this->root_struct]['result'];
6509  // get header value
6510  if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
6511  $this->soapheader = $this->message[$this->root_header]['result'];
6512  }
6513  // resolve hrefs/ids
6514  if(sizeof($this->multirefs) > 0){
6515  foreach($this->multirefs as $id => $hrefs){
6516  $this->debug('resolving multirefs for id: '.$id);
6517  $idVal = $this->buildVal($this->ids[$id]);
6518  if (is_array($idVal) && isset($idVal['!id'])) {
6519  unset($idVal['!id']);
6520  }
6521  foreach($hrefs as $refPos => $ref){
6522  $this->debug('resolving href at pos '.$refPos);
6523  $this->multirefs[$id][$refPos] = $idVal;
6524  }
6525  }
6526  }
6527  }
6528  xml_parser_free($this->parser);
6529  } else {
6530  $this->debug('xml was empty, didn\'t parse!');
6531  $this->setError('xml was empty, didn\'t parse!');
6532  }
6533  }
6534 
6543  function start_element($parser, $name, $attrs) {
6544  // position in a total number of elements, starting from 0
6545  // update class level pos
6546  $pos = $this->position++;
6547  // and set mine
6548  $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
6549  // depth = how many levels removed from root?
6550  // set mine as current global depth and increment global depth value
6551  $this->message[$pos]['depth'] = $this->depth++;
6552 
6553  // else add self as child to whoever the current parent is
6554  if($pos != 0){
6555  $this->message[$this->parent]['children'] .= '|'.$pos;
6556  }
6557  // set my parent
6558  $this->message[$pos]['parent'] = $this->parent;
6559  // set self as current parent
6560  $this->parent = $pos;
6561  // set self as current value for this depth
6562  $this->depth_array[$this->depth] = $pos;
6563  // get element prefix
6564  if(strpos($name,':')){
6565  // get ns prefix
6566  $prefix = substr($name,0,strpos($name,':'));
6567  // get unqualified name
6568  $name = substr(strstr($name,':'),1);
6569  }
6570  // set status
6571  if($name == 'Envelope'){
6572  $this->status = 'envelope';
6573  } elseif($name == 'Header' && $this->status = 'envelope'){
6574  $this->root_header = $pos;
6575  $this->status = 'header';
6576  } elseif($name == 'Body' && $this->status = 'envelope'){
6577  $this->status = 'body';
6578  $this->body_position = $pos;
6579  // set method
6580  } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
6581  $this->status = 'method';
6582  $this->root_struct_name = $name;
6583  $this->root_struct = $pos;
6584  $this->message[$pos]['type'] = 'struct';
6585  $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6586  }
6587  // set my status
6588  $this->message[$pos]['status'] = $this->status;
6589  // set name
6590  $this->message[$pos]['name'] = htmlspecialchars($name);
6591  // set attrs
6592  $this->message[$pos]['attrs'] = $attrs;
6593 
6594  // loop through atts, logging ns and type declarations
6595  $attstr = '';
6596  foreach($attrs as $key => $value){
6597  $key_prefix = $this->getPrefix($key);
6598  $key_localpart = $this->getLocalPart($key);
6599  // if ns declarations, add to class level array of valid namespaces
6600  if($key_prefix == 'xmlns'){
6601  if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){
6602  $this->XMLSchemaVersion = $value;
6603  $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6604  $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
6605  }
6606  $this->namespaces[$key_localpart] = $value;
6607  // set method namespace
6608  if($name == $this->root_struct_name){
6609  $this->methodNamespace = $value;
6610  }
6611  // if it's a type declaration, set type
6612  } elseif($key_localpart == 'type'){
6613  if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6614  // do nothing: already processed arrayType
6615  } else {
6616  $value_prefix = $this->getPrefix($value);
6617  $value_localpart = $this->getLocalPart($value);
6618  $this->message[$pos]['type'] = $value_localpart;
6619  $this->message[$pos]['typePrefix'] = $value_prefix;
6620  if(isset($this->namespaces[$value_prefix])){
6621  $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6622  } else if(isset($attrs['xmlns:'.$value_prefix])) {
6623  $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
6624  }
6625  // should do something here with the namespace of specified type?
6626  }
6627  } elseif($key_localpart == 'arrayType'){
6628  $this->message[$pos]['type'] = 'array';
6629  /* do arrayType ereg here
6630  [1] arrayTypeValue ::= atype asize
6631  [2] atype ::= QName rank*
6632  [3] rank ::= '[' (',')* ']'
6633  [4] asize ::= '[' length~ ']'
6634  [5] length ::= nextDimension* Digit+
6635  [6] nextDimension ::= Digit+ ','
6636  */
6637  $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6638  if(preg_match($expr,$value,$regs)){
6639  $this->message[$pos]['typePrefix'] = $regs[1];
6640  $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6641  if (isset($this->namespaces[$regs[1]])) {
6642  $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6643  } else if (isset($attrs['xmlns:'.$regs[1]])) {
6644  $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
6645  }
6646  $this->message[$pos]['arrayType'] = $regs[2];
6647  $this->message[$pos]['arraySize'] = $regs[3];
6648  $this->message[$pos]['arrayCols'] = $regs[4];
6649  }
6650  // specifies nil value (or not)
6651  } elseif ($key_localpart == 'nil'){
6652  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6653  // some other attribute
6654  } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6655  $this->message[$pos]['xattrs']['!' . $key] = $value;
6656  }
6657 
6658  if ($key == 'xmlns') {
6659  $this->default_namespace = $value;
6660  }
6661  // log id
6662  if($key == 'id'){
6663  $this->ids[$value] = $pos;
6664  }
6665  // root
6666  if($key_localpart == 'root' && $value == 1){
6667  $this->status = 'method';
6668  $this->root_struct_name = $name;
6669  $this->root_struct = $pos;
6670  $this->debug("found root struct $this->root_struct_name, pos $pos");
6671  }
6672  // for doclit
6673  $attstr .= " $key=\"$value\"";
6674  }
6675  // get namespace - must be done after namespace atts are processed
6676  if(isset($prefix)){
6677  $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6678  $this->default_namespace = $this->namespaces[$prefix];
6679  } else {
6680  $this->message[$pos]['namespace'] = $this->default_namespace;
6681  }
6682  if($this->status == 'header'){
6683  if ($this->root_header != $pos) {
6684  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6685  }
6686  } elseif($this->root_struct_name != ''){
6687  $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6688  }
6689  }
6690 
6698  function end_element($parser, $name) {
6699  // position of current element is equal to the last value left in depth_array for my depth
6700  $pos = $this->depth_array[$this->depth--];
6701 
6702  // get element prefix
6703  if(strpos($name,':')){
6704  // get ns prefix
6705  $prefix = substr($name,0,strpos($name,':'));
6706  // get unqualified name
6707  $name = substr(strstr($name,':'),1);
6708  }
6709 
6710  // build to native type
6711  if(isset($this->body_position) && $pos > $this->body_position){
6712  // deal w/ multirefs
6713  if(isset($this->message[$pos]['attrs']['href'])){
6714  // get id
6715  $id = substr($this->message[$pos]['attrs']['href'],1);
6716  // add placeholder to href array
6717  $this->multirefs[$id][$pos] = 'placeholder';
6718  // add set a reference to it as the result value
6719  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6720  // build complexType values
6721  } elseif($this->message[$pos]['children'] != ''){
6722  // if result has already been generated (struct/array)
6723  if(!isset($this->message[$pos]['result'])){
6724  $this->message[$pos]['result'] = $this->buildVal($pos);
6725  }
6726  // build complexType values of attributes and possibly simpleContent
6727  } elseif (isset($this->message[$pos]['xattrs'])) {
6728  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6729  $this->message[$pos]['xattrs']['!'] = null;
6730  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6731  if (isset($this->message[$pos]['type'])) {
6732  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6733  } else {
6734  $parent = $this->message[$pos]['parent'];
6735  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6736  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6737  } else {
6738  $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6739  }
6740  }
6741  }
6742  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6743  // set value of simpleType (or nil complexType)
6744  } else {
6745  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
6746  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6747  $this->message[$pos]['xattrs']['!'] = null;
6748  } elseif (isset($this->message[$pos]['type'])) {
6749  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6750  } else {
6751  $parent = $this->message[$pos]['parent'];
6752  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6753  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6754  } else {
6755  $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
6756  }
6757  }
6758 
6759  /* add value to parent's result, if parent is struct/array
6760  $parent = $this->message[$pos]['parent'];
6761  if($this->message[$parent]['type'] != 'map'){
6762  if(strtolower($this->message[$parent]['type']) == 'array'){
6763  $this->message[$parent]['result'][] = $this->message[$pos]['result'];
6764  } else {
6765  $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
6766  }
6767  }
6768  */
6769  }
6770  }
6771 
6772  // for doclit
6773  if($this->status == 'header'){
6774  if ($this->root_header != $pos) {
6775  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6776  }
6777  } elseif($pos >= $this->root_struct){
6778  $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6779  }
6780  // switch status
6781  if($pos == $this->root_struct){
6782  $this->status = 'body';
6783  $this->root_struct_namespace = $this->message[$pos]['namespace'];
6784  } elseif($name == 'Body'){
6785  $this->status = 'envelope';
6786  } elseif($name == 'Header'){
6787  $this->status = 'envelope';
6788  } elseif($name == 'Envelope'){
6789  //
6790  }
6791  // set parent back to my parent
6792  $this->parent = $this->message[$pos]['parent'];
6793  }
6794 
6802  function character_data($parser, $data){
6803  $pos = $this->depth_array[$this->depth];
6804  if ($this->xml_encoding=='UTF-8'){
6805  // TODO: add an option to disable this for folks who want
6806  // raw UTF-8 that, e.g., might not map to iso-8859-1
6807  // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
6808  if($this->decode_utf8){
6809  $data = utf8_decode($data);
6810  }
6811  }
6812  $this->message[$pos]['cdata'] .= $data;
6813  // for doclit
6814  if($this->status == 'header'){
6815  $this->responseHeaders .= $data;
6816  } else {
6817  $this->document .= $data;
6818  }
6819  }
6820 
6828  function get_response(){
6829  return $this->soapresponse;
6830  }
6831 
6838  function get_soapbody(){
6839  return $this->soapresponse;
6840  }
6841 
6848  function get_soapheader(){
6849  return $this->soapheader;
6850  }
6851 
6858  function getHeaders(){
6859  return $this->responseHeaders;
6860  }
6861 
6871  function decodeSimple($value, $type, $typens) {
6872  // TODO: use the namespace!
6873  if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
6874  return (string) $value;
6875  }
6876  if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
6877  return (int) $value;
6878  }
6879  if ($type == 'float' || $type == 'double' || $type == 'decimal') {
6880  return (double) $value;
6881  }
6882  if ($type == 'boolean') {
6883  if (strtolower($value) == 'false' || strtolower($value) == 'f') {
6884  return false;
6885  }
6886  return (boolean) $value;
6887  }
6888  if ($type == 'base64' || $type == 'base64Binary') {
6889  $this->debug('Decode base64 value');
6890  return base64_decode($value);
6891  }
6892  // obscure numeric types
6893  if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
6894  || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
6895  || $type == 'unsignedInt'
6896  || $type == 'unsignedShort' || $type == 'unsignedByte') {
6897  return (int) $value;
6898  }
6899  // bogus: parser treats array with no elements as a simple type
6900  if ($type == 'array') {
6901  return array();
6902  }
6903  // everything else
6904  return (string) $value;
6905  }
6906 
6915  function buildVal($pos){
6916  if(!isset($this->message[$pos]['type'])){
6917  $this->message[$pos]['type'] = '';
6918  }
6919  $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
6920  // if there are children...
6921  if($this->message[$pos]['children'] != ''){
6922  $this->debug('in buildVal, there are children');
6923  $children = explode('|',$this->message[$pos]['children']);
6924  array_shift($children); // knock off empty
6925  // md array
6926  if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
6927  $r=0; // rowcount
6928  $c=0; // colcount
6929  foreach($children as $child_pos){
6930  $this->debug("in buildVal, got an MD array element: $r, $c");
6931  $params[$r][] = $this->message[$child_pos]['result'];
6932  $c++;
6933  if($c == $this->message[$pos]['arrayCols']){
6934  $c = 0;
6935  $r++;
6936  }
6937  }
6938  // array
6939  } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
6940  $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
6941  foreach($children as $child_pos){
6942  $params[] = &$this->message[$child_pos]['result'];
6943  }
6944  // apache Map type: java hashtable
6945  } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
6946  $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
6947  foreach($children as $child_pos){
6948  $kv = explode("|",$this->message[$child_pos]['children']);
6949  $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
6950  }
6951  // generic compound type
6952  //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
6953  } else {
6954  // Apache Vector type: treat as an array
6955  $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
6956  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
6957  $notstruct = 1;
6958  } else {
6959  $notstruct = 0;
6960  }
6961  //
6962  foreach($children as $child_pos){
6963  if($notstruct){
6964  $params[] = &$this->message[$child_pos]['result'];
6965  } else {
6966  if (isset($params[$this->message[$child_pos]['name']])) {
6967  // de-serialize repeated element name into an array
6968  if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
6969  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
6970  }
6971  $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
6972  } else {
6973  $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
6974  }
6975  }
6976  }
6977  }
6978  if (isset($this->message[$pos]['xattrs'])) {
6979  $this->debug('in buildVal, handling attributes');
6980  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
6981  $params[$n] = $v;
6982  }
6983  }
6984  // handle simpleContent
6985  if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6986  $this->debug('in buildVal, handling simpleContent');
6987  if (isset($this->message[$pos]['type'])) {
6988  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6989  } else {
6990  $parent = $this->message[$pos]['parent'];
6991  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6992  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6993  } else {
6994  $params['!'] = $this->message[$pos]['cdata'];
6995  }
6996  }
6997  }
6998  $ret = is_array($params) ? $params : array();
6999  $this->debug('in buildVal, return:');
7000  $this->appendDebug($this->varDump($ret));
7001  return $ret;
7002  } else {
7003  $this->debug('in buildVal, no children, building scalar');
7004  $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7005  if (isset($this->message[$pos]['type'])) {
7006  $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7007  $this->debug("in buildVal, return: $ret");
7008  return $ret;
7009  }
7010  $parent = $this->message[$pos]['parent'];
7011  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7012  $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7013  $this->debug("in buildVal, return: $ret");
7014  return $ret;
7015  }
7016  $ret = $this->message[$pos]['cdata'];
7017  $this->debug("in buildVal, return: $ret");
7018  return $ret;
7019  }
7020  }
7021 }
7022 
7026 class soap_parser extends nusoap_parser {
7027 }
7028 
7029 ?><?php
7030 
7031 
7032 
7054 
7055  var $username = ''; // Username for HTTP authentication
7056  var $password = ''; // Password for HTTP authentication
7057  var $authtype = ''; // Type of HTTP authentication
7058  var $certRequest = array(); // Certificate for HTTP SSL authentication
7059  var $requestHeaders = false; // SOAP headers in request (text)
7060  var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7061  var $responseHeader = NULL; // SOAP Header from response (parsed)
7062  var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7064  var $forceEndpoint = ''; // overrides WSDL endpoint
7065  var $proxyhost = '';
7066  var $proxyport = '';
7067  var $proxyusername = '';
7068  var $proxypassword = '';
7069  var $xml_encoding = ''; // character set encoding of incoming (response) messages
7070  var $http_encoding = false;
7071  var $timeout = 0; // HTTP connection timeout
7072  var $response_timeout = 30; // HTTP response timeout
7073  var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7075  var $defaultRpcParams = false; // This is no longer used
7076  var $request = ''; // HTTP request
7077  var $response = ''; // HTTP response
7078  var $responseData = ''; // SOAP payload of response
7079  var $cookies = array(); // Cookies from response or for request
7080  var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7081  var $operations = array(); // WSDL operations, empty for WSDL initialization error
7082  var $curl_options = array(); // User-specified cURL options
7083  var $bindingType = ''; // WSDL operation binding type
7084  var $use_curl = false; // whether to always try to use cURL
7085 
7086  /*
7087  * fault related variables
7088  */
7093  var $fault;
7109 
7124  function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
7126  $this->endpoint = $endpoint;
7127  $this->proxyhost = $proxyhost;
7128  $this->proxyport = $proxyport;
7129  $this->proxyusername = $proxyusername;
7130  $this->proxypassword = $proxypassword;
7131  $this->timeout = $timeout;
7132  $this->response_timeout = $response_timeout;
7133 
7134  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7135  $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7136 
7137  // make values
7138  if($wsdl){
7139  if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
7140  $this->wsdl = $endpoint;
7141  $this->endpoint = $this->wsdl->wsdl;
7142  $this->wsdlFile = $this->endpoint;
7143  $this->debug('existing wsdl instance created from ' . $this->endpoint);
7144  $this->checkWSDL();
7145  } else {
7146  $this->wsdlFile = $this->endpoint;
7147  $this->wsdl = null;
7148  $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7149  }
7150  $this->endpointType = 'wsdl';
7151  } else {
7152  $this->debug("instantiate SOAP with endpoint at $endpoint");
7153  $this->endpointType = 'soap';
7154  }
7155  }
7156 
7182  function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
7183  $this->operation = $operation;
7184  $this->fault = false;
7185  $this->setError('');
7186  $this->request = '';
7187  $this->response = '';
7188  $this->responseData = '';
7189  $this->faultstring = '';
7190  $this->faultcode = '';
7191  $this->opData = array();
7192 
7193  $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7194  $this->appendDebug('params=' . $this->varDump($params));
7195  $this->appendDebug('headers=' . $this->varDump($headers));
7196  if ($headers) {
7197  $this->requestHeaders = $headers;
7198  }
7199  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7200  $this->loadWSDL();
7201  if ($this->getError())
7202  return false;
7203  }
7204  // serialize parameters
7205  if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
7206  // use WSDL for operation
7207  $this->opData = $opData;
7208  $this->debug("found operation");
7209  $this->appendDebug('opData=' . $this->varDump($opData));
7210  if (isset($opData['soapAction'])) {
7211  $soapAction = $opData['soapAction'];
7212  }
7213  if (! $this->forceEndpoint) {
7214  $this->endpoint = $opData['endpoint'];
7215  } else {
7216  $this->endpoint = $this->forceEndpoint;
7217  }
7218  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7219  $style = $opData['style'];
7220  $use = $opData['input']['use'];
7221  // add ns to ns array
7222  if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
7223  $nsPrefix = 'ns' . rand(1000, 9999);
7224  $this->wsdl->namespaces[$nsPrefix] = $namespace;
7225  }
7226  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7227  // serialize payload
7228  if (is_string($params)) {
7229  $this->debug("serializing param string for WSDL operation $operation");
7230  $payload = $params;
7231  } elseif (is_array($params)) {
7232  $this->debug("serializing param array for WSDL operation $operation");
7233  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
7234  } else {
7235  $this->debug('params must be array or string');
7236  $this->setError('params must be array or string');
7237  return false;
7238  }
7239  $usedNamespaces = $this->wsdl->usedNamespaces;
7240  if (isset($opData['input']['encodingStyle'])) {
7241  $encodingStyle = $opData['input']['encodingStyle'];
7242  } else {
7243  $encodingStyle = '';
7244  }
7245  $this->appendDebug($this->wsdl->getDebug());
7246  $this->wsdl->clearDebug();
7247  if ($errstr = $this->wsdl->getError()) {
7248  $this->debug('got wsdl error: '.$errstr);
7249  $this->setError('wsdl error: '.$errstr);
7250  return false;
7251  }
7252  } elseif($this->endpointType == 'wsdl') {
7253  // operation not in WSDL
7254  $this->appendDebug($this->wsdl->getDebug());
7255  $this->wsdl->clearDebug();
7256  $this->setError( 'operation '.$operation.' not present.');
7257  $this->debug("operation '$operation' not present.");
7258  return false;
7259  } else {
7260  // no WSDL
7261  //$this->namespaces['ns1'] = $namespace;
7262  $nsPrefix = 'ns' . rand(1000, 9999);
7263  // serialize
7264  $payload = '';
7265  if (is_string($params)) {
7266  $this->debug("serializing param string for operation $operation");
7267  $payload = $params;
7268  } elseif (is_array($params)) {
7269  $this->debug("serializing param array for operation $operation");
7270  foreach($params as $k => $v){
7271  $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
7272  }
7273  } else {
7274  $this->debug('params must be array or string');
7275  $this->setError('params must be array or string');
7276  return false;
7277  }
7278  $usedNamespaces = array();
7279  if ($use == 'encoded') {
7280  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7281  } else {
7282  $encodingStyle = '';
7283  }
7284  }
7285  // wrap RPC calls with method element
7286  if ($style == 'rpc') {
7287  if ($use == 'literal') {
7288  $this->debug("wrapping RPC request with literal method element");
7289  if ($namespace) {
7290  // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
7291  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7292  $payload .
7293  "</$nsPrefix:$operation>";
7294  } else {
7295  $payload = "<$operation>" . $payload . "</$operation>";
7296  }
7297  } else {
7298  $this->debug("wrapping RPC request with encoded method element");
7299  if ($namespace) {
7300  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7301  $payload .
7302  "</$nsPrefix:$operation>";
7303  } else {
7304  $payload = "<$operation>" .
7305  $payload .
7306  "</$operation>";
7307  }
7308  }
7309  }
7310  // serialize envelope
7311  $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
7312  $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7313  $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7314  // send
7315  $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
7316  if($errstr = $this->getError()){
7317  $this->debug('Error: '.$errstr);
7318  return false;
7319  } else {
7320  $this->return = $return;
7321  $this->debug('sent message successfully and got a(n) '.gettype($return));
7322  $this->appendDebug('return=' . $this->varDump($return));
7323 
7324  // fault?
7325  if(is_array($return) && isset($return['faultcode'])){
7326  $this->debug('got fault');
7327  $this->setError($return['faultcode'].': '.$return['faultstring']);
7328  $this->fault = true;
7329  foreach($return as $k => $v){
7330  $this->$k = $v;
7331  $this->debug("$k = $v<br>");
7332  }
7333  return $return;
7334  } elseif ($style == 'document') {
7335  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7336  // we are only going to return the first part here...sorry about that
7337  return $return;
7338  } else {
7339  // array of return values
7340  if(is_array($return)){
7341  // multiple 'out' parameters, which we return wrapped up
7342  // in the array
7343  if(sizeof($return) > 1){
7344  return $return;
7345  }
7346  // single 'out' parameter (normally the return value)
7347  $return = array_shift($return);
7348  $this->debug('return shifted value: ');
7349  $this->appendDebug($this->varDump($return));
7350  return $return;
7351  // nothing returned (ie, echoVoid)
7352  } else {
7353  return "";
7354  }
7355  }
7356  }
7357  }
7358 
7364  function checkWSDL() {
7365  $this->appendDebug($this->wsdl->getDebug());
7366  $this->wsdl->clearDebug();
7367  $this->debug('checkWSDL');
7368  // catch errors
7369  if ($errstr = $this->wsdl->getError()) {
7370  $this->debug('got wsdl error: '.$errstr);
7371  $this->setError('wsdl error: '.$errstr);
7372  } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
7373  $this->bindingType = 'soap';
7374  $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7375  } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
7376  $this->bindingType = 'soap12';
7377  $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7378  $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7379  } else {
7380  $this->debug('getOperations returned false');
7381  $this->setError('no operations defined in the WSDL document!');
7382  }
7383  }
7384 
7390  function loadWSDL() {
7391  $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
7392  $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
7393  $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7394  $this->wsdl->fetchWSDL($this->wsdlFile);
7395  $this->checkWSDL();
7396  }
7397 
7405  function getOperationData($operation){
7406  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7407  $this->loadWSDL();
7408  if ($this->getError())
7409  return false;
7410  }
7411  if(isset($this->operations[$operation])){
7412  return $this->operations[$operation];
7413  }
7414  $this->debug("No data for operation: $operation");
7415  }
7416 
7431  function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
7432  $this->checkCookies();
7433  // detect transport
7434  switch(true){
7435  // http(s)
7436  case preg_match('/^http/',$this->endpoint):
7437  $this->debug('transporting via HTTP');
7438  if($this->persistentConnection == true && is_object($this->persistentConnection)){
7439  $http =& $this->persistentConnection;
7440  } else {
7441  $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7442  if ($this->persistentConnection) {
7443  $http->usePersistentConnection();
7444  }
7445  }
7446  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7447  $http->setSOAPAction($soapaction);
7448  if($this->proxyhost && $this->proxyport){
7449  $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
7450  }
7451  if($this->authtype != '') {
7452  $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
7453  }
7454  if($this->http_encoding != ''){
7455  $http->setEncoding($this->http_encoding);
7456  }
7457  $this->debug('sending message, length='.strlen($msg));
7458  if(preg_match('/^http:/',$this->endpoint)){
7459  //if(strpos($this->endpoint,'http:')){
7460  $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
7461  } elseif(preg_match('/^https/',$this->endpoint)){
7462  //} elseif(strpos($this->endpoint,'https:')){
7463  //if(phpversion() == '4.3.0-dev'){
7464  //$response = $http->send($msg,$timeout,$response_timeout);
7465  //$this->request = $http->outgoing_payload;
7466  //$this->response = $http->incoming_payload;
7467  //} else
7468  $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
7469  } else {
7470  $this->setError('no http/s in endpoint url');
7471  }
7472  $this->request = $http->outgoing_payload;
7473  $this->response = $http->incoming_payload;
7474  $this->appendDebug($http->getDebug());
7475  $this->UpdateCookies($http->incoming_cookies);
7476 
7477  // save transport object if using persistent connections
7478  if ($this->persistentConnection) {
7479  $http->clearDebug();
7480  if (!is_object($this->persistentConnection)) {
7481  $this->persistentConnection = $http;
7482  }
7483  }
7484 
7485  if($err = $http->getError()){
7486  $this->setError('HTTP Error: '.$err);
7487  return false;
7488  } elseif($this->getError()){
7489  return false;
7490  } else {
7491  $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
7492  return $this->parseResponse($http->incoming_headers, $this->responseData);
7493  }
7494  break;
7495  default:
7496  $this->setError('no transport found, or selected transport is not yet supported!');
7497  return false;
7498  break;
7499  }
7500  }
7501 
7510  function parseResponse($headers, $data) {
7511  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7512  $this->appendDebug($this->varDump($headers));
7513  if (!strstr($headers['content-type'], 'text/xml')) {
7514  $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7515  return false;
7516  }
7517  if (strpos($headers['content-type'], '=')) {
7518  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
7519  $this->debug('Got response encoding: ' . $enc);
7520  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
7521  $this->xml_encoding = strtoupper($enc);
7522  } else {
7523  $this->xml_encoding = 'US-ASCII';
7524  }
7525  } else {
7526  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7527  $this->xml_encoding = 'ISO-8859-1';
7528  }
7529  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7530  $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
7531  // add parser debug data to our debug
7532  $this->appendDebug($parser->getDebug());
7533  // if parse errors
7534  if($errstr = $parser->getError()){
7535  $this->setError( $errstr);
7536  // destroy the parser object
7537  unset($parser);
7538  return false;
7539  } else {
7540  // get SOAP headers
7541  $this->responseHeaders = $parser->getHeaders();
7542  // get SOAP headers
7543  $this->responseHeader = $parser->get_soapheader();
7544  // get decoded message
7545  $return = $parser->get_soapbody();
7546  // add document for doclit support
7547  $this->document = $parser->document;
7548  // destroy the parser object
7549  unset($parser);
7550  // return decode message
7551  return $return;
7552  }
7553  }
7554 
7562  function setCurlOption($option, $value) {
7563  $this->debug("setCurlOption option=$option, value=");
7564  $this->appendDebug($this->varDump($value));
7565  $this->curl_options[$option] = $value;
7566  }
7567 
7575  $this->debug("setEndpoint(\"$endpoint\")");
7576  $this->forceEndpoint = $endpoint;
7577  }
7578 
7585  function setHeaders($headers){
7586  $this->debug("setHeaders headers=");
7587  $this->appendDebug($this->varDump($headers));
7588  $this->requestHeaders = $headers;
7589  }
7590 
7597  function getHeaders(){
7598  return $this->responseHeaders;
7599  }
7600 
7607  function getHeader(){
7608  return $this->responseHeader;
7609  }
7610 
7621  $this->proxyhost = $proxyhost;
7622  $this->proxyport = $proxyport;
7623  $this->proxyusername = $proxyusername;
7624  $this->proxypassword = $proxypassword;
7625  }
7626 
7636  function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
7637  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7638  $this->appendDebug($this->varDump($certRequest));
7639  $this->username = $username;
7640  $this->password = $password;
7641  $this->authtype = $authtype;
7642  $this->certRequest = $certRequest;
7643  }
7644 
7651  function setHTTPEncoding($enc='gzip, deflate'){
7652  $this->debug("setHTTPEncoding(\"$enc\")");
7653  $this->http_encoding = $enc;
7654  }
7655 
7662  function setUseCURL($use) {
7663  $this->debug("setUseCURL($use)");
7664  $this->use_curl = $use;
7665  }
7666 
7673  $this->debug("useHTTPPersistentConnection");
7674  $this->persistentConnection = true;
7675  }
7676 
7688  function getDefaultRpcParams() {
7689  return $this->defaultRpcParams;
7690  }
7691 
7703  function setDefaultRpcParams($rpcParams) {
7704  $this->defaultRpcParams = $rpcParams;
7705  }
7706 
7714  function getProxy() {
7715  $r = rand();
7716  $evalStr = $this->_getProxyClassCode($r);
7717  //$this->debug("proxy class: $evalStr");
7718  if ($this->getError()) {
7719  $this->debug("Error from _getProxyClassCode, so return NULL");
7720  return null;
7721  }
7722  // eval the class
7723  eval($evalStr);
7724  // instantiate proxy object
7725  eval("\$proxy = new nusoap_proxy_$r('');");
7726  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
7727  $proxy->endpointType = 'wsdl';
7728  $proxy->wsdlFile = $this->wsdlFile;
7729  $proxy->wsdl = $this->wsdl;
7730  $proxy->operations = $this->operations;
7731  $proxy->defaultRpcParams = $this->defaultRpcParams;
7732  // transfer other state
7733  $proxy->soap_defencoding = $this->soap_defencoding;
7734  $proxy->username = $this->username;
7735  $proxy->password = $this->password;
7736  $proxy->authtype = $this->authtype;
7737  $proxy->certRequest = $this->certRequest;
7738  $proxy->requestHeaders = $this->requestHeaders;
7739  $proxy->endpoint = $this->endpoint;
7740  $proxy->forceEndpoint = $this->forceEndpoint;
7741  $proxy->proxyhost = $this->proxyhost;
7742  $proxy->proxyport = $this->proxyport;
7743  $proxy->proxyusername = $this->proxyusername;
7744  $proxy->proxypassword = $this->proxypassword;
7745  $proxy->http_encoding = $this->http_encoding;
7746  $proxy->timeout = $this->timeout;
7747  $proxy->response_timeout = $this->response_timeout;
7748  $proxy->persistentConnection = &$this->persistentConnection;
7749  $proxy->decode_utf8 = $this->decode_utf8;
7750  $proxy->curl_options = $this->curl_options;
7751  $proxy->bindingType = $this->bindingType;
7752  $proxy->use_curl = $this->use_curl;
7753  return $proxy;
7754  }
7755 
7762  function _getProxyClassCode($r) {
7763  $this->debug("in getProxy endpointType=$this->endpointType");
7764  $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
7765  if ($this->endpointType != 'wsdl') {
7766  $evalStr = 'A proxy can only be created for a WSDL client';
7767  $this->setError($evalStr);
7768  $evalStr = "echo \"$evalStr\";";
7769  return $evalStr;
7770  }
7771  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7772  $this->loadWSDL();
7773  if ($this->getError()) {
7774  return "echo \"" . $this->getError() . "\";";
7775  }
7776  }
7777  $evalStr = '';
7778  foreach ($this->operations as $operation => $opData) {
7779  if ($operation != '') {
7780  // create param string and param comment string
7781  if (sizeof($opData['input']['parts']) > 0) {
7782  $paramStr = '';
7783  $paramArrayStr = '';
7784  $paramCommentStr = '';
7785  foreach ($opData['input']['parts'] as $name => $type) {
7786  $paramStr .= "\$$name, ";
7787  $paramArrayStr .= "'$name' => \$$name, ";
7788  $paramCommentStr .= "$type \$$name, ";
7789  }
7790  $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
7791  $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
7792  $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
7793  } else {
7794  $paramStr = '';
7795  $paramArrayStr = '';
7796  $paramCommentStr = 'void';
7797  }
7798  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7799  $evalStr .= "// $paramCommentStr
7800  function " . str_replace('.', '__', $operation) . "($paramStr) {
7801  \$params = array($paramArrayStr);
7802  return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
7803  }
7804  ";
7805  unset($paramStr);
7806  unset($paramCommentStr);
7807  }
7808  }
7809  $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
7810  '.$evalStr.'
7811 }';
7812  return $evalStr;
7813  }
7814 
7821  function getProxyClassCode() {
7822  $r = rand();
7823  return $this->_getProxyClassCode($r);
7824  }
7825 
7833  function getHTTPBody($soapmsg) {
7834  return $soapmsg;
7835  }
7836 
7845  function getHTTPContentType() {
7846  return 'text/xml';
7847  }
7848 
7859  return $this->soap_defencoding;
7860  }
7861 
7862  /*
7863  * whether or not parser should decode utf8 element content
7864  *
7865  * @return always returns true
7866  * @access public
7867  */
7868  function decodeUTF8($bool){
7869  $this->decode_utf8 = $bool;
7870  return true;
7871  }
7872 
7881  function setCookie($name, $value) {
7882  if (strlen($name) == 0) {
7883  return false;
7884  }
7885  $this->cookies[] = array('name' => $name, 'value' => $value);
7886  return true;
7887  }
7888 
7895  function getCookies() {
7896  return $this->cookies;
7897  }
7898 
7905  function checkCookies() {
7906  if (sizeof($this->cookies) == 0) {
7907  return true;
7908  }
7909  $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
7910  $curr_cookies = $this->cookies;
7911  $this->cookies = array();
7912  foreach ($curr_cookies as $cookie) {
7913  if (! is_array($cookie)) {
7914  $this->debug('Remove cookie that is not an array');
7915  continue;
7916  }
7917  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
7918  if (strtotime($cookie['expires']) > time()) {
7919  $this->cookies[] = $cookie;
7920  } else {
7921  $this->debug('Remove expired cookie ' . $cookie['name']);
7922  }
7923  } else {
7924  $this->cookies[] = $cookie;
7925  }
7926  }
7927  $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
7928  return true;
7929  }
7930 
7939  if (sizeof($this->cookies) == 0) {
7940  // no existing cookies: take whatever is new
7941  if (sizeof($cookies) > 0) {
7942  $this->debug('Setting new cookie(s)');
7943  $this->cookies = $cookies;
7944  }
7945  return true;
7946  }
7947  if (sizeof($cookies) == 0) {
7948  // no new cookies: keep what we've got
7949  return true;
7950  }
7951  // merge
7952  foreach ($cookies as $newCookie) {
7953  if (!is_array($newCookie)) {
7954  continue;
7955  }
7956  if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
7957  continue;
7958  }
7959  $newName = $newCookie['name'];
7960 
7961  $found = false;
7962  for ($i = 0; $i < count($this->cookies); $i++) {
7963  $cookie = $this->cookies[$i];
7964  if (!is_array($cookie)) {
7965  continue;
7966  }
7967  if (!isset($cookie['name'])) {
7968  continue;
7969  }
7970  if ($newName != $cookie['name']) {
7971  continue;
7972  }
7973  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
7974  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
7975  if ($newDomain != $domain) {
7976  continue;
7977  }
7978  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
7979  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
7980  if ($newPath != $path) {
7981  continue;
7982  }
7983  $this->cookies[$i] = $newCookie;
7984  $found = true;
7985  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
7986  break;
7987  }
7988  if (! $found) {
7989  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
7990  $this->cookies[] = $newCookie;
7991  }
7992  }
7993  return true;
7994  }
7995 }
7996 
7997 if (!extension_loaded('soap')) {
8001  class soapclient extends nusoap_client {
8002  }
8003 }
8004 ?>