ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
nusoap.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4 $Id$
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 
76 // alex patch: we need an object here, otherwise we will get a warning in php 5.4
77 if (!is_object($GLOBALS['_transient']['static']['nusoap_base']))
78 {
79  $GLOBALS['_transient']['static']['nusoap_base'] = new stdClass();
80 }
81 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 0;
82 
92 class nusoap_base {
99  var $title = 'NuSOAP';
106  var $version = '0.7.3';
113  var $revision = '$Revision$';
120  var $error_str = '';
127  var $debug_str = '';
135  var $charencoding = true;
143 
150  var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
151 
158  //var $soap_defencoding = 'ISO-8859-1';
159  var $soap_defencoding = 'UTF-8';
160 
169  var $namespaces = array(
170  'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
171  'xsd' => 'http://www.w3.org/2001/XMLSchema',
172  'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
173  'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
174  );
175 
182  var $usedNamespaces = array();
183 
191  var $typemap = array(
192  'http://www.w3.org/2001/XMLSchema' => array(
193  'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
194  'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
195  'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
196  // abstract "any" types
197  'anyType'=>'string','anySimpleType'=>'string',
198  // derived datatypes
199  'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
200  'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
201  'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
202  'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
203  'http://www.w3.org/2000/10/XMLSchema' => array(
204  'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
205  'float'=>'double','dateTime'=>'string',
206  'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
207  'http://www.w3.org/1999/XMLSchema' => array(
208  'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
209  'float'=>'double','dateTime'=>'string',
210  'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
211  'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
212  'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
213  'http://xml.apache.org/xml-soap' => array('Map')
214  );
215 
224  var $xmlEntities = array('quot' => '"','amp' => '&',
225  'lt' => '<','gt' => '>','apos' => "'");
226 
232  function nusoap_base() {
233  $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
234  }
235 
242  function getGlobalDebugLevel() {
243  return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
244  }
245 
252  function setGlobalDebugLevel($level) {
253  $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
254  }
255 
262  function getDebugLevel() {
263  return $this->debugLevel;
264  }
265 
272  function setDebugLevel($level) {
273  $this->debugLevel = $level;
274  }
275 
282  function debug($string){
283  if ($this->debugLevel > 0) {
284  $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
285  }
286  }
287 
294  function appendDebug($string){
295  if ($this->debugLevel > 0) {
296  // it would be nice to use a memory stream here to use
297  // memory more efficiently
298  $this->debug_str .= $string;
299  }
300  }
301 
307  function clearDebug() {
308  // it would be nice to use a memory stream here to use
309  // memory more efficiently
310  $this->debug_str = '';
311  }
312 
319  function &getDebug() {
320  // it would be nice to use a memory stream here to use
321  // memory more efficiently
322  return $this->debug_str;
323  }
324 
332  function &getDebugAsXMLComment() {
333  // it would be nice to use a memory stream here to use
334  // memory more efficiently
335  while (strpos($this->debug_str, '--')) {
336  $this->debug_str = str_replace('--', '- -', $this->debug_str);
337  }
338  $ret = "<!--\n" . $this->debug_str . "\n-->";
339  return $ret;
340  }
341 
348  function expandEntities($val) {
349  if ($this->charencoding) {
350  $val = str_replace('&', '&amp;', $val);
351  $val = str_replace("'", '&apos;', $val);
352  $val = str_replace('"', '&quot;', $val);
353  $val = str_replace('<', '&lt;', $val);
354  $val = str_replace('>', '&gt;', $val);
355  }
356  return $val;
357  }
358 
365  function getError(){
366  if($this->error_str != ''){
367  return $this->error_str;
368  }
369  return false;
370  }
371 
378  function setError($str){
379  $this->error_str = $str;
380  }
381 
389  function isArraySimpleOrStruct($val) {
390  $keyList = array_keys($val);
391  foreach ($keyList as $keyListValue) {
392  if (!is_int($keyListValue)) {
393  return 'arrayStruct';
394  }
395  }
396  return 'arraySimple';
397  }
398 
414  function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
415  $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
416  $this->appendDebug('value=' . $this->varDump($val));
417  $this->appendDebug('attributes=' . $this->varDump($attributes));
418 
419  if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
420  $this->debug("serialize_val: serialize soapval");
421  $xml = $val->serialize($use);
422  $this->appendDebug($val->getDebug());
423  $val->clearDebug();
424  $this->debug("serialize_val of soapval returning $xml");
425  return $xml;
426  }
427  // force valid name if necessary
428  if (is_numeric($name)) {
429  $name = '__numeric_' . $name;
430  } elseif (! $name) {
431  $name = 'noname';
432  }
433  // if name has ns, add ns prefix to name
434  $xmlns = '';
435  if($name_ns){
436  $prefix = 'nu'.rand(1000,9999);
437  $name = $prefix.':'.$name;
438  $xmlns .= " xmlns:$prefix=\"$name_ns\"";
439  }
440  // if type is prefixed, create type prefix
441  if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
442  // need to fix this. shouldn't default to xsd if no ns specified
443  // w/o checking against typemap
444  $type_prefix = 'xsd';
445  } elseif($type_ns){
446  $type_prefix = 'ns'.rand(1000,9999);
447  $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
448  }
449  // serialize attributes if present
450  $atts = '';
451  if($attributes){
452  foreach($attributes as $k => $v){
453  $atts .= " $k=\"".$this->expandEntities($v).'"';
454  }
455  }
456  // serialize null value
457  if (is_null($val)) {
458  $this->debug("serialize_val: serialize null");
459  if ($use == 'literal') {
460  // TODO: depends on minOccurs
461  $xml = "<$name$xmlns$atts/>";
462  $this->debug("serialize_val returning $xml");
463  return $xml;
464  } else {
465  if (isset($type) && isset($type_prefix)) {
466  $type_str = " xsi:type=\"$type_prefix:$type\"";
467  } else {
468  $type_str = '';
469  }
470  $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
471  $this->debug("serialize_val returning $xml");
472  return $xml;
473  }
474  }
475  // serialize if an xsd built-in primitive type
476  if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
477  $this->debug("serialize_val: serialize xsd built-in primitive type");
478  if (is_bool($val)) {
479  if ($type == 'boolean') {
480  $val = $val ? 'true' : 'false';
481  } elseif (! $val) {
482  $val = 0;
483  }
484  } else if (is_string($val)) {
485  $val = $this->expandEntities($val);
486  }
487  if ($use == 'literal') {
488  $xml = "<$name$xmlns$atts>$val</$name>";
489  $this->debug("serialize_val returning $xml");
490  return $xml;
491  } else {
492  $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
493  $this->debug("serialize_val returning $xml");
494  return $xml;
495  }
496  }
497  // detect type and serialize
498  $xml = '';
499  switch(true) {
500  case (is_bool($val) || $type == 'boolean'):
501  $this->debug("serialize_val: serialize boolean");
502  if ($type == 'boolean') {
503  $val = $val ? 'true' : 'false';
504  } elseif (! $val) {
505  $val = 0;
506  }
507  if ($use == 'literal') {
508  $xml .= "<$name$xmlns$atts>$val</$name>";
509  } else {
510  $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
511  }
512  break;
513  case (is_int($val) || is_long($val) || $type == 'int'):
514  $this->debug("serialize_val: serialize int");
515  if ($use == 'literal') {
516  $xml .= "<$name$xmlns$atts>$val</$name>";
517  } else {
518  $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
519  }
520  break;
521  case (is_float($val)|| is_double($val) || $type == 'float'):
522  $this->debug("serialize_val: serialize float");
523  if ($use == 'literal') {
524  $xml .= "<$name$xmlns$atts>$val</$name>";
525  } else {
526  $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
527  }
528  break;
529  case (is_string($val) || $type == 'string'):
530  $this->debug("serialize_val: serialize string");
531  $val = $this->expandEntities($val);
532  if ($use == 'literal') {
533  $xml .= "<$name$xmlns$atts>$val</$name>";
534  } else {
535  $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
536  }
537  break;
538  case is_object($val):
539  $this->debug("serialize_val: serialize object");
540  if (get_class($val) == 'soapval') {
541  $this->debug("serialize_val: serialize soapval object");
542  $pXml = $val->serialize($use);
543  $this->appendDebug($val->getDebug());
544  $val->clearDebug();
545  } else {
546  if (! $name) {
547  $name = get_class($val);
548  $this->debug("In serialize_val, used class name $name as element name");
549  } else {
550  $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
551  }
552  foreach(get_object_vars($val) as $k => $v){
553  $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
554  }
555  }
556  if(isset($type) && isset($type_prefix)){
557  $type_str = " xsi:type=\"$type_prefix:$type\"";
558  } else {
559  $type_str = '';
560  }
561  if ($use == 'literal') {
562  $xml .= "<$name$xmlns$atts>$pXml</$name>";
563  } else {
564  $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
565  }
566  break;
567  break;
568  case (is_array($val) || $type):
569  // detect if struct or array
570  $valueType = $this->isArraySimpleOrStruct($val);
571  if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){
572  $this->debug("serialize_val: serialize array");
573  $i = 0;
574  if(is_array($val) && count($val)> 0){
575  foreach($val as $v){
576  if(is_object($v) && get_class($v) == 'soapval'){
577  $tt_ns = $v->type_ns;
578  $tt = $v->type;
579  } elseif (is_array($v)) {
580  $tt = $this->isArraySimpleOrStruct($v);
581  } else {
582  $tt = gettype($v);
583  }
584  $array_types[$tt] = 1;
585  // TODO: for literal, the name should be $name
586  $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
587  ++$i;
588  }
589  if(count($array_types) > 1){
590  $array_typename = 'xsd:anyType';
591  } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
592  if ($tt == 'integer') {
593  $tt = 'int';
594  }
595  $array_typename = 'xsd:'.$tt;
596  } elseif(isset($tt) && $tt == 'arraySimple'){
597  $array_typename = 'SOAP-ENC:Array';
598  } elseif(isset($tt) && $tt == 'arrayStruct'){
599  $array_typename = 'unnamed_struct_use_soapval';
600  } else {
601  // if type is prefixed, create type prefix
602  if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
603  $array_typename = 'xsd:' . $tt;
604  } elseif ($tt_ns) {
605  $tt_prefix = 'ns' . rand(1000, 9999);
606  $array_typename = "$tt_prefix:$tt";
607  $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
608  } else {
609  $array_typename = $tt;
610  }
611  }
612  $array_type = $i;
613  if ($use == 'literal') {
614  $type_str = '';
615  } else if (isset($type) && isset($type_prefix)) {
616  $type_str = " xsi:type=\"$type_prefix:$type\"";
617  } else {
618  $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
619  }
620  // empty array
621  } else {
622  if ($use == 'literal') {
623  $type_str = '';
624  } else if (isset($type) && isset($type_prefix)) {
625  $type_str = " xsi:type=\"$type_prefix:$type\"";
626  } else {
627  $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
628  }
629  }
630  // TODO: for array in literal, there is no wrapper here
631  $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
632  } else {
633  // got a struct
634  $this->debug("serialize_val: serialize struct");
635  if(isset($type) && isset($type_prefix)){
636  $type_str = " xsi:type=\"$type_prefix:$type\"";
637  } else {
638  $type_str = '';
639  }
640  if ($use == 'literal') {
641  $xml .= "<$name$xmlns$atts>";
642  } else {
643  $xml .= "<$name$xmlns$type_str$atts>";
644  }
645  foreach($val as $k => $v){
646  // Apache Map
647  if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
648  $xml .= '<item>';
649  $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
650  $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
651  $xml .= '</item>';
652  } else {
653  $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
654  }
655  }
656  $xml .= "</$name>";
657  }
658  break;
659  default:
660  $this->debug("serialize_val: serialize unknown");
661  $xml .= 'not detected, got '.gettype($val).' for '.$val;
662  break;
663  }
664  $this->debug("serialize_val returning $xml");
665  return $xml;
666  }
667 
680  function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
681  // TODO: add an option to automatically run utf8_encode on $body and $headers
682  // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
683  // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
684 
685  $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
686  $this->debug("headers:");
687  $this->appendDebug($this->varDump($headers));
688  $this->debug("namespaces:");
689  $this->appendDebug($this->varDump($namespaces));
690 
691  // serialize namespaces
692  $ns_string = '';
693  foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
694  $ns_string .= " xmlns:$k=\"$v\"";
695  }
696  if($encodingStyle) {
697  $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
698  }
699 
700  // serialize headers
701  if($headers){
702  if (is_array($headers)) {
703  $xml = '';
704  foreach ($headers as $k => $v) {
705  if (is_object($v) && get_class($v) == 'soapval') {
706  $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
707  } else {
708  $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
709  }
710  }
711  $headers = $xml;
712  $this->debug("In serializeEnvelope, serialized array of headers to $headers");
713  }
714  $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
715  }
716  // serialize envelope
717  return
718  '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
719  '<SOAP-ENV:Envelope'.$ns_string.">".
720  $headers.
721  "<SOAP-ENV:Body>".
722  $body.
723  "</SOAP-ENV:Body>".
724  "</SOAP-ENV:Envelope>";
725  }
726 
735  function formatDump($str){
736  $str = htmlspecialchars($str);
737  return nl2br($str);
738  }
739 
747  function contractQname($qname){
748  // get element namespace
749  //$this->xdebug("Contract $qname");
750  if (strrpos($qname, ':')) {
751  // get unqualified name
752  $name = substr($qname, strrpos($qname, ':') + 1);
753  // get ns
754  $ns = substr($qname, 0, strrpos($qname, ':'));
755  $p = $this->getPrefixFromNamespace($ns);
756  if ($p) {
757  return $p . ':' . $name;
758  }
759  return $qname;
760  } else {
761  return $qname;
762  }
763  }
764 
772  function expandQname($qname){
773  // get element prefix
774  if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){
775  // get unqualified name
776  $name = substr(strstr($qname,':'),1);
777  // get ns prefix
778  $prefix = substr($qname,0,strpos($qname,':'));
779  if(isset($this->namespaces[$prefix])){
780  return $this->namespaces[$prefix].':'.$name;
781  } else {
782  return $qname;
783  }
784  } else {
785  return $qname;
786  }
787  }
788 
797  function getLocalPart($str){
798  if($sstr = strrchr($str,':')){
799  // get unqualified name
800  return substr( $sstr, 1 );
801  } else {
802  return $str;
803  }
804  }
805 
814  function getPrefix($str){
815  if($pos = strrpos($str,':')){
816  // get prefix
817  return substr($str,0,$pos);
818  }
819  return false;
820  }
821 
829  function getNamespaceFromPrefix($prefix){
830  if (isset($this->namespaces[$prefix])) {
831  return $this->namespaces[$prefix];
832  }
833  //$this->setError("No namespace registered for prefix '$prefix'");
834  return false;
835  }
836 
845  function getPrefixFromNamespace($ns) {
846  foreach ($this->namespaces as $p => $n) {
847  if ($ns == $n || $ns == $p) {
848  $this->usedNamespaces[$p] = $n;
849  return $p;
850  }
851  }
852  return false;
853  }
854 
861  function getmicrotime() {
862  if (function_exists('gettimeofday')) {
863  $tod = gettimeofday();
864  $sec = $tod['sec'];
865  $usec = $tod['usec'];
866  } else {
867  $sec = time();
868  $usec = 0;
869  }
870  return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
871  }
872 
880  function varDump($data) {
881  ob_start();
882  var_dump($data);
883  $ret_val = ob_get_contents();
884  ob_end_clean();
885  return $ret_val;
886  }
887 
894  function __toString() {
895  return $this->varDump($this);
896  }
897 }
898 
899 // XML Schema Datatype Helper Functions
900 
901 //xsd:dateTime helpers
902 
910 function timestamp_to_iso8601($timestamp,$utc=true){
911  $datestr = date('Y-m-d\TH:i:sO',$timestamp);
912  if($utc){
913  $pattern = '/'.
914  '([0-9]{4})-'. // centuries & years CCYY-
915  '([0-9]{2})-'. // months MM-
916  '([0-9]{2})'. // days DD
917  'T'. // separator T
918  '([0-9]{2}):'. // hours hh:
919  '([0-9]{2}):'. // minutes mm:
920  '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
921  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
922  '/';
923 
924  if(preg_match($pattern,$datestr,$regs)){
925  return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
926  }
927  return false;
928  } else {
929  return $datestr;
930  }
931 }
932 
939 function iso8601_to_timestamp($datestr){
940  $pattern = '/'.
941  '([0-9]{4})-'. // centuries & years CCYY-
942  '([0-9]{2})-'. // months MM-
943  '([0-9]{2})'. // days DD
944  'T'. // separator T
945  '([0-9]{2}):'. // hours hh:
946  '([0-9]{2}):'. // minutes mm:
947  '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
948  '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
949  '/';
950 
951  if(preg_match($pattern,$datestr,$regs)){
952  // not utc
953  if($regs[8] != 'Z'){
954  $op = substr($regs[8],0,1);
955  $h = substr($regs[8],1,2);
956  $m = substr($regs[8],strlen($regs[8])-2,2);
957  if($op == '-'){
958  $regs[4] = $regs[4] + $h;
959  $regs[5] = $regs[5] + $m;
960  } elseif($op == '+'){
961  $regs[4] = $regs[4] - $h;
962  $regs[5] = $regs[5] - $m;
963  }
964  }
965  return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
966 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
967  } else {
968  return false;
969  }
970 }
971 
979 function usleepWindows($usec)
980 {
981  $start = gettimeofday();
982 
983  do
984  {
985  $stop = gettimeofday();
986  $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
987  + $stop['usec'] - $start['usec'];
988  }
989  while ($timePassed < $usec);
990 }
991 
992 ?><?php
993 
994 
995 
1004 class nusoap_fault extends nusoap_base {
1029 
1040  $this->faultcode = $faultcode;
1041  $this->faultactor = $faultactor;
1042  $this->faultstring = $faultstring;
1043  $this->faultdetail = $faultdetail;
1044  }
1045 
1052  function serialize(){
1053  $ns_string = '';
1054  foreach($this->namespaces as $k => $v){
1055  $ns_string .= "\n xmlns:$k=\"$v\"";
1056  }
1057  $return_msg =
1058  '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1059  '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1060  '<SOAP-ENV:Body>'.
1061  '<SOAP-ENV:Fault>'.
1062  $this->serialize_val($this->faultcode, 'faultcode').
1063  $this->serialize_val($this->faultstring, 'faultstring').
1064  $this->serialize_val($this->faultactor, 'faultactor').
1065  $this->serialize_val($this->faultdetail, 'detail').
1066  '</SOAP-ENV:Fault>'.
1067  '</SOAP-ENV:Body>'.
1068  '</SOAP-ENV:Envelope>';
1069  return $return_msg;
1070  }
1071 }
1072 
1076 class soap_fault extends nusoap_fault {
1077 }
1078 
1079 ?><?php
1080 
1081 
1082 
1093 
1094  // files
1095  var $schema = '';
1096  var $xml = '';
1097  // namespaces
1099  // schema info
1100  var $schemaInfo = array();
1102  // types, elements, attributes defined by the schema
1103  var $attributes = array();
1104  var $complexTypes = array();
1105  var $complexTypeStack = array();
1107  var $elements = array();
1108  var $elementStack = array();
1109  var $currentElement = null;
1110  var $simpleTypes = array();
1111  var $simpleTypeStack = array();
1113  // imports
1114  var $imports = array();
1115  // parser vars
1116  var $parser;
1117  var $position = 0;
1118  var $depth = 0;
1119  var $depth_array = array();
1120  var $message = array();
1121  var $defaultNamespace = array();
1122 
1131  function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
1133  $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1134  // files
1135  $this->schema = $schema;
1136  $this->xml = $xml;
1137 
1138  // namespaces
1139  $this->enclosingNamespaces = $namespaces;
1140  $this->namespaces = array_merge($this->namespaces, $namespaces);
1141 
1142  // parse schema file
1143  if($schema != ''){
1144  $this->debug('initial schema file: '.$schema);
1145  $this->parseFile($schema, 'schema');
1146  }
1147 
1148  // parse xml file
1149  if($xml != ''){
1150  $this->debug('initial xml file: '.$xml);
1151  $this->parseFile($xml, 'xml');
1152  }
1153 
1154  }
1155 
1164  function parseFile($xml,$type){
1165  // parse xml file
1166  if($xml != ""){
1167  $xmlStr = @join("",@file($xml));
1168  if($xmlStr == ""){
1169  $msg = 'Error reading XML from '.$xml;
1170  $this->setError($msg);
1171  $this->debug($msg);
1172  return false;
1173  } else {
1174  $this->debug("parsing $xml");
1175  $this->parseString($xmlStr,$type);
1176  $this->debug("done parsing $xml");
1177  return true;
1178  }
1179  }
1180  return false;
1181  }
1182 
1190  function parseString($xml,$type){
1191  // parse xml string
1192  if($xml != ""){
1193 
1194  // Create an XML parser.
1195  $this->parser = xml_parser_create();
1196  // Set the options for parsing the XML data.
1197  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1198 
1199  // Set the object for the parser.
1200  xml_set_object($this->parser, $this);
1201 
1202  // Set the element handlers for the parser.
1203  if($type == "schema"){
1204  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1205  xml_set_character_data_handler($this->parser,'schemaCharacterData');
1206  } elseif($type == "xml"){
1207  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1208  xml_set_character_data_handler($this->parser,'xmlCharacterData');
1209  }
1210 
1211  // Parse the XML file.
1212  if(!xml_parse($this->parser,$xml,true)){
1213  // Display an error message.
1214  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1215  xml_get_current_line_number($this->parser),
1216  xml_error_string(xml_get_error_code($this->parser))
1217  );
1218  $this->debug($errstr);
1219  $this->debug("XML payload:\n" . $xml);
1220  $this->setError($errstr);
1221  }
1222 
1223  xml_parser_free($this->parser);
1224  } else{
1225  $this->debug('no xml passed to parseString()!!');
1226  $this->setError('no xml passed to parseString()!!');
1227  }
1228  }
1229 
1237  function CreateTypeName($ename) {
1238  $scope = '';
1239  for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1240  $scope .= $this->complexTypeStack[$i] . '_';
1241  }
1242  return $scope . $ename . '_ContainedType';
1243  }
1244 
1253  function schemaStartElement($parser, $name, $attrs) {
1254 
1255  // position in the total number of elements, starting from 0
1256  $pos = $this->position++;
1257  $depth = $this->depth++;
1258  // set self as current value for this depth
1259  $this->depth_array[$depth] = $pos;
1260  $this->message[$pos] = array('cdata' => '');
1261  if ($depth > 0) {
1262  $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1263  } else {
1264  $this->defaultNamespace[$pos] = false;
1265  }
1266 
1267  // get element prefix
1268  if($prefix = $this->getPrefix($name)){
1269  // get unqualified name
1270  $name = $this->getLocalPart($name);
1271  } else {
1272  $prefix = '';
1273  }
1274 
1275  // loop thru attributes, expanding, and registering namespace declarations
1276  if(count($attrs) > 0){
1277  foreach($attrs as $k => $v){
1278  // if ns declarations, add to class level array of valid namespaces
1279  if(preg_match('/^xmlns/',$k)){
1280  //$this->xdebug("$k: $v");
1281  //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1282  if($ns_prefix = substr(strrchr($k,':'),1)){
1283  //$this->xdebug("Add namespace[$ns_prefix] = $v");
1284  $this->namespaces[$ns_prefix] = $v;
1285  } else {
1286  $this->defaultNamespace[$pos] = $v;
1287  if (! $this->getPrefixFromNamespace($v)) {
1288  $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1289  }
1290  }
1291  if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1292  $this->XMLSchemaVersion = $v;
1293  $this->namespaces['xsi'] = $v.'-instance';
1294  }
1295  }
1296  }
1297  foreach($attrs as $k => $v){
1298  // expand each attribute
1299  $k = strpos($k,':') ? $this->expandQname($k) : $k;
1300  $v = strpos($v,':') ? $this->expandQname($v) : $v;
1301  $eAttrs[$k] = $v;
1302  }
1303  $attrs = $eAttrs;
1304  } else {
1305  $attrs = array();
1306  }
1307  // find status, register data
1308  switch($name){
1309  case 'all': // (optional) compositor content for a complexType
1310  case 'choice':
1311  case 'group':
1312  case 'sequence':
1313  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1314  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1315  //if($name == 'all' || $name == 'sequence'){
1316  // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1317  //}
1318  break;
1319  case 'attribute': // complexType attribute
1320  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1321  $this->xdebug("parsing attribute:");
1322  $this->appendDebug($this->varDump($attrs));
1323  if (!isset($attrs['form'])) {
1324  $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1325  }
1326  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1327  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1328  if (!strpos($v, ':')) {
1329  // no namespace in arrayType attribute value...
1330  if ($this->defaultNamespace[$pos]) {
1331  // ...so use the default
1332  $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1333  }
1334  }
1335  }
1336  if(isset($attrs['name'])){
1337  $this->attributes[$attrs['name']] = $attrs;
1338  $aname = $attrs['name'];
1339  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1340  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1341  $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1342  } else {
1343  $aname = '';
1344  }
1345  } elseif(isset($attrs['ref'])){
1346  $aname = $attrs['ref'];
1347  $this->attributes[$attrs['ref']] = $attrs;
1348  }
1349 
1350  if($this->currentComplexType){ // This should *always* be
1351  $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1352  }
1353  // arrayType attribute
1354  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1355  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1356  $prefix = $this->getPrefix($aname);
1357  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1358  $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1359  } else {
1360  $v = '';
1361  }
1362  if(strpos($v,'[,]')){
1363  $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1364  }
1365  $v = substr($v,0,strpos($v,'[')); // clip the []
1366  if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1367  $v = $this->XMLSchemaVersion.':'.$v;
1368  }
1369  $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1370  }
1371  break;
1372  case 'complexContent': // (optional) content for a complexType
1373  break;
1374  case 'complexType':
1375  array_push($this->complexTypeStack, $this->currentComplexType);
1376  if(isset($attrs['name'])){
1377  // TODO: what is the scope of named complexTypes that appear
1378  // nested within other c complexTypes?
1379  $this->xdebug('processing named complexType '.$attrs['name']);
1380  //$this->currentElement = false;
1381  $this->currentComplexType = $attrs['name'];
1382  $this->complexTypes[$this->currentComplexType] = $attrs;
1383  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1384  // This is for constructs like
1385  // <complexType name="ListOfString" base="soap:Array">
1386  // <sequence>
1387  // <element name="string" type="xsd:string"
1388  // minOccurs="0" maxOccurs="unbounded" />
1389  // </sequence>
1390  // </complexType>
1391  if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
1392  $this->xdebug('complexType is unusual array');
1393  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1394  } else {
1395  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1396  }
1397  } else {
1398  $name = $this->CreateTypeName($this->currentElement);
1399  $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1400  $this->currentComplexType = $name;
1401  //$this->currentElement = false;
1402  $this->complexTypes[$this->currentComplexType] = $attrs;
1403  $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1404  // This is for constructs like
1405  // <complexType name="ListOfString" base="soap:Array">
1406  // <sequence>
1407  // <element name="string" type="xsd:string"
1408  // minOccurs="0" maxOccurs="unbounded" />
1409  // </sequence>
1410  // </complexType>
1411  if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
1412  $this->xdebug('complexType is unusual array');
1413  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1414  } else {
1415  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1416  }
1417  }
1418  break;
1419  case 'element':
1420  array_push($this->elementStack, $this->currentElement);
1421  if (!isset($attrs['form'])) {
1422  $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1423  }
1424  if(isset($attrs['type'])){
1425  $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1426  if (! $this->getPrefix($attrs['type'])) {
1427  if ($this->defaultNamespace[$pos]) {
1428  $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1429  $this->xdebug('used default namespace to make type ' . $attrs['type']);
1430  }
1431  }
1432  // This is for constructs like
1433  // <complexType name="ListOfString" base="soap:Array">
1434  // <sequence>
1435  // <element name="string" type="xsd:string"
1436  // minOccurs="0" maxOccurs="unbounded" />
1437  // </sequence>
1438  // </complexType>
1439  if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1440  $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1441  $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1442  }
1443  $this->currentElement = $attrs['name'];
1444  $ename = $attrs['name'];
1445  } elseif(isset($attrs['ref'])){
1446  $this->xdebug("processing element as ref to ".$attrs['ref']);
1447  $this->currentElement = "ref to ".$attrs['ref'];
1448  $ename = $this->getLocalPart($attrs['ref']);
1449  } else {
1450  $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1451  $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1452  $this->currentElement = $attrs['name'];
1453  $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1454  $ename = $attrs['name'];
1455  }
1456  if (isset($ename) && $this->currentComplexType) {
1457  $this->xdebug("add element $ename to complexType $this->currentComplexType");
1458  $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1459  } elseif (!isset($attrs['ref'])) {
1460  $this->xdebug("add element $ename to elements array");
1461  $this->elements[ $attrs['name'] ] = $attrs;
1462  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1463  }
1464  break;
1465  case 'enumeration': // restriction value list member
1466  $this->xdebug('enumeration ' . $attrs['value']);
1467  if ($this->currentSimpleType) {
1468  $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1469  } elseif ($this->currentComplexType) {
1470  $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1471  }
1472  break;
1473  case 'extension': // simpleContent or complexContent type extension
1474  $this->xdebug('extension ' . $attrs['base']);
1475  if ($this->currentComplexType) {
1476  $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1477  }
1478  break;
1479  case 'import':
1480  if (isset($attrs['schemaLocation'])) {
1481  //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1482  $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1483  } else {
1484  //$this->xdebug('import namespace ' . $attrs['namespace']);
1485  $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1486  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1487  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1488  }
1489  }
1490  break;
1491  case 'list': // simpleType value list
1492  break;
1493  case 'restriction': // simpleType, simpleContent or complexContent value restriction
1494  $this->xdebug('restriction ' . $attrs['base']);
1495  if($this->currentSimpleType){
1496  $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1497  } elseif($this->currentComplexType){
1498  $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1499  if(strstr($attrs['base'],':') == ':Array'){
1500  $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1501  }
1502  }
1503  break;
1504  case 'schema':
1505  $this->schemaInfo = $attrs;
1506  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1507  if (isset($attrs['targetNamespace'])) {
1508  $this->schemaTargetNamespace = $attrs['targetNamespace'];
1509  }
1510  if (!isset($attrs['elementFormDefault'])) {
1511  $this->schemaInfo['elementFormDefault'] = 'unqualified';
1512  }
1513  if (!isset($attrs['attributeFormDefault'])) {
1514  $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1515  }
1516  break;
1517  case 'simpleContent': // (optional) content for a complexType
1518  break;
1519  case 'simpleType':
1520  array_push($this->simpleTypeStack, $this->currentSimpleType);
1521  if(isset($attrs['name'])){
1522  $this->xdebug("processing simpleType for name " . $attrs['name']);
1523  $this->currentSimpleType = $attrs['name'];
1524  $this->simpleTypes[ $attrs['name'] ] = $attrs;
1525  $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1526  $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1527  } else {
1528  $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1529  $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1530  $this->currentSimpleType = $name;
1531  //$this->currentElement = false;
1532  $this->simpleTypes[$this->currentSimpleType] = $attrs;
1533  $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1534  }
1535  break;
1536  case 'union': // simpleType type list
1537  break;
1538  default:
1539  //$this->xdebug("do not have anything to do for element $name");
1540  }
1541  }
1542 
1550  function schemaEndElement($parser, $name) {
1551  // bring depth down a notch
1552  $this->depth--;
1553  // position of current element is equal to the last value left in depth_array for my depth
1554  if(isset($this->depth_array[$this->depth])){
1555  $pos = $this->depth_array[$this->depth];
1556  }
1557  // get element prefix
1558  if ($prefix = $this->getPrefix($name)){
1559  // get unqualified name
1560  $name = $this->getLocalPart($name);
1561  } else {
1562  $prefix = '';
1563  }
1564  // move on...
1565  if($name == 'complexType'){
1566  $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1567  $this->currentComplexType = array_pop($this->complexTypeStack);
1568  //$this->currentElement = false;
1569  }
1570  if($name == 'element'){
1571  $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1572  $this->currentElement = array_pop($this->elementStack);
1573  }
1574  if($name == 'simpleType'){
1575  $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1576  $this->currentSimpleType = array_pop($this->simpleTypeStack);
1577  }
1578  }
1579 
1588  $pos = $this->depth_array[$this->depth - 1];
1589  $this->message[$pos]['cdata'] .= $data;
1590  }
1591 
1597  function serializeSchema(){
1598 
1599  $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1600  $xml = '';
1601  // imports
1602  if (sizeof($this->imports) > 0) {
1603  foreach($this->imports as $ns => $list) {
1604  foreach ($list as $ii) {
1605  if ($ii['location'] != '') {
1606  $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1607  } else {
1608  $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1609  }
1610  }
1611  }
1612  }
1613  // complex types
1614  foreach($this->complexTypes as $typeName => $attrs){
1615  $contentStr = '';
1616  // serialize child elements
1617  if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1618  foreach($attrs['elements'] as $element => $eParts){
1619  if(isset($eParts['ref'])){
1620  $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
1621  } else {
1622  $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1623  foreach ($eParts as $aName => $aValue) {
1624  // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1625  if ($aName != 'name' && $aName != 'type') {
1626  $contentStr .= " $aName=\"$aValue\"";
1627  }
1628  }
1629  $contentStr .= "/>\n";
1630  }
1631  }
1632  // compositor wraps elements
1633  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1634  $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n";
1635  }
1636  }
1637  // attributes
1638  if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1639  foreach($attrs['attrs'] as $attr => $aParts){
1640  $contentStr .= " <$schemaPrefix:attribute";
1641  foreach ($aParts as $a => $v) {
1642  if ($a == 'ref' || $a == 'type') {
1643  $contentStr .= " $a=\"".$this->contractQName($v).'"';
1644  } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1645  $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1646  $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1647  } else {
1648  $contentStr .= " $a=\"$v\"";
1649  }
1650  }
1651  $contentStr .= "/>\n";
1652  }
1653  }
1654  // if restriction
1655  if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1656  $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n";
1657  // complex or simple content
1658  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1659  $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n";
1660  }
1661  }
1662  // finalize complex type
1663  if($contentStr != ''){
1664  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1665  } else {
1666  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1667  }
1668  $xml .= $contentStr;
1669  }
1670  // simple types
1671  if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1672  foreach($this->simpleTypes as $typeName => $eParts){
1673  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
1674  if (isset($eParts['enumeration'])) {
1675  foreach ($eParts['enumeration'] as $e) {
1676  $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
1677  }
1678  }
1679  $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1680  }
1681  }
1682  // elements
1683  if(isset($this->elements) && count($this->elements) > 0){
1684  foreach($this->elements as $element => $eParts){
1685  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1686  }
1687  }
1688  // attributes
1689  if(isset($this->attributes) && count($this->attributes) > 0){
1690  foreach($this->attributes as $attr => $aParts){
1691  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1692  }
1693  }
1694  // finish 'er up
1695  $attr = '';
1696  foreach ($this->schemaInfo as $k => $v) {
1697  if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1698  $attr .= " $k=\"$v\"";
1699  }
1700  }
1701  $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1702  foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1703  $el .= " xmlns:$nsp=\"$ns\"";
1704  }
1705  $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1706  return $xml;
1707  }
1708 
1715  function xdebug($string){
1716  $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1717  }
1718 
1731  function getPHPType($type,$ns){
1732  if(isset($this->typemap[$ns][$type])){
1733  //print "found type '$type' and ns $ns in typemap<br>";
1734  return $this->typemap[$ns][$type];
1735  } elseif(isset($this->complexTypes[$type])){
1736  //print "getting type '$type' and ns $ns from complexTypes array<br>";
1737  return $this->complexTypes[$type]['phpType'];
1738  }
1739  return false;
1740  }
1741 
1764  function getTypeDef($type){
1765  //$this->debug("in getTypeDef for type $type");
1766  if (substr($type, -1) == '^') {
1767  $is_element = 1;
1768  $type = substr($type, 0, -1);
1769  } else {
1770  $is_element = 0;
1771  }
1772 
1773  if((! $is_element) && isset($this->complexTypes[$type])){
1774  $this->xdebug("in getTypeDef, found complexType $type");
1775  return $this->complexTypes[$type];
1776  } elseif((! $is_element) && isset($this->simpleTypes[$type])){
1777  $this->xdebug("in getTypeDef, found simpleType $type");
1778  if (!isset($this->simpleTypes[$type]['phpType'])) {
1779  // get info for type to tack onto the simple type
1780  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1781  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1782  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1783  $etype = $this->getTypeDef($uqType);
1784  if ($etype) {
1785  $this->xdebug("in getTypeDef, found type for simpleType $type:");
1786  $this->xdebug($this->varDump($etype));
1787  if (isset($etype['phpType'])) {
1788  $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1789  }
1790  if (isset($etype['elements'])) {
1791  $this->simpleTypes[$type]['elements'] = $etype['elements'];
1792  }
1793  }
1794  }
1795  return $this->simpleTypes[$type];
1796  } elseif(isset($this->elements[$type])){
1797  $this->xdebug("in getTypeDef, found element $type");
1798  if (!isset($this->elements[$type]['phpType'])) {
1799  // get info for type to tack onto the element
1800  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1801  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1802  $etype = $this->getTypeDef($uqType);
1803  if ($etype) {
1804  $this->xdebug("in getTypeDef, found type for element $type:");
1805  $this->xdebug($this->varDump($etype));
1806  if (isset($etype['phpType'])) {
1807  $this->elements[$type]['phpType'] = $etype['phpType'];
1808  }
1809  if (isset($etype['elements'])) {
1810  $this->elements[$type]['elements'] = $etype['elements'];
1811  }
1812  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1813  $this->xdebug("in getTypeDef, element $type is an XSD type");
1814  $this->elements[$type]['phpType'] = 'scalar';
1815  }
1816  }
1817  return $this->elements[$type];
1818  } elseif(isset($this->attributes[$type])){
1819  $this->xdebug("in getTypeDef, found attribute $type");
1820  return $this->attributes[$type];
1821  } elseif (preg_match('/_ContainedType$/', $type)) {
1822  $this->xdebug("in getTypeDef, have an untyped element $type");
1823  $typeDef['typeClass'] = 'simpleType';
1824  $typeDef['phpType'] = 'scalar';
1825  $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1826  return $typeDef;
1827  }
1828  $this->xdebug("in getTypeDef, did not find $type");
1829  return false;
1830  }
1831 
1840  function serializeTypeDef($type){
1841  //print "in sTD() for type $type<br>";
1842  if($typeDef = $this->getTypeDef($type)){
1843  $str .= '<'.$type;
1844  if(is_array($typeDef['attrs'])){
1845  foreach($typeDef['attrs'] as $attName => $data){
1846  $str .= " $attName=\"{type = ".$data['type']."}\"";
1847  }
1848  }
1849  $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1850  if(count($typeDef['elements']) > 0){
1851  $str .= ">";
1852  foreach($typeDef['elements'] as $element => $eData){
1853  $str .= $this->serializeTypeDef($element);
1854  }
1855  $str .= "</$type>";
1856  } elseif($typeDef['typeClass'] == 'element') {
1857  $str .= "></$type>";
1858  } else {
1859  $str .= "/>";
1860  }
1861  return $str;
1862  }
1863  return false;
1864  }
1865 
1876  function typeToForm($name,$type){
1877  // get typedef
1878  if($typeDef = $this->getTypeDef($type)){
1879  // if struct
1880  if($typeDef['phpType'] == 'struct'){
1881  $buffer .= '<table>';
1882  foreach($typeDef['elements'] as $child => $childDef){
1883  $buffer .= "
1884  <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1885  <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1886  }
1887  $buffer .= '</table>';
1888  // if array
1889  } elseif($typeDef['phpType'] == 'array'){
1890  $buffer .= '<table>';
1891  for($i=0;$i < 3; $i++){
1892  $buffer .= "
1893  <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1894  <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1895  }
1896  $buffer .= '</table>';
1897  // if scalar
1898  } else {
1899  $buffer .= "<input type='text' name='parameters[$name]'>";
1900  }
1901  } else {
1902  $buffer .= "<input type='text' name='parameters[$name]'>";
1903  }
1904  return $buffer;
1905  }
1906 
1948  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1949  $this->complexTypes[$name] = array(
1950  'name' => $name,
1951  'typeClass' => $typeClass,
1952  'phpType' => $phpType,
1953  'compositor'=> $compositor,
1954  'restrictionBase' => $restrictionBase,
1955  'elements' => $elements,
1956  'attrs' => $attrs,
1957  'arrayType' => $arrayType
1958  );
1959 
1960  $this->xdebug("addComplexType $name:");
1961  $this->appendDebug($this->varDump($this->complexTypes[$name]));
1962  }
1963 
1976  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1977  $this->simpleTypes[$name] = array(
1978  'name' => $name,
1979  'typeClass' => $typeClass,
1980  'phpType' => $phpType,
1981  'type' => $restrictionBase,
1982  'enumeration' => $enumeration
1983  );
1984 
1985  $this->xdebug("addSimpleType $name:");
1986  $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1987  }
1988 
1996  function addElement($attrs) {
1997  if (! $this->getPrefix($attrs['type'])) {
1998  $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
1999  }
2000  $this->elements[ $attrs['name'] ] = $attrs;
2001  $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2002 
2003  $this->xdebug("addElement " . $attrs['name']);
2004  $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
2005  }
2006 }
2007 
2011 class XMLSchema extends nusoap_xmlschema {
2012 }
2013 
2014 ?><?php
2015 
2016 
2017 
2029 class soapval extends nusoap_base {
2036  var $name;
2043  var $type;
2050  var $value;
2072 
2084  function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
2086  $this->name = $name;
2087  $this->type = $type;
2088  $this->value = $value;
2089  $this->element_ns = $element_ns;
2090  $this->type_ns = $type_ns;
2091  $this->attributes = $attributes;
2092  }
2093 
2101  function serialize($use='encoded') {
2102  return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2103  }
2104 
2111  function decode(){
2112  return $this->value;
2113  }
2114 }
2115 
2116 
2117 
2118 ?><?php
2119 
2120 
2121 
2131 class soap_transport_http extends nusoap_base {
2132 
2133  var $url = '';
2134  var $uri = '';
2135  var $digest_uri = '';
2136  var $scheme = '';
2137  var $host = '';
2138  var $port = '';
2139  var $path = '';
2140  var $request_method = 'POST';
2141  var $protocol_version = '1.0';
2142  var $encoding = '';
2143  var $outgoing_headers = array();
2144  var $incoming_headers = array();
2145  var $incoming_cookies = array();
2146  var $outgoing_payload = '';
2147  var $incoming_payload = '';
2148  var $response_status_line; // HTTP response status line
2149  var $useSOAPAction = true;
2150  var $persistentConnection = false;
2151  var $ch = false; // cURL handle
2152  var $ch_options = array(); // cURL custom options
2153  var $use_curl = false; // force cURL use
2154  var $proxy = null; // proxy information (associative array)
2155  var $username = '';
2156  var $password = '';
2157  var $authtype = '';
2158  var $digestRequest = array();
2159  var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2160  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2161  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2162  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2163  // passphrase: SSL key password/passphrase
2164  // certpassword: SSL certificate password
2165  // verifypeer: default is 1
2166  // verifyhost: default is 1
2167 
2176  function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
2178  $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2179  $this->appendDebug($this->varDump($curl_options));
2180  $this->setURL($url);
2181  if (is_array($curl_options)) {
2182  $this->ch_options = $curl_options;
2183  }
2184  $this->use_curl = $use_curl;
2185  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2186  $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
2187  }
2188 
2196  function setCurlOption($option, $value) {
2197  $this->debug("setCurlOption option=$option, value=");
2198  $this->appendDebug($this->varDump($value));
2199  curl_setopt($this->ch, $option, $value);
2200  }
2201 
2209  function setHeader($name, $value) {
2210  $this->outgoing_headers[$name] = $value;
2211  $this->debug("set header $name: $value");
2212  }
2213 
2220  function unsetHeader($name) {
2221  if (isset($this->outgoing_headers[$name])) {
2222  $this->debug("unset header $name");
2223  unset($this->outgoing_headers[$name]);
2224  }
2225  }
2226 
2233  function setURL($url) {
2234  $this->url = $url;
2235 
2236  $u = parse_url($url);
2237  foreach($u as $k => $v){
2238  $this->debug("parsed URL $k = $v");
2239  $this->$k = $v;
2240  }
2241 
2242  // add any GET params to path
2243  if(isset($u['query']) && $u['query'] != ''){
2244  $this->path .= '?' . $u['query'];
2245  }
2246 
2247  // set default port
2248  if(!isset($u['port'])){
2249  if($u['scheme'] == 'https'){
2250  $this->port = 443;
2251  } else {
2252  $this->port = 80;
2253  }
2254  }
2255 
2256  $this->uri = $this->path;
2257  $this->digest_uri = $this->uri;
2258 
2259  // build headers
2260  if (!isset($u['port'])) {
2261  $this->setHeader('Host', $this->host);
2262  } else {
2263  $this->setHeader('Host', $this->host.':'.$this->port);
2264  }
2265 
2266  if (isset($u['user']) && $u['user'] != '') {
2267  $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2268  }
2269  }
2270 
2277  function io_method() {
2278  if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
2279  return 'curl';
2280  if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
2281  return 'socket';
2282  return 'unknown';
2283  }
2284 
2293  function connect($connection_timeout=0,$response_timeout=30){
2294  // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2295  // "regular" socket.
2296  // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2297  // loaded), and until PHP5 stream_get_wrappers is not available.
2298 // if ($this->scheme == 'https') {
2299 // if (version_compare(phpversion(), '4.3.0') >= 0) {
2300 // if (extension_loaded('openssl')) {
2301 // $this->scheme = 'ssl';
2302 // $this->debug('Using SSL over OpenSSL');
2303 // }
2304 // }
2305 // }
2306  $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2307  if ($this->io_method() == 'socket') {
2308  if (!is_array($this->proxy)) {
2309  $host = $this->host;
2310  $port = $this->port;
2311  } else {
2312  $host = $this->proxy['host'];
2313  $port = $this->proxy['port'];
2314  }
2315 
2316  // use persistent connection
2317  if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
2318  if (!feof($this->fp)) {
2319  $this->debug('Re-use persistent connection');
2320  return true;
2321  }
2322  fclose($this->fp);
2323  $this->debug('Closed persistent connection at EOF');
2324  }
2325 
2326  // munge host if using OpenSSL
2327  if ($this->scheme == 'ssl') {
2328  $host = 'ssl://' . $host;
2329  }
2330  $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2331 
2332  // open socket
2333  if($connection_timeout > 0){
2334  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2335  } else {
2336  $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
2337  }
2338 
2339  // test pointer
2340  if(!$this->fp) {
2341  $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2342  if ($this->errno) {
2343  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2344  } else {
2345  $msg .= ' prior to connect(). This is often a problem looking up the host name.';
2346  }
2347  $this->debug($msg);
2348  $this->setError($msg);
2349  return false;
2350  }
2351 
2352  // set response timeout
2353  $this->debug('set response timeout to ' . $response_timeout);
2354  socket_set_timeout( $this->fp, $response_timeout);
2355 
2356  $this->debug('socket connected');
2357  return true;
2358  } else if ($this->io_method() == 'curl') {
2359  if (!extension_loaded('curl')) {
2360 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2361  $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.');
2362  return false;
2363  }
2364  // Avoid warnings when PHP does not have these options
2365  if (defined('CURLOPT_CONNECTIONTIMEOUT'))
2366  $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2367  else
2368  $CURLOPT_CONNECTIONTIMEOUT = 78;
2369  if (defined('CURLOPT_HTTPAUTH'))
2370  $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2371  else
2372  $CURLOPT_HTTPAUTH = 107;
2373  if (defined('CURLOPT_PROXYAUTH'))
2374  $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2375  else
2376  $CURLOPT_PROXYAUTH = 111;
2377  if (defined('CURLAUTH_BASIC'))
2378  $CURLAUTH_BASIC = CURLAUTH_BASIC;
2379  else
2380  $CURLAUTH_BASIC = 1;
2381  if (defined('CURLAUTH_DIGEST'))
2382  $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2383  else
2384  $CURLAUTH_DIGEST = 2;
2385  if (defined('CURLAUTH_NTLM'))
2386  $CURLAUTH_NTLM = CURLAUTH_NTLM;
2387  else
2388  $CURLAUTH_NTLM = 8;
2389 
2390  $this->debug('connect using cURL');
2391  // init CURL
2392  $this->ch = curl_init();
2393  // set url
2394  $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2395  // add path
2396  $hostURL .= $this->path;
2397  $this->setCurlOption(CURLOPT_URL, $hostURL);
2398  // follow location headers (re-directs)
2399  if (ini_get('safe_mode') || ini_get('open_basedir')) {
2400  $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2401  $this->debug('safe_mode = ');
2402  $this->appendDebug($this->varDump(ini_get('safe_mode')));
2403  $this->debug('open_basedir = ');
2404  $this->appendDebug($this->varDump(ini_get('open_basedir')));
2405  } else {
2406  $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2407  }
2408  // ask for headers in the response output
2409  $this->setCurlOption(CURLOPT_HEADER, 1);
2410  // ask for the response output as the return value
2411  $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2412  // encode
2413  // We manage this ourselves through headers and encoding
2414 // if(function_exists('gzuncompress')){
2415 // $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
2416 // }
2417  // persistent connection
2418  if ($this->persistentConnection) {
2419  // I believe the following comment is now bogus, having applied to
2420  // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2421  // The way we send data, we cannot use persistent connections, since
2422  // there will be some "junk" at the end of our request.
2423  //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
2424  $this->persistentConnection = false;
2425  $this->setHeader('Connection', 'close');
2426  }
2427  // set timeouts
2428  if ($connection_timeout != 0) {
2429  $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2430  }
2431  if ($response_timeout != 0) {
2432  $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2433  }
2434 
2435  if ($this->scheme == 'https') {
2436  $this->debug('set cURL SSL verify options');
2437  // recent versions of cURL turn on peer/host checking by default,
2438  // while PHP binaries are not compiled with a default location for the
2439  // CA cert bundle, so disable peer/host checking.
2440  //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2441  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2442  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2443 
2444  // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2445  if ($this->authtype == 'certificate') {
2446  $this->debug('set cURL certificate options');
2447  if (isset($this->certRequest['cainfofile'])) {
2448  $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2449  }
2450  if (isset($this->certRequest['verifypeer'])) {
2451  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2452  } else {
2453  $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2454  }
2455  if (isset($this->certRequest['verifyhost'])) {
2456  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2457  } else {
2458  $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2459  }
2460  if (isset($this->certRequest['sslcertfile'])) {
2461  $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2462  }
2463  if (isset($this->certRequest['sslkeyfile'])) {
2464  $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2465  }
2466  if (isset($this->certRequest['passphrase'])) {
2467  $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2468  }
2469  if (isset($this->certRequest['certpassword'])) {
2470  $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2471  }
2472  }
2473  }
2474  if ($this->authtype && ($this->authtype != 'certificate')) {
2475  if ($this->username) {
2476  $this->debug('set cURL username/password');
2477  $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2478  }
2479  if ($this->authtype == 'basic') {
2480  $this->debug('set cURL for Basic authentication');
2481  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2482  }
2483  if ($this->authtype == 'digest') {
2484  $this->debug('set cURL for digest authentication');
2485  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2486  }
2487  if ($this->authtype == 'ntlm') {
2488  $this->debug('set cURL for NTLM authentication');
2489  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2490  }
2491  }
2492  if (is_array($this->proxy)) {
2493  $this->debug('set cURL proxy options');
2494  if ($this->proxy['port'] != '') {
2495  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
2496  } else {
2497  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2498  }
2499  if ($this->proxy['username'] || $this->proxy['password']) {
2500  $this->debug('set cURL proxy authentication options');
2501  $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
2502  if ($this->proxy['authtype'] == 'basic') {
2503  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2504  }
2505  if ($this->proxy['authtype'] == 'ntlm') {
2506  $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2507  }
2508  }
2509  }
2510  $this->debug('cURL connection set up');
2511  return true;
2512  } else {
2513  $this->setError('Unknown scheme ' . $this->scheme);
2514  $this->debug('Unknown scheme ' . $this->scheme);
2515  return false;
2516  }
2517  }
2518 
2529  function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
2530 
2531  $this->debug('entered send() with data of length: '.strlen($data));
2532 
2533  $this->tryagain = true;
2534  $tries = 0;
2535  while ($this->tryagain) {
2536  $this->tryagain = false;
2537  if ($tries++ < 2) {
2538  // make connnection
2539  if (!$this->connect($timeout, $response_timeout)){
2540  return false;
2541  }
2542 
2543  // send request
2544  if (!$this->sendRequest($data, $cookies)){
2545  return false;
2546  }
2547 
2548  // get response
2549  $respdata = $this->getResponse();
2550  } else {
2551  $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2552  }
2553  }
2554  $this->debug('end of send()');
2555  return $respdata;
2556  }
2557 
2558 
2570  function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
2571  return $this->send($data, $timeout, $response_timeout, $cookies);
2572  }
2573 
2584  function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
2585  $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2586  $this->appendDebug($this->varDump($digestRequest));
2587  $this->debug("certRequest=");
2588  $this->appendDebug($this->varDump($certRequest));
2589  // cf. RFC 2617
2590  if ($authtype == 'basic') {
2591  $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
2592  } elseif ($authtype == 'digest') {
2593  if (isset($digestRequest['nonce'])) {
2594  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2595 
2596  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2597 
2598  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2599  $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2600 
2601  // H(A1) = MD5(A1)
2602  $HA1 = md5($A1);
2603 
2604  // A2 = Method ":" digest-uri-value
2605  $A2 = $this->request_method . ':' . $this->digest_uri;
2606 
2607  // H(A2)
2608  $HA2 = md5($A2);
2609 
2610  // KD(secret, data) = H(concat(secret, ":", data))
2611  // if qop == auth:
2612  // request-digest = <"> < KD ( H(A1), unq(nonce-value)
2613  // ":" nc-value
2614  // ":" unq(cnonce-value)
2615  // ":" unq(qop-value)
2616  // ":" H(A2)
2617  // ) <">
2618  // if qop is missing,
2619  // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2620 
2621  $unhashedDigest = '';
2622  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2623  $cnonce = $nonce;
2624  if ($digestRequest['qop'] != '') {
2625  $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2626  } else {
2627  $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2628  }
2629 
2630  $hashedDigest = md5($unhashedDigest);
2631 
2632  $opaque = '';
2633  if (isset($digestRequest['opaque'])) {
2634  $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2635  }
2636 
2637  $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 . '"');
2638  }
2639  } elseif ($authtype == 'certificate') {
2640  $this->certRequest = $certRequest;
2641  $this->debug('Authorization header not set for certificate');
2642  } elseif ($authtype == 'ntlm') {
2643  // do nothing
2644  $this->debug('Authorization header not set for ntlm');
2645  }
2646  $this->username = $username;
2647  $this->password = $password;
2648  $this->authtype = $authtype;
2649  $this->digestRequest = $digestRequest;
2650  }
2651 
2658  function setSOAPAction($soapaction) {
2659  $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2660  }
2661 
2668  function setEncoding($enc='gzip, deflate') {
2669  if (function_exists('gzdeflate')) {
2670  $this->protocol_version = '1.1';
2671  $this->setHeader('Accept-Encoding', $enc);
2672  if (!isset($this->outgoing_headers['Connection'])) {
2673  $this->setHeader('Connection', 'close');
2674  $this->persistentConnection = false;
2675  }
2676  set_magic_quotes_runtime(0);
2677  // deprecated
2678  $this->encoding = $enc;
2679  }
2680  }
2681 
2692  function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
2693  if ($proxyhost) {
2694  $this->proxy = array(
2695  'host' => $proxyhost,
2696  'port' => $proxyport,
2697  'username' => $proxyusername,
2698  'password' => $proxypassword,
2699  'authtype' => $proxyauthtype
2700  );
2701  if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2702  $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
2703  }
2704  } else {
2705  $this->debug('remove proxy');
2706  $proxy = null;
2707  unsetHeader('Proxy-Authorization');
2708  }
2709  }
2710 
2711 
2721  $skipHeaders = array( 'HTTP/1.1 100',
2722  'HTTP/1.0 301',
2723  'HTTP/1.1 301',
2724  'HTTP/1.0 302',
2725  'HTTP/1.1 302',
2726  'HTTP/1.0 401',
2727  'HTTP/1.1 401',
2728  'HTTP/1.0 200 Connection established');
2729  foreach ($skipHeaders as $hd) {
2730  $prefix = substr($data, 0, strlen($hd));
2731  if ($prefix == $hd) return true;
2732  }
2733 
2734  return false;
2735  }
2736 
2747  function decodeChunked($buffer, $lb){
2748  // length := 0
2749  $length = 0;
2750  $new = '';
2751 
2752  // read chunk-size, chunk-extension (if any) and CRLF
2753  // get the position of the linebreak
2754  $chunkend = strpos($buffer, $lb);
2755  if ($chunkend == FALSE) {
2756  $this->debug('no linebreak found in decodeChunked');
2757  return $new;
2758  }
2759  $temp = substr($buffer,0,$chunkend);
2760  $chunk_size = hexdec( trim($temp) );
2761  $chunkstart = $chunkend + strlen($lb);
2762  // while (chunk-size > 0) {
2763  while ($chunk_size > 0) {
2764  $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2765  $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2766 
2767  // Just in case we got a broken connection
2768  if ($chunkend == FALSE) {
2769  $chunk = substr($buffer,$chunkstart);
2770  // append chunk-data to entity-body
2771  $new .= $chunk;
2772  $length += strlen($chunk);
2773  break;
2774  }
2775 
2776  // read chunk-data and CRLF
2777  $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2778  // append chunk-data to entity-body
2779  $new .= $chunk;
2780  // length := length + chunk-size
2781  $length += strlen($chunk);
2782  // read chunk-size and CRLF
2783  $chunkstart = $chunkend + strlen($lb);
2784 
2785  $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2786  if ($chunkend == FALSE) {
2787  break; //Just in case we got a broken connection
2788  }
2789  $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2790  $chunk_size = hexdec( trim($temp) );
2791  $chunkstart = $chunkend;
2792  }
2793  return $new;
2794  }
2795 
2804  function buildPayload($data, $cookie_str = '') {
2805  // Note: for cURL connections, $this->outgoing_payload is ignored,
2806  // as is the Content-Length header, but these are still created as
2807  // debugging guides.
2808 
2809  // add content-length header
2810  $this->setHeader('Content-Length', strlen($data));
2811 
2812  // start building outgoing payload:
2813  if ($this->proxy) {
2814  $uri = $this->url;
2815  } else {
2816  $uri = $this->uri;
2817  }
2818  $req = "$this->request_method $uri HTTP/$this->protocol_version";
2819  $this->debug("HTTP request: $req");
2820  $this->outgoing_payload = "$req\r\n";
2821 
2822  // loop thru headers, serializing
2823  foreach($this->outgoing_headers as $k => $v){
2824  $hdr = $k.': '.$v;
2825  $this->debug("HTTP header: $hdr");
2826  $this->outgoing_payload .= "$hdr\r\n";
2827  }
2828 
2829  // add any cookies
2830  if ($cookie_str != '') {
2831  $hdr = 'Cookie: '.$cookie_str;
2832  $this->debug("HTTP header: $hdr");
2833  $this->outgoing_payload .= "$hdr\r\n";
2834  }
2835 
2836  // header/body separator
2837  $this->outgoing_payload .= "\r\n";
2838 
2839  // add data
2840  $this->outgoing_payload .= $data;
2841  }
2842 
2851  function sendRequest($data, $cookies = NULL) {
2852  // build cookie string
2853  $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2854 
2855  // build payload
2856  $this->buildPayload($data, $cookie_str);
2857 
2858  if ($this->io_method() == 'socket') {
2859  // send payload
2860  if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2861  $this->setError('couldn\'t write message data to socket');
2862  $this->debug('couldn\'t write message data to socket');
2863  return false;
2864  }
2865  $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2866  return true;
2867  } else if ($this->io_method() == 'curl') {
2868  // set payload
2869  // cURL does say this should only be the verb, and in fact it
2870  // turns out that the URI and HTTP version are appended to this, which
2871  // some servers refuse to work with (so we no longer use this method!)
2872  //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2873  $curl_headers = array();
2874  foreach($this->outgoing_headers as $k => $v){
2875  if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2876  $this->debug("Skip cURL header $k: $v");
2877  } else {
2878  $curl_headers[] = "$k: $v";
2879  }
2880  }
2881  if ($cookie_str != '') {
2882  $curl_headers[] = 'Cookie: ' . $cookie_str;
2883  }
2884  $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
2885  $this->debug('set cURL HTTP headers');
2886  if ($this->request_method == "POST") {
2887  $this->setCurlOption(CURLOPT_POST, 1);
2888  $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
2889  $this->debug('set cURL POST data');
2890  } else {
2891  }
2892  // insert custom user-set cURL options
2893  foreach ($this->ch_options as $key => $val) {
2894  $this->setCurlOption($key, $val);
2895  }
2896 
2897  $this->debug('set cURL payload');
2898  return true;
2899  }
2900  }
2901 
2908  function getResponse(){
2909  $this->incoming_payload = '';
2910 
2911  if ($this->io_method() == 'socket') {
2912  // loop until headers have been retrieved
2913  $data = '';
2914  while (!isset($lb)){
2915 
2916  // We might EOF during header read.
2917  if(feof($this->fp)) {
2918  $this->incoming_payload = $data;
2919  $this->debug('found no headers before EOF after length ' . strlen($data));
2920  $this->debug("received before EOF:\n" . $data);
2921  $this->setError('server failed to send headers');
2922  return false;
2923  }
2924 
2925  $tmp = fgets($this->fp, 256);
2926  $tmplen = strlen($tmp);
2927  $this->debug("read line of $tmplen bytes: " . trim($tmp));
2928 
2929  if ($tmplen == 0) {
2930  $this->incoming_payload = $data;
2931  $this->debug('socket read of headers timed out after length ' . strlen($data));
2932  $this->debug("read before timeout: " . $data);
2933  $this->setError('socket read of headers timed out');
2934  return false;
2935  }
2936 
2937  $data .= $tmp;
2938  $pos = strpos($data,"\r\n\r\n");
2939  if($pos > 1){
2940  $lb = "\r\n";
2941  } else {
2942  $pos = strpos($data,"\n\n");
2943  if($pos > 1){
2944  $lb = "\n";
2945  }
2946  }
2947  // remove 100 headers
2948  if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) {
2949  unset($lb);
2950  $data = '';
2951  }//
2952  }
2953  // store header data
2954  $this->incoming_payload .= $data;
2955  $this->debug('found end of headers after length ' . strlen($data));
2956  // process headers
2957  $header_data = trim(substr($data,0,$pos));
2958  $header_array = explode($lb,$header_data);
2959  $this->incoming_headers = array();
2960  $this->incoming_cookies = array();
2961  foreach($header_array as $header_line){
2962  $arr = explode(':',$header_line, 2);
2963  if(count($arr) > 1){
2964  $header_name = strtolower(trim($arr[0]));
2965  $this->incoming_headers[$header_name] = trim($arr[1]);
2966  if ($header_name == 'set-cookie') {
2967  // TODO: allow multiple cookies from parseCookie
2968  $cookie = $this->parseCookie(trim($arr[1]));
2969  if ($cookie) {
2970  $this->incoming_cookies[] = $cookie;
2971  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2972  } else {
2973  $this->debug('did not find cookie in ' . trim($arr[1]));
2974  }
2975  }
2976  } else if (isset($header_name)) {
2977  // append continuation line to previous header
2978  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2979  }
2980  }
2981 
2982  // loop until msg has been received
2983  if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2984  $content_length = 2147483647; // ignore any content-length header
2985  $chunked = true;
2986  $this->debug("want to read chunked content");
2987  } elseif (isset($this->incoming_headers['content-length'])) {
2988  $content_length = $this->incoming_headers['content-length'];
2989  $chunked = false;
2990  $this->debug("want to read content of length $content_length");
2991  } else {
2992  $content_length = 2147483647;
2993  $chunked = false;
2994  $this->debug("want to read content to EOF");
2995  }
2996  $data = '';
2997  do {
2998  if ($chunked) {
2999  $tmp = fgets($this->fp, 256);
3000  $tmplen = strlen($tmp);
3001  $this->debug("read chunk line of $tmplen bytes");
3002  if ($tmplen == 0) {
3003  $this->incoming_payload = $data;
3004  $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3005  $this->debug("read before timeout:\n" . $data);
3006  $this->setError('socket read of chunk length timed out');
3007  return false;
3008  }
3009  $content_length = hexdec(trim($tmp));
3010  $this->debug("chunk length $content_length");
3011  }
3012  $strlen = 0;
3013  while (($strlen < $content_length) && (!feof($this->fp))) {
3014  $readlen = min(8192, $content_length - $strlen);
3015  $tmp = fread($this->fp, $readlen);
3016  $tmplen = strlen($tmp);
3017  $this->debug("read buffer of $tmplen bytes");
3018  if (($tmplen == 0) && (!feof($this->fp))) {
3019  $this->incoming_payload = $data;
3020  $this->debug('socket read of body timed out after length ' . strlen($data));
3021  $this->debug("read before timeout:\n" . $data);
3022  $this->setError('socket read of body timed out');
3023  return false;
3024  }
3025  $strlen += $tmplen;
3026  $data .= $tmp;
3027  }
3028  if ($chunked && ($content_length > 0)) {
3029  $tmp = fgets($this->fp, 256);
3030  $tmplen = strlen($tmp);
3031  $this->debug("read chunk terminator of $tmplen bytes");
3032  if ($tmplen == 0) {
3033  $this->incoming_payload = $data;
3034  $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3035  $this->debug("read before timeout:\n" . $data);
3036  $this->setError('socket read of chunk terminator timed out');
3037  return false;
3038  }
3039  }
3040  } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3041  if (feof($this->fp)) {
3042  $this->debug('read to EOF');
3043  }
3044  $this->debug('read body of length ' . strlen($data));
3045  $this->incoming_payload .= $data;
3046  $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
3047 
3048  // close filepointer
3049  if(
3050  (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
3051  (! $this->persistentConnection) || feof($this->fp)){
3052  fclose($this->fp);
3053  $this->fp = false;
3054  $this->debug('closed socket');
3055  }
3056 
3057  // connection was closed unexpectedly
3058  if($this->incoming_payload == ''){
3059  $this->setError('no response from server');
3060  return false;
3061  }
3062 
3063  // decode transfer-encoding
3064 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
3065 // if(!$data = $this->decodeChunked($data, $lb)){
3066 // $this->setError('Decoding of chunked data failed');
3067 // return false;
3068 // }
3069  //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3070  // set decoded payload
3071 // $this->incoming_payload = $header_data.$lb.$lb.$data;
3072 // }
3073 
3074  } else if ($this->io_method() == 'curl') {
3075  // send and receive
3076  $this->debug('send and receive with cURL');
3077  $this->incoming_payload = curl_exec($this->ch);
3079 
3080  $cErr = curl_error($this->ch);
3081  if ($cErr != '') {
3082  $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
3083  // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3084  foreach(curl_getinfo($this->ch) as $k => $v){
3085  $err .= "$k: $v<br>";
3086  }
3087  $this->debug($err);
3088  $this->setError($err);
3089  curl_close($this->ch);
3090  return false;
3091  } else {
3092  //echo '<pre>';
3093  //var_dump(curl_getinfo($this->ch));
3094  //echo '</pre>';
3095  }
3096  // close curl
3097  $this->debug('No cURL error, closing cURL');
3098  curl_close($this->ch);
3099 
3100  // try removing skippable headers
3101  $savedata = $data;
3102  while ($this->isSkippableCurlHeader($data)) {
3103  $this->debug("Found HTTP header to skip");
3104  if ($pos = strpos($data,"\r\n\r\n")) {
3105  $data = ltrim(substr($data,$pos));
3106  } elseif($pos = strpos($data,"\n\n") ) {
3107  $data = ltrim(substr($data,$pos));
3108  }
3109  }
3110 
3111  if ($data == '') {
3112  // have nothing left; just remove 100 header(s)
3113  $data = $savedata;
3114  while (preg_match('/^HTTP\/1.1 100/',$data)) {
3115  if ($pos = strpos($data,"\r\n\r\n")) {
3116  $data = ltrim(substr($data,$pos));
3117  } elseif($pos = strpos($data,"\n\n") ) {
3118  $data = ltrim(substr($data,$pos));
3119  }
3120  }
3121  }
3122 
3123  // separate content from HTTP headers
3124  if ($pos = strpos($data,"\r\n\r\n")) {
3125  $lb = "\r\n";
3126  } elseif( $pos = strpos($data,"\n\n")) {
3127  $lb = "\n";
3128  } else {
3129  $this->debug('no proper separation of headers and document');
3130  $this->setError('no proper separation of headers and document');
3131  return false;
3132  }
3133  $header_data = trim(substr($data,0,$pos));
3134  $header_array = explode($lb,$header_data);
3135  $data = ltrim(substr($data,$pos));
3136  $this->debug('found proper separation of headers and document');
3137  $this->debug('cleaned data, stringlen: '.strlen($data));
3138  // clean headers
3139  foreach ($header_array as $header_line) {
3140  $arr = explode(':',$header_line,2);
3141  if(count($arr) > 1){
3142  $header_name = strtolower(trim($arr[0]));
3143  $this->incoming_headers[$header_name] = trim($arr[1]);
3144  if ($header_name == 'set-cookie') {
3145  // TODO: allow multiple cookies from parseCookie
3146  $cookie = $this->parseCookie(trim($arr[1]));
3147  if ($cookie) {
3148  $this->incoming_cookies[] = $cookie;
3149  $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3150  } else {
3151  $this->debug('did not find cookie in ' . trim($arr[1]));
3152  }
3153  }
3154  } else if (isset($header_name)) {
3155  // append continuation line to previous header
3156  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3157  }
3158  }
3159  }
3160 
3161  $this->response_status_line = $header_array[0];
3162  $arr = explode(' ', $this->response_status_line, 3);
3163  $http_version = $arr[0];
3164  $http_status = intval($arr[1]);
3165  $http_reason = count($arr) > 2 ? $arr[2] : '';
3166 
3167  // see if we need to resend the request with http digest authentication
3168  if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3169  $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3170  $this->setURL($this->incoming_headers['location']);
3171  $this->tryagain = true;
3172  return false;
3173  }
3174 
3175  // see if we need to resend the request with http digest authentication
3176  if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3177  $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3178  if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3179  $this->debug('Server wants digest authentication');
3180  // remove "Digest " from our elements
3181  $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3182 
3183  // parse elements into array
3184  $digestElements = explode(',', $digestString);
3185  foreach ($digestElements as $val) {
3186  $tempElement = explode('=', trim($val), 2);
3187  $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3188  }
3189 
3190  // should have (at least) qop, realm, nonce
3191  if (isset($digestRequest['nonce'])) {
3192  $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3193  $this->tryagain = true;
3194  return false;
3195  }
3196  }
3197  $this->debug('HTTP authentication failed');
3198  $this->setError('HTTP authentication failed');
3199  return false;
3200  }
3201 
3202  if (
3203  ($http_status >= 300 && $http_status <= 307) ||
3204  ($http_status >= 400 && $http_status <= 417) ||
3205  ($http_status >= 501 && $http_status <= 505)
3206  ) {
3207  $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3208  return false;
3209  }
3210 
3211  // decode content-encoding
3212  if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
3213  if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
3214  // if decoding works, use it. else assume data wasn't gzencoded
3215  if(function_exists('gzinflate')){
3216  //$timer->setMarker('starting decoding of gzip/deflated content');
3217  // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3218  // this means there are no Zlib headers, although there should be
3219  $this->debug('The gzinflate function exists');
3220  $datalen = strlen($data);
3221  if ($this->incoming_headers['content-encoding'] == 'deflate') {
3222  if ($degzdata = @gzinflate($data)) {
3223  $data = $degzdata;
3224  $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3225  if (strlen($data) < $datalen) {
3226  // test for the case that the payload has been compressed twice
3227  $this->debug('The inflated payload is smaller than the gzipped one; try again');
3228  if ($degzdata = @gzinflate($data)) {
3229  $data = $degzdata;
3230  $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3231  }
3232  }
3233  } else {
3234  $this->debug('Error using gzinflate to inflate the payload');
3235  $this->setError('Error using gzinflate to inflate the payload');
3236  }
3237  } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3238  if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
3239  $data = $degzdata;
3240  $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3241  if (strlen($data) < $datalen) {
3242  // test for the case that the payload has been compressed twice
3243  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3244  if ($degzdata = @gzinflate(substr($data, 10))) {
3245  $data = $degzdata;
3246  $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3247  }
3248  }
3249  } else {
3250  $this->debug('Error using gzinflate to un-gzip the payload');
3251  $this->setError('Error using gzinflate to un-gzip the payload');
3252  }
3253  }
3254  //$timer->setMarker('finished decoding of gzip/deflated content');
3255  //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3256  // set decoded payload
3257  $this->incoming_payload = $header_data.$lb.$lb.$data;
3258  } else {
3259  $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3260  $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3261  }
3262  } else {
3263  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3264  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3265  }
3266  } else {
3267  $this->debug('No Content-Encoding header');
3268  }
3269 
3270  if(strlen($data) == 0){
3271  $this->debug('no data after headers!');
3272  $this->setError('no data present after HTTP headers');
3273  return false;
3274  }
3275 
3276  return $data;
3277  }
3278 
3286  function setContentType($type, $charset = false) {
3287  $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3288  }
3289 
3297  if (isset($this->outgoing_headers['Accept-Encoding'])) {
3298  return false;
3299  }
3300  $this->protocol_version = '1.1';
3301  $this->persistentConnection = true;
3302  $this->setHeader('Connection', 'Keep-Alive');
3303  return true;
3304  }
3305 
3313  /*
3314  * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3315  */
3316  function parseCookie($cookie_str) {
3317  $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3318  $data = split(';', $cookie_str);
3319  $value_str = $data[0];
3320 
3321  $cookie_param = 'domain=';
3322  $start = strpos($cookie_str, $cookie_param);
3323  if ($start > 0) {
3324  $domain = substr($cookie_str, $start + strlen($cookie_param));
3325  $domain = substr($domain, 0, strpos($domain, ';'));
3326  } else {
3327  $domain = '';
3328  }
3329 
3330  $cookie_param = 'expires=';
3331  $start = strpos($cookie_str, $cookie_param);
3332  if ($start > 0) {
3333  $expires = substr($cookie_str, $start + strlen($cookie_param));
3334  $expires = substr($expires, 0, strpos($expires, ';'));
3335  } else {
3336  $expires = '';
3337  }
3338 
3339  $cookie_param = 'path=';
3340  $start = strpos($cookie_str, $cookie_param);
3341  if ( $start > 0 ) {
3342  $path = substr($cookie_str, $start + strlen($cookie_param));
3343  $path = substr($path, 0, strpos($path, ';'));
3344  } else {
3345  $path = '/';
3346  }
3347 
3348  $cookie_param = ';secure;';
3349  if (strpos($cookie_str, $cookie_param) !== FALSE) {
3350  $secure = true;
3351  } else {
3352  $secure = false;
3353  }
3354 
3355  $sep_pos = strpos($value_str, '=');
3356 
3357  if ($sep_pos) {
3358  $name = substr($value_str, 0, $sep_pos);
3359  $value = substr($value_str, $sep_pos + 1);
3360  $cookie= array( 'name' => $name,
3361  'value' => $value,
3362  'domain' => $domain,
3363  'path' => $path,
3364  'expires' => $expires,
3365  'secure' => $secure
3366  );
3367  return $cookie;
3368  }
3369  return false;
3370  }
3371 
3380  function getCookiesForRequest($cookies, $secure=false) {
3381  $cookie_str = '';
3382  if ((! is_null($cookies)) && (is_array($cookies))) {
3383  foreach ($cookies as $cookie) {
3384  if (! is_array($cookie)) {
3385  continue;
3386  }
3387  $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
3388  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3389  if (strtotime($cookie['expires']) <= time()) {
3390  $this->debug('cookie has expired');
3391  continue;
3392  }
3393  }
3394  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3395  $domain = preg_quote($cookie['domain']);
3396  if (! preg_match("'.*$domain$'i", $this->host)) {
3397  $this->debug('cookie has different domain');
3398  continue;
3399  }
3400  }
3401  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3402  $path = preg_quote($cookie['path']);
3403  if (! preg_match("'^$path.*'i", $this->path)) {
3404  $this->debug('cookie is for a different path');
3405  continue;
3406  }
3407  }
3408  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3409  $this->debug('cookie is secure, transport is not');
3410  continue;
3411  }
3412  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3413  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3414  }
3415  }
3416  return $cookie_str;
3417  }
3418 }
3419 
3420 ?><?php
3421 
3422 
3423 
3440  var $headers = array();
3446  var $request = '';
3458  var $requestHeader = NULL;
3464  var $document = '';
3470  var $requestSOAP = '';
3476  var $methodURI = '';
3482  var $methodname = '';
3488  var $methodparams = array();
3494  var $SOAPAction = '';
3500  var $xml_encoding = '';
3506  var $decode_utf8 = true;
3507 
3513  var $outgoing_headers = array();
3519  var $response = '';
3531  var $responseSOAP = '';
3537  var $methodreturn = false;
3549  var $fault = false;
3555  var $result = 'successful';
3556 
3563  var $operations = array();
3569  var $wsdl = false;
3575  var $externalWSDLURL = false;
3581  var $debug_flag = false;
3582 
3583 
3591  function nusoap_server($wsdl=false){
3593  // turn on debugging?
3594  global $debug;
3595  global $HTTP_SERVER_VARS;
3596 
3597  if (isset($_SERVER)) {
3598  $this->debug("_SERVER is defined:");
3599  $this->appendDebug($this->varDump($_SERVER));
3600  } elseif (isset($HTTP_SERVER_VARS)) {
3601  $this->debug("HTTP_SERVER_VARS is defined:");
3602  $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3603  } else {
3604  $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3605  }
3606 
3607  if (isset($debug)) {
3608  $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3609  $this->debug_flag = $debug;
3610  } elseif (isset($_SERVER['QUERY_STRING'])) {
3611  $qs = explode('&', $_SERVER['QUERY_STRING']);
3612  foreach ($qs as $v) {
3613  if (substr($v, 0, 6) == 'debug=') {
3614  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3615  $this->debug_flag = substr($v, 6);
3616  }
3617  }
3618  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3619  $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3620  foreach ($qs as $v) {
3621  if (substr($v, 0, 6) == 'debug=') {
3622  $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3623  $this->debug_flag = substr($v, 6);
3624  }
3625  }
3626  }
3627 
3628  // wsdl
3629  if($wsdl){
3630  $this->debug("In nusoap_server, WSDL is specified");
3631  if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3632  $this->wsdl = $wsdl;
3633  $this->externalWSDLURL = $this->wsdl->wsdl;
3634  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3635  } else {
3636  $this->debug('Create wsdl from ' . $wsdl);
3637  $this->wsdl = new wsdl($wsdl);
3638  $this->externalWSDLURL = $wsdl;
3639  }
3640  $this->appendDebug($this->wsdl->getDebug());
3641  $this->wsdl->clearDebug();
3642  if($err = $this->wsdl->getError()){
3643  die('WSDL ERROR: '.$err);
3644  }
3645  }
3646  }
3647 
3654  function service($data){
3655  global $HTTP_SERVER_VARS;
3656 
3657  if (isset($_SERVER['QUERY_STRING'])) {
3658  $qs = $_SERVER['QUERY_STRING'];
3659  } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3660  $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3661  } else {
3662  $qs = '';
3663  }
3664  $this->debug("In service, query string=$qs");
3665 
3666  if (preg_match('/wsdl/', $qs) ){
3667  $this->debug("In service, this is a request for WSDL");
3668  if($this->externalWSDLURL){
3669  if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
3670  header('Location: '.$this->externalWSDLURL);
3671  } else { // assume file
3672  header("Content-Type: text/xml\r\n");
3673  $fp = fopen($this->externalWSDLURL, 'r');
3674  fpassthru($fp);
3675  }
3676  } elseif ($this->wsdl) {
3677  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3678  print $this->wsdl->serialize($this->debug_flag);
3679  if ($this->debug_flag) {
3680  $this->debug('wsdl:');
3681  $this->appendDebug($this->varDump($this->wsdl));
3682  print $this->getDebugAsXMLComment();
3683  }
3684  } else {
3685  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3686  print "This service does not provide WSDL";
3687  }
3688  } elseif ($data == '' && $this->wsdl) {
3689  $this->debug("In service, there is no data, so return Web description");
3690  print $this->wsdl->webDescription();
3691  } else {
3692  $this->debug("In service, invoke the request");
3693  $this->parse_request($data);
3694  if (! $this->fault) {
3695  $this->invoke_method();
3696  }
3697  if (! $this->fault) {
3698  $this->serialize_return();
3699  }
3700  $this->send_response();
3701  }
3702  }
3703 
3716  function parse_http_headers() {
3717  global $HTTP_SERVER_VARS;
3718 
3719  $this->request = '';
3720  $this->SOAPAction = '';
3721  if(function_exists('getallheaders')){
3722  $this->debug("In parse_http_headers, use getallheaders");
3723  $headers = getallheaders();
3724  foreach($headers as $k=>$v){
3725  $k = strtolower($k);
3726  $this->headers[$k] = $v;
3727  $this->request .= "$k: $v\r\n";
3728  $this->debug("$k: $v");
3729  }
3730  // get SOAPAction header
3731  if(isset($this->headers['soapaction'])){
3732  $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
3733  }
3734  // get the character encoding of the incoming request
3735  if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
3736  $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
3737  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
3738  $this->xml_encoding = strtoupper($enc);
3739  } else {
3740  $this->xml_encoding = 'US-ASCII';
3741  }
3742  } else {
3743  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3744  $this->xml_encoding = 'ISO-8859-1';
3745  }
3746  } elseif(isset($_SERVER) && is_array($_SERVER)){
3747  $this->debug("In parse_http_headers, use _SERVER");
3748  foreach ($_SERVER as $k => $v) {
3749  if (substr($k, 0, 5) == 'HTTP_') {
3750  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3751  } else {
3752  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3753  }
3754  if ($k == 'soapaction') {
3755  // get SOAPAction header
3756  $k = 'SOAPAction';
3757  $v = str_replace('"', '', $v);
3758  $v = str_replace('\\', '', $v);
3759  $this->SOAPAction = $v;
3760  } else if ($k == 'content-type') {
3761  // get the character encoding of the incoming request
3762  if (strpos($v, '=')) {
3763  $enc = substr(strstr($v, '='), 1);
3764  $enc = str_replace('"', '', $enc);
3765  $enc = str_replace('\\', '', $enc);
3766  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
3767  $this->xml_encoding = strtoupper($enc);
3768  } else {
3769  $this->xml_encoding = 'US-ASCII';
3770  }
3771  } else {
3772  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3773  $this->xml_encoding = 'ISO-8859-1';
3774  }
3775  }
3776  $this->headers[$k] = $v;
3777  $this->request .= "$k: $v\r\n";
3778  $this->debug("$k: $v");
3779  }
3780  } elseif (is_array($HTTP_SERVER_VARS)) {
3781  $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3782  foreach ($HTTP_SERVER_VARS as $k => $v) {
3783  if (substr($k, 0, 5) == 'HTTP_') {
3784  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5));
3785  } else {
3786  $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k);
3787  }
3788  if ($k == 'soapaction') {
3789  // get SOAPAction header
3790  $k = 'SOAPAction';
3791  $v = str_replace('"', '', $v);
3792  $v = str_replace('\\', '', $v);
3793  $this->SOAPAction = $v;
3794  } else if ($k == 'content-type') {
3795  // get the character encoding of the incoming request
3796  if (strpos($v, '=')) {
3797  $enc = substr(strstr($v, '='), 1);
3798  $enc = str_replace('"', '', $enc);
3799  $enc = str_replace('\\', '', $enc);
3800  if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
3801  $this->xml_encoding = strtoupper($enc);
3802  } else {
3803  $this->xml_encoding = 'US-ASCII';
3804  }
3805  } else {
3806  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3807  $this->xml_encoding = 'ISO-8859-1';
3808  }
3809  }
3810  $this->headers[$k] = $v;
3811  $this->request .= "$k: $v\r\n";
3812  $this->debug("$k: $v");
3813  }
3814  } else {
3815  $this->debug("In parse_http_headers, HTTP headers not accessible");
3816  $this->setError("HTTP headers not accessible");
3817  }
3818  }
3819 
3842  function parse_request($data='') {
3843  $this->debug('entering parse_request()');
3844  $this->parse_http_headers();
3845  $this->debug('got character encoding: '.$this->xml_encoding);
3846  // uncompress if necessary
3847  if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3848  $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3849  if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3850  // if decoding works, use it. else assume data wasn't gzencoded
3851  if (function_exists('gzuncompress')) {
3852  if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3853  $data = $degzdata;
3854  } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3855  $data = $degzdata;
3856  } else {
3857  $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3858  return;
3859  }
3860  } else {
3861  $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3862  return;
3863  }
3864  }
3865  }
3866  $this->request .= "\r\n".$data;
3867  $data = $this->parseRequest($this->headers, $data);
3868  $this->requestSOAP = $data;
3869  $this->debug('leaving parse_request');
3870  }
3871 
3889  function invoke_method() {
3890  $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3891 
3892  if ($this->wsdl) {
3893  if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3894  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3895  $this->appendDebug('opData=' . $this->varDump($this->opData));
3896  } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3897  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3898  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3899  $this->appendDebug('opData=' . $this->varDump($this->opData));
3900  $this->methodname = $this->opData['name'];
3901  } else {
3902  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3903  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3904  return;
3905  }
3906  } else {
3907  $this->debug('in invoke_method, no WSDL to validate method');
3908  }
3909 
3910  // if a . is present in $this->methodname, we see if there is a class in scope,
3911  // which could be referred to. We will also distinguish between two deliminators,
3912  // to allow methods to be called a the class or an instance
3913  $class = '';
3914  $method = '';
3915  if (strpos($this->methodname, '..') > 0) {
3916  $delim = '..';
3917  } else if (strpos($this->methodname, '.') > 0) {
3918  $delim = '.';
3919  } else {
3920  $delim = '';
3921  }
3922 
3923  if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3924  class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3925  // get the class and method name
3926  $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3927  $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3928  $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3929  }
3930  // set class handler
3931  // added to support single operations
3932  if ($class == '' && $this->class !='')
3933  {
3934  $class = $this->class;
3935  $delim = "..";
3936  $method = $this->methodname;
3937  }
3938 
3939  // does method exist?
3940  if ($class == '') {
3941  if (!function_exists($this->methodname)) {
3942  $this->debug("in invoke_method, function '$this->methodname' not found!");
3943  $this->result = 'fault: method not found';
3944  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3945  return;
3946  }
3947  } else {
3948  $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
3949  if (!in_array($method_to_compare, get_class_methods($class))) {
3950  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
3951  $this->result = 'fault: method not found';
3952  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3953  return;
3954  }
3955  }
3956 
3957  // evaluate message, getting back parameters
3958  // verify that request parameters match the method's signature
3959  if(! $this->verify_method($this->methodname,$this->methodparams)){
3960  // debug
3961  $this->debug('ERROR: request not verified against method signature');
3962  $this->result = 'fault: request failed validation against method signature';
3963  // return fault
3964  $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
3965  return;
3966  }
3967 
3968  // if there are parameters to pass
3969  $this->debug('in invoke_method, params:');
3970  $this->appendDebug($this->varDump($this->methodparams));
3971  $this->debug("in invoke_method, calling '$this->methodname'");
3972  if (!function_exists('call_user_func_array')) {
3973  if ($class == '') {
3974  $this->debug('in invoke_method, calling function using eval()');
3975  $funcCall = "\$this->methodreturn = $this->methodname(";
3976  } else {
3977  if ($delim == '..') {
3978  $this->debug('in invoke_method, calling class method using eval()');
3979  $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
3980  } else {
3981  $this->debug('in invoke_method, calling instance method using eval()');
3982  // generate unique instance name
3983  $instname = "\$inst_".time();
3984  $funcCall = $instname." = new ".$class."(); ";
3985  $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
3986  }
3987  }
3988  if ($this->methodparams) {
3989  foreach ($this->methodparams as $param) {
3990  if (is_array($param) || is_object($param)) {
3991  $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
3992  return;
3993  }
3994  $funcCall .= "\"$param\",";
3995  }
3996  $funcCall = substr($funcCall, 0, -1);
3997  }
3998  $funcCall .= ');';
3999  $this->debug('in invoke_method, function call: '.$funcCall);
4000  @eval($funcCall);
4001  } else {
4002  if ($class == '') {
4003  $this->debug('in invoke_method, calling function using call_user_func_array()');
4004  $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
4005  } elseif ($delim == '..') {
4006  $this->debug('in invoke_method, calling class method using call_user_func_array()');
4007  $call_arg = array ($class, $method);
4008  } else {
4009  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4010  $instance = new $class ();
4011  $call_arg = array(&$instance, $method);
4012  }
4013  if (is_array($this->methodparams)) {
4014  $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4015  } else {
4016  $this->methodreturn = call_user_func_array($call_arg, array());
4017  }
4018  }
4019  $this->debug('in invoke_method, methodreturn:');
4020  $this->appendDebug($this->varDump($this->methodreturn));
4021  $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
4022  }
4023 
4035  function serialize_return() {
4036  $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4037  // if fault
4038  if (isset($this->methodreturn) && ((get_class((object)$this->methodreturn) == 'soap_fault') || (get_class((object)$this->methodreturn) == 'nusoap_fault'))) {
4039  $this->debug('got a fault object from method');
4040  $this->fault = $this->methodreturn;
4041  return;
4042  } elseif ($this->methodreturnisliteralxml) {
4043  $return_val = $this->methodreturn;
4044  // returned value(s)
4045  } else {
4046  $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
4047  $this->debug('serializing return value');
4048  if($this->wsdl){
4049  if (sizeof($this->opData['output']['parts']) > 1) {
4050  $this->debug('more than one output part, so use the method return unchanged');
4051  $opParams = $this->methodreturn;
4052  } elseif (sizeof($this->opData['output']['parts']) == 1) {
4053  $this->debug('exactly one output part, so wrap the method return in a simple array');
4054  // TODO: verify that it is not already wrapped!
4055  //foreach ($this->opData['output']['parts'] as $name => $type) {
4056  // $this->debug('wrap in element named ' . $name);
4057  //}
4058  $opParams = array($this->methodreturn);
4059  }
4060  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
4061  $this->appendDebug($this->wsdl->getDebug());
4062  $this->wsdl->clearDebug();
4063  if($errstr = $this->wsdl->getError()){
4064  $this->debug('got wsdl error: '.$errstr);
4065  $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4066  return;
4067  }
4068  } else {
4069  if (isset($this->methodreturn)) {
4070  $return_val = $this->serialize_val($this->methodreturn, 'return');
4071  } else {
4072  $return_val = '';
4073  $this->debug('in absence of WSDL, assume void return for backward compatibility');
4074  }
4075  }
4076  }
4077  $this->debug('return value:');
4078  $this->appendDebug($this->varDump($return_val));
4079 
4080  $this->debug('serializing response');
4081  if ($this->wsdl) {
4082  $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4083  if ($this->opData['style'] == 'rpc') {
4084  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4085  if ($this->opData['output']['use'] == 'literal') {
4086  // 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
4087  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4088  } else {
4089  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4090  }
4091  } else {
4092  $this->debug('style is not rpc for serialization: assume document');
4093  $payload = $return_val;
4094  }
4095  } else {
4096  $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4097  $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4098  }
4099  $this->result = 'successful';
4100  if($this->wsdl){
4101  //if($this->debug_flag){
4102  $this->appendDebug($this->wsdl->getDebug());
4103  // }
4104  if (isset($opData['output']['encodingStyle'])) {
4105  $encodingStyle = $opData['output']['encodingStyle'];
4106  } else {
4107  $encodingStyle = '';
4108  }
4109  // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4110  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
4111  } else {
4112  $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
4113  }
4114  $this->debug("Leaving serialize_return");
4115  }
4116 
4127  function send_response() {
4128  $this->debug('Enter send_response');
4129  if ($this->fault) {
4130  $payload = $this->fault->serialize();
4131  $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4132  $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4133  } else {
4134  $payload = $this->responseSOAP;
4135  // Some combinations of PHP+Web server allow the Status
4136  // to come through as a header. Since OK is the default
4137  // just do nothing.
4138  // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
4139  // $this->outgoing_headers[] = "Status: 200 OK";
4140  }
4141  // add debug data if in debug mode
4142  if(isset($this->debug_flag) && $this->debug_flag){
4143  $payload .= $this->getDebugAsXMLComment();
4144  }
4145  $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4146  preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4147  $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
4148  // Let the Web server decide about this
4149  //$this->outgoing_headers[] = "Connection: Close\r\n";
4150  $payload = $this->getHTTPBody($payload);
4151  $type = $this->getHTTPContentType();
4152  $charset = $this->getHTTPContentTypeCharset();
4153  $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4154  //begin code to compress payload - by John
4155  // NOTE: there is no way to know whether the Web server will also compress
4156  // this data.
4157  if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4158  if (strstr($this->headers['accept-encoding'], 'gzip')) {
4159  if (function_exists('gzencode')) {
4160  if (isset($this->debug_flag) && $this->debug_flag) {
4161  $payload .= "<!-- Content being gzipped -->";
4162  }
4163  $this->outgoing_headers[] = "Content-Encoding: gzip";
4164  $payload = gzencode($payload);
4165  } else {
4166  if (isset($this->debug_flag) && $this->debug_flag) {
4167  $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4168  }
4169  }
4170  } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4171  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4172  // instead of gzcompress output,
4173  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4174  if (function_exists('gzdeflate')) {
4175  if (isset($this->debug_flag) && $this->debug_flag) {
4176  $payload .= "<!-- Content being deflated -->";
4177  }
4178  $this->outgoing_headers[] = "Content-Encoding: deflate";
4179  $payload = gzdeflate($payload);
4180  } else {
4181  if (isset($this->debug_flag) && $this->debug_flag) {
4182  $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4183  }
4184  }
4185  }
4186  }
4187  //end code
4188  $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
4189  reset($this->outgoing_headers);
4190  foreach($this->outgoing_headers as $hdr){
4191  header($hdr, false);
4192  }
4193  print $payload;
4194  $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
4195  }
4196 
4206  function verify_method($operation,$request){
4207  if(isset($this->wsdl) && is_object($this->wsdl)){
4208  if($this->wsdl->getOperationData($operation)){
4209  return true;
4210  }
4211  } elseif(isset($this->operations[$operation])){
4212  return true;
4213  }
4214  return false;
4215  }
4216 
4226  $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
4227  if (!strstr($headers['content-type'], 'text/xml')) {
4228  $this->setError('Request not of type text/xml');
4229  return false;
4230  }
4231  if (strpos($headers['content-type'], '=')) {
4232  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4233  $this->debug('Got response encoding: ' . $enc);
4234  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
4235  $this->xml_encoding = strtoupper($enc);
4236  } else {
4237  $this->xml_encoding = 'US-ASCII';
4238  }
4239  } else {
4240  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4241  $this->xml_encoding = 'ISO-8859-1';
4242  }
4243  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4244  // parse response, get soap parser obj
4245  $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
4246  // parser debug
4247  $this->debug("parser debug: \n".$parser->getDebug());
4248  // if fault occurred during message parsing
4249  if($err = $parser->getError()){
4250  $this->result = 'fault: error in msg parsing: '.$err;
4251  $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
4252  // else successfully parsed request into soapval object
4253  } else {
4254  // get/set methodname
4255  $this->methodURI = $parser->root_struct_namespace;
4256  $this->methodname = $parser->root_struct_name;
4257  $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
4258  $this->debug('calling parser->get_soapbody()');
4259  $this->methodparams = $parser->get_soapbody();
4260  // get SOAP headers
4261  $this->requestHeaders = $parser->getHeaders();
4262  // get SOAP Header
4263  $this->requestHeader = $parser->get_soapheader();
4264  // add document for doclit support
4265  $this->document = $parser->document;
4266  }
4267  }
4268 
4276  function getHTTPBody($soapmsg) {
4277  return $soapmsg;
4278  }
4279 
4288  function getHTTPContentType() {
4289  return 'text/xml';
4290  }
4291 
4302  return $this->soap_defencoding;
4303  }
4304 
4315  $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
4316  }
4317 
4332  function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
4333  global $HTTP_SERVER_VARS;
4334 
4335  if($this->externalWSDLURL){
4336  die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4337  }
4338  if (! $name) {
4339  die('You must specify a name when you register an operation');
4340  }
4341  if (!is_array($in)) {
4342  die('You must provide an array for operation inputs');
4343  }
4344  if (!is_array($out)) {
4345  die('You must provide an array for operation outputs');
4346  }
4347  if(false == $namespace) {
4348  }
4349  if(false == $soapaction) {
4350  if (isset($_SERVER)) {
4351  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4352  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4353  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4354  } elseif (isset($HTTP_SERVER_VARS)) {
4355  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4356  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4357  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4358  } else {
4359  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4360  }
4361  if ($HTTPS == '1' || $HTTPS == 'on') {
4362  $SCHEME = 'https';
4363  } else {
4364  $SCHEME = 'http';
4365  }
4366  $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4367  }
4368  if(false == $style) {
4369  $style = "rpc";
4370  }
4371  if(false == $use) {
4372  $use = "encoded";
4373  }
4374  if ($use == 'encoded' && $encodingStyle = '') {
4375  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4376  }
4377 
4378  $this->operations[$name] = array(
4379  'name' => $name,
4380  'in' => $in,
4381  'out' => $out,
4382  'namespace' => $namespace,
4383  'soapaction' => $soapaction,
4384  'style' => $style);
4385  if($this->wsdl){
4386  $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
4387  }
4388  return true;
4389  }
4390 
4401  function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
4402  if ($faultdetail == '' && $this->debug_flag) {
4403  $faultdetail = $this->getDebug();
4404  }
4405  $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
4406  $this->fault->soap_defencoding = $this->soap_defencoding;
4407  }
4408 
4420  function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4421  {
4422  global $HTTP_SERVER_VARS;
4423 
4424  if (isset($_SERVER)) {
4425  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4426  $SERVER_PORT = $_SERVER['SERVER_PORT'];
4427  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4428  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4429  } elseif (isset($HTTP_SERVER_VARS)) {
4430  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4431  $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4432  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4433  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4434  } else {
4435  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4436  }
4437  // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4438  $colon = strpos($SERVER_NAME,":");
4439  if ($colon) {
4440  $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4441  }
4442  if ($SERVER_PORT == 80) {
4443  $SERVER_PORT = '';
4444  } else {
4445  $SERVER_PORT = ':' . $SERVER_PORT;
4446  }
4447  if(false == $namespace) {
4448  $namespace = "http://$SERVER_NAME/soap/$serviceName";
4449  }
4450 
4451  if(false == $endpoint) {
4452  if ($HTTPS == '1' || $HTTPS == 'on') {
4453  $SCHEME = 'https';
4454  } else {
4455  $SCHEME = 'http';
4456  }
4457  $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4458  }
4459 
4460  if(false == $schemaTargetNamespace) {
4461  $schemaTargetNamespace = $namespace;
4462  }
4463 
4464  $this->wsdl = new wsdl;
4465  $this->wsdl->serviceName = $serviceName;
4466  $this->wsdl->endpoint = $endpoint;
4467  $this->wsdl->namespaces['tns'] = $namespace;
4468  $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4469  $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4470  if ($schemaTargetNamespace != $namespace) {
4471  $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4472  }
4473  $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4474  if ($style == 'document') {
4475  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4476  }
4477  $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4478  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4479  $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4480  $this->wsdl->bindings[$serviceName.'Binding'] = array(
4481  'name'=>$serviceName.'Binding',
4482  'style'=>$style,
4483  'transport'=>$transport,
4484  'portType'=>$serviceName.'PortType');
4485  $this->wsdl->ports[$serviceName.'Port'] = array(
4486  'binding'=>$serviceName.'Binding',
4487  'location'=>$endpoint,
4488  'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
4489  }
4490 }
4491 
4495 class soap_server extends nusoap_server {
4496 }
4497 
4498 ?><?php
4499 
4500 
4501 
4511 class wsdl extends nusoap_base {
4512  // URL or filename of the root of this WSDL
4513  var $wsdl;
4514  // define internal arrays of bindings, ports, operations, messages, etc.
4515  var $schemas = array();
4516  var $currentSchema;
4517  var $message = array();
4518  var $complexTypes = array();
4519  var $messages = array();
4520  var $currentMessage;
4521  var $currentOperation;
4522  var $portTypes = array();
4523  var $currentPortType;
4524  var $bindings = array();
4525  var $currentBinding;
4526  var $ports = array();
4527  var $currentPort;
4528  var $opData = array();
4529  var $status = '';
4530  var $documentation = false;
4531  var $endpoint = '';
4532  // array of wsdl docs to import
4533  var $import = array();
4534  // parser vars
4535  var $parser;
4536  var $position = 0;
4537  var $depth = 0;
4538  var $depth_array = array();
4539  // for getting wsdl
4540  var $proxyhost = '';
4541  var $proxyport = '';
4542  var $proxyusername = '';
4543  var $proxypassword = '';
4544  var $timeout = 0;
4545  var $response_timeout = 30;
4546  var $curl_options = array(); // User-specified cURL options
4547  var $use_curl = false; // whether to always try to use cURL
4548  // for HTTP authentication
4549  var $username = ''; // Username for HTTP authentication
4550  var $password = ''; // Password for HTTP authentication
4551  var $authtype = ''; // Type of HTTP authentication
4552  var $certRequest = array(); // Certificate for HTTP SSL authentication
4553 
4570  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4571  $this->proxyhost = $proxyhost;
4572  $this->proxyport = $proxyport;
4573  $this->proxyusername = $proxyusername;
4574  $this->proxypassword = $proxypassword;
4575  $this->timeout = $timeout;
4576  $this->response_timeout = $response_timeout;
4577  if (is_array($curl_options))
4578  $this->curl_options = $curl_options;
4579  $this->use_curl = $use_curl;
4580  $this->fetchWSDL($wsdl);
4581  }
4582 
4588  function fetchWSDL($wsdl) {
4589  $this->debug("parse and process WSDL path=$wsdl");
4590  $this->wsdl = $wsdl;
4591  // parse wsdl file
4592  if ($this->wsdl != "") {
4593  $this->parseWSDL($this->wsdl);
4594  }
4595  // imports
4596  // TODO: handle imports more properly, grabbing them in-line and nesting them
4597  $imported_urls = array();
4598  $imported = 1;
4599  while ($imported > 0) {
4600  $imported = 0;
4601  // Schema imports
4602  foreach ($this->schemas as $ns => $list) {
4603  foreach ($list as $xs) {
4604  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4605  foreach ($xs->imports as $ns2 => $list2) {
4606  for ($ii = 0; $ii < count($list2); $ii++) {
4607  if (! $list2[$ii]['loaded']) {
4608  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4609  $url = $list2[$ii]['location'];
4610  if ($url != '') {
4611  $urlparts = parse_url($url);
4612  if (!isset($urlparts['host'])) {
4613  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
4614  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4615  }
4616  if (! in_array($url, $imported_urls)) {
4617  $this->parseWSDL($url);
4618  $imported++;
4619  $imported_urls[] = $url;
4620  }
4621  } else {
4622  $this->debug("Unexpected scenario: empty URL for unloaded import");
4623  }
4624  }
4625  }
4626  }
4627  }
4628  }
4629  // WSDL imports
4630  $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
4631  foreach ($this->import as $ns => $list) {
4632  for ($ii = 0; $ii < count($list); $ii++) {
4633  if (! $list[$ii]['loaded']) {
4634  $this->import[$ns][$ii]['loaded'] = true;
4635  $url = $list[$ii]['location'];
4636  if ($url != '') {
4637  $urlparts = parse_url($url);
4638  if (!isset($urlparts['host'])) {
4639  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4640  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4641  }
4642  if (! in_array($url, $imported_urls)) {
4643  $this->parseWSDL($url);
4644  $imported++;
4645  $imported_urls[] = $url;
4646  }
4647  } else {
4648  $this->debug("Unexpected scenario: empty URL for unloaded import");
4649  }
4650  }
4651  }
4652  }
4653  }
4654  // add new data to operation data
4655  foreach($this->bindings as $binding => $bindingData) {
4656  if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4657  foreach($bindingData['operations'] as $operation => $data) {
4658  $this->debug('post-parse data gathering for ' . $operation);
4659  $this->bindings[$binding]['operations'][$operation]['input'] =
4660  isset($this->bindings[$binding]['operations'][$operation]['input']) ?
4661  array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4662  $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4663  $this->bindings[$binding]['operations'][$operation]['output'] =
4664  isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4665  array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4666  $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4667  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
4668  $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4669  }
4670  if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
4671  $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4672  }
4673  // Set operation style if necessary, but do not override one already provided
4674  if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4675  $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4676  }
4677  $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4678  $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4679  $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4680  }
4681  }
4682  }
4683  }
4684 
4691  function parseWSDL($wsdl = '') {
4692  $this->debug("parse WSDL at path=$wsdl");
4693 
4694  if ($wsdl == '') {
4695  $this->debug('no wsdl passed to parseWSDL()!!');
4696  $this->setError('no wsdl passed to parseWSDL()!!');
4697  return false;
4698  }
4699 
4700  // parse $wsdl for url format
4701  $wsdl_props = parse_url($wsdl);
4702 
4703  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4704  $this->debug('getting WSDL http(s) URL ' . $wsdl);
4705  // get wsdl
4706  $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4707  $tr->request_method = 'GET';
4708  $tr->useSOAPAction = false;
4709  if($this->proxyhost && $this->proxyport){
4710  $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
4711  }
4712  if ($this->authtype != '') {
4713  $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4714  }
4715  $tr->setEncoding('gzip, deflate');
4716  $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4717  //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4718  //$this->debug("WSDL response\n" . $tr->incoming_payload);
4719  $this->appendDebug($tr->getDebug());
4720  // catch errors
4721  if($err = $tr->getError() ){
4722  $errstr = 'HTTP ERROR: '.$err;
4723  $this->debug($errstr);
4724  $this->setError($errstr);
4725  unset($tr);
4726  return false;
4727  }
4728  unset($tr);
4729  $this->debug("got WSDL URL");
4730  } else {
4731  // $wsdl is not http(s), so treat it as a file URL or plain file path
4732  if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4733  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4734  } else {
4735  $path = $wsdl;
4736  }
4737  $this->debug('getting WSDL file ' . $path);
4738  if ($fp = @fopen($path, 'r')) {
4739  $wsdl_string = '';
4740  while ($data = fread($fp, 32768)) {
4741  $wsdl_string .= $data;
4742  }
4743  fclose($fp);
4744  } else {
4745  $errstr = "Bad path to WSDL file $path";
4746  $this->debug($errstr);
4747  $this->setError($errstr);
4748  return false;
4749  }
4750  }
4751  $this->debug('Parse WSDL');
4752  // end new code added
4753  // Create an XML parser.
4754  $this->parser = xml_parser_create();
4755  // Set the options for parsing the XML data.
4756  // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4757  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
4758  // Set the object for the parser.
4759  xml_set_object($this->parser, $this);
4760  // Set the element handlers for the parser.
4761  xml_set_element_handler($this->parser, 'start_element', 'end_element');
4762  xml_set_character_data_handler($this->parser, 'character_data');
4763  // Parse the XML file.
4764  if (!xml_parse($this->parser, $wsdl_string, true)) {
4765  // Display an error message.
4766  $errstr = sprintf(
4767  'XML error parsing WSDL from %s on line %d: %s',
4768  $wsdl,
4769  xml_get_current_line_number($this->parser),
4770  xml_error_string(xml_get_error_code($this->parser))
4771  );
4772  $this->debug($errstr);
4773  $this->debug("XML payload:\n" . $wsdl_string);
4774  $this->setError($errstr);
4775  return false;
4776  }
4777  // free the parser
4778  xml_parser_free($this->parser);
4779  $this->debug('Parsing WSDL done');
4780  // catch wsdl parse errors
4781  if($this->getError()){
4782  return false;
4783  }
4784  return true;
4785  }
4786 
4795  function start_element($parser, $name, $attrs)
4796  {
4797  if ($this->status == 'schema') {
4798  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4799  $this->appendDebug($this->currentSchema->getDebug());
4800  $this->currentSchema->clearDebug();
4801  } elseif (preg_match('/schema$/', $name)) {
4802  $this->debug('Parsing WSDL schema');
4803  // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
4804  $this->status = 'schema';
4805  $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
4806  $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4807  $this->appendDebug($this->currentSchema->getDebug());
4808  $this->currentSchema->clearDebug();
4809  } else {
4810  // position in the total number of elements, starting from 0
4811  $pos = $this->position++;
4812  $depth = $this->depth++;
4813  // set self as current value for this depth
4814  $this->depth_array[$depth] = $pos;
4815  $this->message[$pos] = array('cdata' => '');
4816  // process attributes
4817  if (count($attrs) > 0) {
4818  // register namespace declarations
4819  foreach($attrs as $k => $v) {
4820  if (preg_match('/^xmlns/',$k)) {
4821  if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4822  $this->namespaces[$ns_prefix] = $v;
4823  } else {
4824  $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4825  }
4826  if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4827  $this->XMLSchemaVersion = $v;
4828  $this->namespaces['xsi'] = $v . '-instance';
4829  }
4830  }
4831  }
4832  // expand each attribute prefix to its namespace
4833  foreach($attrs as $k => $v) {
4834  $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4835  if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4836  $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4837  }
4838  $eAttrs[$k] = $v;
4839  }
4840  $attrs = $eAttrs;
4841  } else {
4842  $attrs = array();
4843  }
4844  // get element prefix, namespace and name
4845  if (preg_match('/:/', $name)) {
4846  // get ns prefix
4847  $prefix = substr($name, 0, strpos($name, ':'));
4848  // get ns
4849  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
4850  // get unqualified name
4851  $name = substr(strstr($name, ':'), 1);
4852  }
4853  // process attributes, expanding any prefixes to namespaces
4854  // find status, register data
4855  switch ($this->status) {
4856  case 'message':
4857  if ($name == 'part') {
4858  if (isset($attrs['type'])) {
4859  $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
4860  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4861  }
4862  if (isset($attrs['element'])) {
4863  $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
4864  $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
4865  }
4866  }
4867  break;
4868  case 'portType':
4869  switch ($name) {
4870  case 'operation':
4871  $this->currentPortOperation = $attrs['name'];
4872  $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4873  if (isset($attrs['parameterOrder'])) {
4874  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4875  }
4876  break;
4877  case 'documentation':
4878  $this->documentation = true;
4879  break;
4880  // merge input/output data
4881  default:
4882  $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4883  $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4884  break;
4885  }
4886  break;
4887  case 'binding':
4888  switch ($name) {
4889  case 'binding':
4890  // get ns prefix
4891  if (isset($attrs['style'])) {
4892  $this->bindings[$this->currentBinding]['prefix'] = $prefix;
4893  }
4894  $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
4895  break;
4896  case 'header':
4897  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
4898  break;
4899  case 'operation':
4900  if (isset($attrs['soapAction'])) {
4901  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
4902  }
4903  if (isset($attrs['style'])) {
4904  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
4905  }
4906  if (isset($attrs['name'])) {
4907  $this->currentOperation = $attrs['name'];
4908  $this->debug("current binding operation: $this->currentOperation");
4909  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
4910  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
4911  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
4912  }
4913  break;
4914  case 'input':
4915  $this->opStatus = 'input';
4916  break;
4917  case 'output':
4918  $this->opStatus = 'output';
4919  break;
4920  case 'body':
4921  if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
4922  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
4923  } else {
4924  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
4925  }
4926  break;
4927  }
4928  break;
4929  case 'service':
4930  switch ($name) {
4931  case 'port':
4932  $this->currentPort = $attrs['name'];
4933  $this->debug('current port: ' . $this->currentPort);
4934  $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
4935 
4936  break;
4937  case 'address':
4938  $this->ports[$this->currentPort]['location'] = $attrs['location'];
4939  $this->ports[$this->currentPort]['bindingType'] = $namespace;
4940  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
4941  $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
4942  break;
4943  }
4944  break;
4945  }
4946  // set status
4947  switch ($name) {
4948  case 'import':
4949  if (isset($attrs['location'])) {
4950  $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
4951  $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
4952  } else {
4953  $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
4954  if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
4955  $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
4956  }
4957  $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
4958  }
4959  break;
4960  //wait for schema
4961  //case 'types':
4962  // $this->status = 'schema';
4963  // break;
4964  case 'message':
4965  $this->status = 'message';
4966  $this->messages[$attrs['name']] = array();
4967  $this->currentMessage = $attrs['name'];
4968  break;
4969  case 'portType':
4970  $this->status = 'portType';
4971  $this->portTypes[$attrs['name']] = array();
4972  $this->currentPortType = $attrs['name'];
4973  break;
4974  case "binding":
4975  if (isset($attrs['name'])) {
4976  // get binding name
4977  if (strpos($attrs['name'], ':')) {
4978  $this->currentBinding = $this->getLocalPart($attrs['name']);
4979  } else {
4980  $this->currentBinding = $attrs['name'];
4981  }
4982  $this->status = 'binding';
4983  $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
4984  $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
4985  }
4986  break;
4987  case 'service':
4988  $this->serviceName = $attrs['name'];
4989  $this->status = 'service';
4990  $this->debug('current service: ' . $this->serviceName);
4991  break;
4992  case 'definitions':
4993  foreach ($attrs as $name => $value) {
4994  $this->wsdl_info[$name] = $value;
4995  }
4996  break;
4997  }
4998  }
4999  }
5000 
5008  function end_element($parser, $name){
5009  // unset schema status
5010  if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
5011  $this->status = "";
5012  $this->appendDebug($this->currentSchema->getDebug());
5013  $this->currentSchema->clearDebug();
5014  $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5015  $this->debug('Parsing WSDL schema done');
5016  }
5017  if ($this->status == 'schema') {
5018  $this->currentSchema->schemaEndElement($parser, $name);
5019  } else {
5020  // bring depth down a notch
5021  $this->depth--;
5022  }
5023  // end documentation
5024  if ($this->documentation) {
5025  //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5026  //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
5027  $this->documentation = false;
5028  }
5029  }
5030 
5039  {
5040  $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5041  if (isset($this->message[$pos]['cdata'])) {
5042  $this->message[$pos]['cdata'] .= $data;
5043  }
5044  if ($this->documentation) {
5045  $this->documentation .= $data;
5046  }
5047  }
5048 
5058  function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
5059  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5060  $this->appendDebug($this->varDump($certRequest));
5061  $this->username = $username;
5062  $this->password = $password;
5063  $this->authtype = $authtype;
5064  $this->certRequest = $certRequest;
5065  }
5066 
5067  function getBindingData($binding)
5068  {
5069  if (is_array($this->bindings[$binding])) {
5070  return $this->bindings[$binding];
5071  }
5072  }
5073 
5081  function getOperations($bindingType = 'soap') {
5082  $ops = array();
5083  if ($bindingType == 'soap') {
5084  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5085  } elseif ($bindingType == 'soap12') {
5086  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5087  }
5088  // loop thru ports
5089  foreach($this->ports as $port => $portData) {
5090  // binding type of port matches parameter
5091  if ($portData['bindingType'] == $bindingType) {
5092  //$this->debug("getOperations for port $port");
5093  //$this->debug("port data: " . $this->varDump($portData));
5094  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
5095  // merge bindings
5096  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5097  $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
5098  }
5099  }
5100  }
5101  return $ops;
5102  }
5103 
5112  function getOperationData($operation, $bindingType = 'soap')
5113  {
5114  if ($bindingType == 'soap') {
5115  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5116  } elseif ($bindingType == 'soap12') {
5117  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5118  }
5119  // loop thru ports
5120  foreach($this->ports as $port => $portData) {
5121  // binding type of port matches parameter
5122  if ($portData['bindingType'] == $bindingType) {
5123  // get binding
5124  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5125  foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5126  // note that we could/should also check the namespace here
5127  if ($operation == $bOperation) {
5128  $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5129  return $opData;
5130  }
5131  }
5132  }
5133  }
5134  }
5135 
5144  function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
5145  if ($bindingType == 'soap') {
5146  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5147  } elseif ($bindingType == 'soap12') {
5148  $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5149  }
5150  // loop thru ports
5151  foreach($this->ports as $port => $portData) {
5152  // binding type of port matches parameter
5153  if ($portData['bindingType'] == $bindingType) {
5154  // loop through operations for the binding
5155  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5156  if ($opData['soapAction'] == $soapAction) {
5157  return $opData;
5158  }
5159  }
5160  }
5161  }
5162  }
5163 
5182  function getTypeDef($type, $ns) {
5183  $this->debug("in getTypeDef: type=$type, ns=$ns");
5184  if ((! $ns) && isset($this->namespaces['tns'])) {
5185  $ns = $this->namespaces['tns'];
5186  $this->debug("in getTypeDef: type namespace forced to $ns");
5187  }
5188  if (!isset($this->schemas[$ns])) {
5189  foreach ($this->schemas as $ns0 => $schema0) {
5190  if (strcasecmp($ns, $ns0) == 0) {
5191  $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5192  $ns = $ns0;
5193  break;
5194  }
5195  }
5196  }
5197  if (isset($this->schemas[$ns])) {
5198  $this->debug("in getTypeDef: have schema for namespace $ns");
5199  for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5200  $xs = &$this->schemas[$ns][$i];
5201  $t = $xs->getTypeDef($type);
5202  //$this->appendDebug($xs->getDebug());
5203  //$xs->clearDebug();
5204  if ($t) {
5205  if (!isset($t['phpType'])) {
5206  // get info for type to tack onto the element
5207  $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5208  $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5209  $etype = $this->getTypeDef($uqType, $ns);
5210  if ($etype) {
5211  $this->debug("found type for [element] $type:");
5212  $this->debug($this->varDump($etype));
5213  if (isset($etype['phpType'])) {
5214  $t['phpType'] = $etype['phpType'];
5215  }
5216  if (isset($etype['elements'])) {
5217  $t['elements'] = $etype['elements'];
5218  }
5219  if (isset($etype['attrs'])) {
5220  $t['attrs'] = $etype['attrs'];
5221  }
5222  }
5223  }
5224  return $t;
5225  }
5226  }
5227  } else {
5228  $this->debug("in getTypeDef: do not have schema for namespace $ns");
5229  }
5230  return false;
5231  }
5232 
5238  function webDescription(){
5239  global $HTTP_SERVER_VARS;
5240 
5241  if (isset($_SERVER)) {
5242  $PHP_SELF = $_SERVER['PHP_SELF'];
5243  } elseif (isset($HTTP_SERVER_VARS)) {
5244  $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5245  } else {
5246  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5247  }
5248 
5249  $b = '
5250  <html><head><title>NuSOAP: '.$this->serviceName.'</title>
5251  <style type="text/css">
5252  body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5253  p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5254  pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5255  ul { margin-top: 10px; margin-left: 20px; }
5256  li { list-style-type: none; margin-top: 10px; color: #000000; }
5257  .content{
5258  margin-left: 0px; padding-bottom: 2em; }
5259  .nav {
5260  padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5261  margin-top: 10px; margin-left: 0px; color: #000000;
5262  background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5263  .title {
5264  font-family: arial; font-size: 26px; color: #ffffff;
5265  background-color: #999999; width: 105%; margin-left: 0px;
5266  padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
5267  .hidden {
5268  position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5269  font-family: arial; overflow: hidden; width: 600;
5270  padding: 20px; font-size: 10px; background-color: #999999;
5271  layer-background-color:#FFFFFF; }
5272  a,a:active { color: charcoal; font-weight: bold; }
5273  a:visited { color: #666666; font-weight: bold; }
5274  a:hover { color: cc3300; font-weight: bold; }
5275  </style>
5276  <script language="JavaScript" type="text/javascript">
5277  <!--
5278  // POP-UP CAPTIONS...
5279  function lib_bwcheck(){ //Browsercheck (needed)
5280  this.ver=navigator.appVersion
5281  this.agent=navigator.userAgent
5282  this.dom=document.getElementById?1:0
5283  this.opera5=this.agent.indexOf("Opera 5")>-1
5284  this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5285  this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5286  this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5287  this.ie=this.ie4||this.ie5||this.ie6
5288  this.mac=this.agent.indexOf("Mac")>-1
5289  this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5290  this.ns4=(document.layers && !this.dom)?1:0;
5291  this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5292  return this
5293  }
5294  var bw = new lib_bwcheck()
5295  //Makes crossbrowser object.
5296  function makeObj(obj){
5297  this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5298  if(!this.evnt) return false
5299  this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5300  this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5301  this.writeIt=b_writeIt;
5302  return this
5303  }
5304  // A unit of measure that will be added when setting the position of a layer.
5305  //var px = bw.ns4||window.opera?"":"px";
5306  function b_writeIt(text){
5307  if (bw.ns4){this.wref.write(text);this.wref.close()}
5308  else this.wref.innerHTML = text
5309  }
5310  //Shows the messages
5311  var oDesc;
5312  function popup(divid){
5313  if(oDesc = new makeObj(divid)){
5314  oDesc.css.visibility = "visible"
5315  }
5316  }
5317  function popout(){ // Hides message
5318  if(oDesc) oDesc.css.visibility = "hidden"
5319  }
5320  //-->
5321  </script>
5322  </head>
5323  <body>
5324  <div class=content>
5325  <br><br>
5326  <div class=title>'.$this->serviceName.'</div>
5327  <div class=nav>
5328  <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
5329  Click on an operation name to view it&apos;s details.</p>
5330  <ul>';
5331  foreach($this->getOperations() as $op => $data){
5332  $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5333  // create hidden div
5334  $b .= "<div id='$op' class='hidden'>
5335  <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5336  foreach($data as $donnie => $marie){ // loop through opdata
5337  if($donnie == 'input' || $donnie == 'output'){ // show input/output data
5338  $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
5339  foreach($marie as $captain => $tenille){ // loop through data
5340  if($captain == 'parts'){ // loop thru parts
5341  $b .= "&nbsp;&nbsp;$captain:<br>";
5342  //if(is_array($tenille)){
5343  foreach($tenille as $joanie => $chachi){
5344  $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5345  }
5346  //}
5347  } else {
5348  $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5349  }
5350  }
5351  } else {
5352  $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
5353  }
5354  }
5355  $b .= '</div>';
5356  }
5357  $b .= '
5358  <ul>
5359  </div>
5360  </div></body></html>';
5361  return $b;
5362  }
5363 
5371  function serialize($debug = 0)
5372  {
5373  $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5374  $xml .= "\n<definitions";
5375  foreach($this->namespaces as $k => $v) {
5376  $xml .= " xmlns:$k=\"$v\"";
5377  }
5378  // 10.9.02 - add poulter fix for wsdl and tns declarations
5379  if (isset($this->namespaces['wsdl'])) {
5380  $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5381  }
5382  if (isset($this->namespaces['tns'])) {
5383  $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5384  }
5385  $xml .= '>';
5386  // imports
5387  if (sizeof($this->import) > 0) {
5388  foreach($this->import as $ns => $list) {
5389  foreach ($list as $ii) {
5390  if ($ii['location'] != '') {
5391  $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5392  } else {
5393  $xml .= '<import namespace="' . $ns . '" />';
5394  }
5395  }
5396  }
5397  }
5398  // types
5399  if (count($this->schemas)>=1) {
5400  $xml .= "\n<types>\n";
5401  foreach ($this->schemas as $ns => $list) {
5402  foreach ($list as $xs) {
5403  $xml .= $xs->serializeSchema();
5404  }
5405  }
5406  $xml .= '</types>';
5407  }
5408  // messages
5409  if (count($this->messages) >= 1) {
5410  foreach($this->messages as $msgName => $msgParts) {
5411  $xml .= "\n<message name=\"" . $msgName . '">';
5412  if(is_array($msgParts)){
5413  foreach($msgParts as $partName => $partType) {
5414  // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
5415  if (strpos($partType, ':')) {
5416  $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5417  } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5418  // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
5419  $typePrefix = 'xsd';
5420  } else {
5421  foreach($this->typemap as $ns => $types) {
5422  if (isset($types[$partType])) {
5423  $typePrefix = $this->getPrefixFromNamespace($ns);
5424  }
5425  }
5426  if (!isset($typePrefix)) {
5427  die("$partType has no namespace!");
5428  }
5429  }
5430  $ns = $this->getNamespaceFromPrefix($typePrefix);
5431  $localPart = $this->getLocalPart($partType);
5432  $typeDef = $this->getTypeDef($localPart, $ns);
5433  if ($typeDef['typeClass'] == 'element') {
5434  $elementortype = 'element';
5435  if (substr($localPart, -1) == '^') {
5436  $localPart = substr($localPart, 0, -1);
5437  }
5438  } else {
5439  $elementortype = 'type';
5440  }
5441  $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5442  }
5443  }
5444  $xml .= '</message>';
5445  }
5446  }
5447  // bindings & porttypes
5448  if (count($this->bindings) >= 1) {
5449  $binding_xml = '';
5450  $portType_xml = '';
5451  foreach($this->bindings as $bindingName => $attrs) {
5452  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5453  $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5454  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5455  foreach($attrs['operations'] as $opName => $opParts) {
5456  $binding_xml .= "\n" . ' <operation name="' . $opName . '">';
5457  $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
5458  if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5459  $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5460  } else {
5461  $enc_style = '';
5462  }
5463  $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5464  if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5465  $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5466  } else {
5467  $enc_style = '';
5468  }
5469  $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5470  $binding_xml .= "\n" . ' </operation>';
5471  $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"';
5472  if (isset($opParts['parameterOrder'])) {
5473  $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5474  }
5475  $portType_xml .= '>';
5476  if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
5477  $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5478  }
5479  $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>';
5480  $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>';
5481  $portType_xml .= "\n" . ' </operation>';
5482  }
5483  $portType_xml .= "\n" . '</portType>';
5484  $binding_xml .= "\n" . '</binding>';
5485  }
5486  $xml .= $portType_xml . $binding_xml;
5487  }
5488  // services
5489  $xml .= "\n<service name=\"" . $this->serviceName . '">';
5490  if (count($this->ports) >= 1) {
5491  foreach($this->ports as $pName => $attrs) {
5492  $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5493  $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5494  $xml .= "\n" . ' </port>';
5495  }
5496  }
5497  $xml .= "\n" . '</service>';
5498  return $xml . "\n</definitions>";
5499  }
5500 
5510  function parametersMatchWrapped($type, &$parameters) {
5511  $this->debug("in parametersMatchWrapped type=$type, parameters=");
5512  $this->appendDebug($this->varDump($parameters));
5513 
5514  // split type into namespace:unqualified-type
5515  if (strpos($type, ':')) {
5516  $uqType = substr($type, strrpos($type, ':') + 1);
5517  $ns = substr($type, 0, strrpos($type, ':'));
5518  $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5519  if ($this->getNamespaceFromPrefix($ns)) {
5520  $ns = $this->getNamespaceFromPrefix($ns);
5521  $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5522  }
5523  } else {
5524  // TODO: should the type be compared to types in XSD, and the namespace
5525  // set to XSD if the type matches?
5526  $this->debug("in parametersMatchWrapped: No namespace for type $type");
5527  $ns = '';
5528  $uqType = $type;
5529  }
5530 
5531  // get the type information
5532  if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5533  $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5534  return false;
5535  }
5536  $this->debug("in parametersMatchWrapped: found typeDef=");
5537  $this->appendDebug($this->varDump($typeDef));
5538  if (substr($uqType, -1) == '^') {
5539  $uqType = substr($uqType, 0, -1);
5540  }
5541  $phpType = $typeDef['phpType'];
5542  $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5543  $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5544 
5545  // we expect a complexType or element of complexType
5546  if ($phpType != 'struct') {
5547  $this->debug("in parametersMatchWrapped: not a struct");
5548  return false;
5549  }
5550 
5551  // see whether the parameter names match the elements
5552  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5553  $elements = 0;
5554  $matches = 0;
5555  $change = false;
5556  if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
5557  $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
5558  $change = true;
5559  }
5560  foreach ($typeDef['elements'] as $name => $attrs) {
5561  if ($change) {
5562  $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
5563  $parameters[$name] = $parameters[$elements];
5564  unset($parameters[$elements]);
5565  $matches++;
5566  } elseif (isset($parameters[$name])) {
5567  $this->debug("in parametersMatchWrapped: have parameter named $name");
5568  $matches++;
5569  } else {
5570  $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5571  }
5572  $elements++;
5573  }
5574 
5575  $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5576  if ($matches == 0) {
5577  return false;
5578  }
5579  return true;
5580  }
5581 
5582  // since there are no elements for the type, if the user passed no
5583  // parameters, the parameters match wrapped.
5584  $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5585  return count($parameters) == 0;
5586  }
5587 
5603  function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
5604  $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5605  $this->appendDebug('parameters=' . $this->varDump($parameters));
5606 
5607  if ($direction != 'input' && $direction != 'output') {
5608  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5609  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5610  return false;
5611  }
5612  if (!$opData = $this->getOperationData($operation, $bindingType)) {
5613  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5614  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5615  return false;
5616  }
5617  $this->debug('in serializeRPCParameters: opData:');
5618  $this->appendDebug($this->varDump($opData));
5619 
5620  // Get encoding style for output and set to current
5621  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5622  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5623  $encodingStyle = $opData['output']['encodingStyle'];
5624  $enc_style = $encodingStyle;
5625  }
5626 
5627  // set input params
5628  $xml = '';
5629  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5630  $parts = &$opData[$direction]['parts'];
5631  $part_count = sizeof($parts);
5632  $style = $opData['style'];
5633  $use = $opData[$direction]['use'];
5634  $this->debug("have $part_count part(s) to serialize using $style/$use");
5635  if (is_array($parameters)) {
5636  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5637  $parameter_count = count($parameters);
5638  $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5639  // check for Microsoft-style wrapped parameters
5640  if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5641  $this->debug('check whether the caller has wrapped the parameters');
5642  if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
5643  $this->debug('check whether caller\'s parameters match the wrapped ones');
5644  if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5645  $this->debug('wrap the parameters for the caller');
5646  $parameters = array('parameters' => $parameters);
5647  $parameter_count = 1;
5648  }
5649  }
5650  }
5651  foreach ($parts as $name => $type) {
5652  $this->debug("serializing part $name of type $type");
5653  // Track encoding style
5654  if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5655  $encodingStyle = $opData[$direction]['encodingStyle'];
5656  $enc_style = $encodingStyle;
5657  } else {
5658  $enc_style = false;
5659  }
5660  // NOTE: add error handling here
5661  // if serializeType returns false, then catch global error and fault
5662  if ($parametersArrayType == 'arraySimple') {
5663  $p = array_shift($parameters);
5664  $this->debug('calling serializeType w/indexed param');
5665  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5666  } elseif (isset($parameters[$name])) {
5667  $this->debug('calling serializeType w/named param');
5668  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5669  } else {
5670  // TODO: only send nillable
5671  $this->debug('calling serializeType w/null param');
5672  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5673  }
5674  }
5675  } else {
5676  $this->debug('no parameters passed.');
5677  }
5678  }
5679  $this->debug("serializeRPCParameters returning: $xml");
5680  return $xml;
5681  }
5682 
5697  function serializeParameters($operation, $direction, $parameters)
5698  {
5699  $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
5700  $this->appendDebug('parameters=' . $this->varDump($parameters));
5701 
5702  if ($direction != 'input' && $direction != 'output') {
5703  $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5704  $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5705  return false;
5706  }
5707  if (!$opData = $this->getOperationData($operation)) {
5708  $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5709  $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5710  return false;
5711  }
5712  $this->debug('opData:');
5713  $this->appendDebug($this->varDump($opData));
5714 
5715  // Get encoding style for output and set to current
5716  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5717  if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5718  $encodingStyle = $opData['output']['encodingStyle'];
5719  $enc_style = $encodingStyle;
5720  }
5721 
5722  // set input params
5723  $xml = '';
5724  if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5725 
5726  $use = $opData[$direction]['use'];
5727  $this->debug("use=$use");
5728  $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5729  if (is_array($parameters)) {
5730  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5731  $this->debug('have ' . $parametersArrayType . ' parameters');
5732  foreach($opData[$direction]['parts'] as $name => $type) {
5733  $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5734  // Track encoding style
5735  if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5736  $encodingStyle = $opData[$direction]['encodingStyle'];
5737  $enc_style = $encodingStyle;
5738  } else {
5739  $enc_style = false;
5740  }
5741  // NOTE: add error handling here
5742  // if serializeType returns false, then catch global error and fault
5743  if ($parametersArrayType == 'arraySimple') {
5744  $p = array_shift($parameters);
5745  $this->debug('calling serializeType w/indexed param');
5746  $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5747  } elseif (isset($parameters[$name])) {
5748  $this->debug('calling serializeType w/named param');
5749  $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5750  } else {
5751  // TODO: only send nillable
5752  $this->debug('calling serializeType w/null param');
5753  $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5754  }
5755  }
5756  } else {
5757  $this->debug('no parameters passed.');
5758  }
5759  }
5760  $this->debug("serializeParameters returning: $xml");
5761  return $xml;
5762  }
5763 
5776  function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
5777  {
5778  $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5779  $this->appendDebug("value=" . $this->varDump($value));
5780  if($use == 'encoded' && $encodingStyle) {
5781  $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5782  }
5783 
5784  // if a soapval has been supplied, let its type override the WSDL
5785  if (is_object($value) && get_class($value) == 'soapval') {
5786  if ($value->type_ns) {
5787  $type = $value->type_ns . ':' . $value->type;
5788  $forceType = true;
5789  $this->debug("in serializeType: soapval overrides type to $type");
5790  } elseif ($value->type) {
5791  $type = $value->type;
5792  $forceType = true;
5793  $this->debug("in serializeType: soapval overrides type to $type");
5794  } else {
5795  $forceType = false;
5796  $this->debug("in serializeType: soapval does not override type");
5797  }
5798  $attrs = $value->attributes;
5799  $value = $value->value;
5800  $this->debug("in serializeType: soapval overrides value to $value");
5801  if ($attrs) {
5802  if (!is_array($value)) {
5803  $value['!'] = $value;
5804  }
5805  foreach ($attrs as $n => $v) {
5806  $value['!' . $n] = $v;
5807  }
5808  $this->debug("in serializeType: soapval provides attributes");
5809  }
5810  } else {
5811  $forceType = false;
5812  }
5813 
5814  $xml = '';
5815  if (strpos($type, ':')) {
5816  $uqType = substr($type, strrpos($type, ':') + 1);
5817  $ns = substr($type, 0, strrpos($type, ':'));
5818  $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5819  if ($this->getNamespaceFromPrefix($ns)) {
5820  $ns = $this->getNamespaceFromPrefix($ns);
5821  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5822  }
5823 
5824  if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
5825  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5826  if ($unqualified && $use == 'literal') {
5827  $elementNS = " xmlns=\"\"";
5828  } else {
5829  $elementNS = '';
5830  }
5831  if (is_null($value)) {
5832  if ($use == 'literal') {
5833  // TODO: depends on minOccurs
5834  $xml = "<$name$elementNS/>";
5835  } else {
5836  // TODO: depends on nillable, which should be checked before calling this method
5837  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5838  }
5839  $this->debug("in serializeType: returning: $xml");
5840  return $xml;
5841  }
5842  if ($uqType == 'Array') {
5843  // JBoss/Axis does this sometimes
5844  return $this->serialize_val($value, $name, false, false, false, false, $use);
5845  }
5846  if ($uqType == 'boolean') {
5847  if ((is_string($value) && $value == 'false') || (! $value)) {
5848  $value = 'false';
5849  } else {
5850  $value = 'true';
5851  }
5852  }
5853  if ($uqType == 'string' && gettype($value) == 'string') {
5854  $value = $this->expandEntities($value);
5855  }
5856  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5857  $value = sprintf("%.0lf", $value);
5858  }
5859  // it's a scalar
5860  // TODO: what about null/nil values?
5861  // check type isn't a custom type extending xmlschema namespace
5862  if (!$this->getTypeDef($uqType, $ns)) {
5863  if ($use == 'literal') {
5864  if ($forceType) {
5865  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5866  } else {
5867  $xml = "<$name$elementNS>$value</$name>";
5868  }
5869  } else {
5870  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5871  }
5872  $this->debug("in serializeType: returning: $xml");
5873  return $xml;
5874  }
5875  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
5876  } else if ($ns == 'http://xml.apache.org/xml-soap') {
5877  $this->debug('in serializeType: appears to be Apache SOAP type');
5878  if ($uqType == 'Map') {
5879  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5880  if (! $tt_prefix) {
5881  $this->debug('in serializeType: Add namespace for Apache SOAP type');
5882  $tt_prefix = 'ns' . rand(1000, 9999);
5883  $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
5884  // force this to be added to usedNamespaces
5885  $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5886  }
5887  $contents = '';
5888  foreach($value as $k => $v) {
5889  $this->debug("serializing map element: key $k, value $v");
5890  $contents .= '<item>';
5891  $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
5892  $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
5893  $contents .= '</item>';
5894  }
5895  if ($use == 'literal') {
5896  if ($forceType) {
5897  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
5898  } else {
5899  $xml = "<$name>$contents</$name>";
5900  }
5901  } else {
5902  $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
5903  }
5904  $this->debug("in serializeType: returning: $xml");
5905  return $xml;
5906  }
5907  $this->debug('in serializeType: Apache SOAP type, but only support Map');
5908  }
5909  } else {
5910  // TODO: should the type be compared to types in XSD, and the namespace
5911  // set to XSD if the type matches?
5912  $this->debug("in serializeType: No namespace for type $type");
5913  $ns = '';
5914  $uqType = $type;
5915  }
5916  if(!$typeDef = $this->getTypeDef($uqType, $ns)){
5917  $this->setError("$type ($uqType) is not a supported type.");
5918  $this->debug("in serializeType: $type ($uqType) is not a supported type.");
5919  return false;
5920  } else {
5921  $this->debug("in serializeType: found typeDef");
5922  $this->appendDebug('typeDef=' . $this->varDump($typeDef));
5923  if (substr($uqType, -1) == '^') {
5924  $uqType = substr($uqType, 0, -1);
5925  }
5926  }
5927  $phpType = $typeDef['phpType'];
5928  $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
5929  // if php type == struct, map value to the <all> element names
5930  if ($phpType == 'struct') {
5931  if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
5932  $elementName = $uqType;
5933  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5934  $elementNS = " xmlns=\"$ns\"";
5935  } else {
5936  $elementNS = " xmlns=\"\"";
5937  }
5938  } else {
5939  $elementName = $name;
5940  if ($unqualified) {
5941  $elementNS = " xmlns=\"\"";
5942  } else {
5943  $elementNS = '';
5944  }
5945  }
5946  if (is_null($value)) {
5947  if ($use == 'literal') {
5948  // TODO: depends on minOccurs
5949  $xml = "<$elementName$elementNS/>";
5950  } else {
5951  $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5952  }
5953  $this->debug("in serializeType: returning: $xml");
5954  return $xml;
5955  }
5956  if (is_object($value)) {
5957  $value = get_object_vars($value);
5958  }
5959  if (is_array($value)) {
5960  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
5961  if ($use == 'literal') {
5962  if ($forceType) {
5963  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
5964  } else {
5965  $xml = "<$elementName$elementNS$elementAttrs>";
5966  }
5967  } else {
5968  $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
5969  }
5970 
5971  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
5972  $xml .= "</$elementName>";
5973  } else {
5974  $this->debug("in serializeType: phpType is struct, but value is not an array");
5975  $this->setError("phpType is struct, but value is not an array: see debug output for details");
5976  $xml = '';
5977  }
5978  } elseif ($phpType == 'array') {
5979  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5980  $elementNS = " xmlns=\"$ns\"";
5981  } else {
5982  if ($unqualified) {
5983  $elementNS = " xmlns=\"\"";
5984  } else {
5985  $elementNS = '';
5986  }
5987  }
5988  if (is_null($value)) {
5989  if ($use == 'literal') {
5990  // TODO: depends on minOccurs
5991  $xml = "<$name$elementNS/>";
5992  } else {
5993  $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
5994  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5995  ":Array\" " .
5996  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5997  ':arrayType="' .
5998  $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
5999  ':' .
6000  $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
6001  }
6002  $this->debug("in serializeType: returning: $xml");
6003  return $xml;
6004  }
6005  if (isset($typeDef['multidimensional'])) {
6006  $nv = array();
6007  foreach($value as $v) {
6008  $cols = ',' . sizeof($v);
6009  $nv = array_merge($nv, $v);
6010  }
6011  $value = $nv;
6012  } else {
6013  $cols = '';
6014  }
6015  if (is_array($value) && sizeof($value) >= 1) {
6016  $rows = sizeof($value);
6017  $contents = '';
6018  foreach($value as $k => $v) {
6019  $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6020  //if (strpos($typeDef['arrayType'], ':') ) {
6021  if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6022  $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6023  } else {
6024  $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6025  }
6026  }
6027  } else {
6028  $rows = 0;
6029  $contents = null;
6030  }
6031  // TODO: for now, an empty value will be serialized as a zero element
6032  // array. Revisit this when coding the handling of null/nil values.
6033  if ($use == 'literal') {
6034  $xml = "<$name$elementNS>"
6035  .$contents
6036  ."</$name>";
6037  } else {
6038  $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
6039  $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6040  .':arrayType="'
6041  .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6042  .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
6043  .$contents
6044  ."</$name>";
6045  }
6046  } elseif ($phpType == 'scalar') {
6047  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6048  $elementNS = " xmlns=\"$ns\"";
6049  } else {
6050  if ($unqualified) {
6051  $elementNS = " xmlns=\"\"";
6052  } else {
6053  $elementNS = '';
6054  }
6055  }
6056  if ($use == 'literal') {
6057  if ($forceType) {
6058  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6059  } else {
6060  $xml = "<$name$elementNS>$value</$name>";
6061  }
6062  } else {
6063  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6064  }
6065  }
6066  $this->debug("in serializeType: returning: $xml");
6067  return $xml;
6068  }
6069 
6080  function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
6081  $xml = '';
6082  if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6083  $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6084  if (is_array($value)) {
6085  $xvalue = $value;
6086  } elseif (is_object($value)) {
6087  $xvalue = get_object_vars($value);
6088  } else {
6089  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6090  $xvalue = array();
6091  }
6092  foreach ($typeDef['attrs'] as $aName => $attrs) {
6093  if (isset($xvalue['!' . $aName])) {
6094  $xname = '!' . $aName;
6095  $this->debug("value provided for attribute $aName with key $xname");
6096  } elseif (isset($xvalue[$aName])) {
6097  $xname = $aName;
6098  $this->debug("value provided for attribute $aName with key $xname");
6099  } elseif (isset($attrs['default'])) {
6100  $xname = '!' . $aName;
6101  $xvalue[$xname] = $attrs['default'];
6102  $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6103  } else {
6104  $xname = '';
6105  $this->debug("no value provided for attribute $aName");
6106  }
6107  if ($xname) {
6108  $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6109  }
6110  }
6111  } else {
6112  $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6113  }
6114  if (isset($typeDef['extensionBase'])) {
6115  $ns = $this->getPrefix($typeDef['extensionBase']);
6116  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6117  if ($this->getNamespaceFromPrefix($ns)) {
6118  $ns = $this->getNamespaceFromPrefix($ns);
6119  }
6120  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6121  $this->debug("serialize attributes for extension base $ns:$uqType");
6122  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6123  } else {
6124  $this->debug("extension base $ns:$uqType is not a supported type");
6125  }
6126  }
6127  return $xml;
6128  }
6129 
6142  function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
6143  $xml = '';
6144  if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6145  $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6146  if (is_array($value)) {
6147  $xvalue = $value;
6148  } elseif (is_object($value)) {
6149  $xvalue = get_object_vars($value);
6150  } else {
6151  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6152  $xvalue = array();
6153  }
6154  // toggle whether all elements are present - ideally should validate against schema
6155  if (count($typeDef['elements']) != count($xvalue)){
6156  $optionals = true;
6157  }
6158  foreach ($typeDef['elements'] as $eName => $attrs) {
6159  if (!isset($xvalue[$eName])) {
6160  if (isset($attrs['default'])) {
6161  $xvalue[$eName] = $attrs['default'];
6162  $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6163  }
6164  }
6165  // if user took advantage of a minOccurs=0, then only serialize named parameters
6166  if (isset($optionals)
6167  && (!isset($xvalue[$eName]))
6168  && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6169  ){
6170  if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6171  $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6172  }
6173  // do nothing
6174  $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6175  } else {
6176  // get value
6177  if (isset($xvalue[$eName])) {
6178  $v = $xvalue[$eName];
6179  } else {
6180  $v = null;
6181  }
6182  if (isset($attrs['form'])) {
6183  $unqualified = ($attrs['form'] == 'unqualified');
6184  } else {
6185  $unqualified = false;
6186  }
6187  if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6188  $vv = $v;
6189  foreach ($vv as $k => $v) {
6190  if (isset($attrs['type']) || isset($attrs['ref'])) {
6191  // serialize schema-defined type
6192  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6193  } else {
6194  // serialize generic type (can this ever really happen?)
6195  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6196  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6197  }
6198  }
6199  } else {
6200  if (isset($attrs['type']) || isset($attrs['ref'])) {
6201  // serialize schema-defined type
6202  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6203  } else {
6204  // serialize generic type (can this ever really happen?)
6205  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6206  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6207  }
6208  }
6209  }
6210  }
6211  } else {
6212  $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6213  }
6214  if (isset($typeDef['extensionBase'])) {
6215  $ns = $this->getPrefix($typeDef['extensionBase']);
6216  $uqType = $this->getLocalPart($typeDef['extensionBase']);
6217  if ($this->getNamespaceFromPrefix($ns)) {
6218  $ns = $this->getNamespaceFromPrefix($ns);
6219  }
6220  if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6221  $this->debug("serialize elements for extension base $ns:$uqType");
6222  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6223  } else {
6224  $this->debug("extension base $ns:$uqType is not a supported type");
6225  }
6226  }
6227  return $xml;
6228  }
6229 
6244  function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
6245  if (count($elements) > 0) {
6246  $eElements = array();
6247  foreach($elements as $n => $e){
6248  // expand each element
6249  $ee = array();
6250  foreach ($e as $k => $v) {
6251  $k = strpos($k,':') ? $this->expandQname($k) : $k;
6252  $v = strpos($v,':') ? $this->expandQname($v) : $v;
6253  $ee[$k] = $v;
6254  }
6255  $eElements[$n] = $ee;
6256  }
6257  $elements = $eElements;
6258  }
6259 
6260  if (count($attrs) > 0) {
6261  foreach($attrs as $n => $a){
6262  // expand each attribute
6263  foreach ($a as $k => $v) {
6264  $k = strpos($k,':') ? $this->expandQname($k) : $k;
6265  $v = strpos($v,':') ? $this->expandQname($v) : $v;
6266  $aa[$k] = $v;
6267  }
6268  $eAttrs[$n] = $aa;
6269  }
6270  $attrs = $eAttrs;
6271  }
6272 
6273  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6274  $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
6275 
6276  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6277  $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
6278  }
6279 
6291  function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
6292  $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6293 
6294  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6295  $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6296  }
6297 
6305  function addElement($attrs) {
6306  $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6307  $this->schemas[$typens][0]->addElement($attrs);
6308  }
6309 
6324  function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
6325  if ($use == 'encoded' && $encodingStyle == '') {
6326  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6327  }
6328 
6329  if ($style == 'document') {
6330  $elements = array();
6331  foreach ($in as $n => $t) {
6332  $elements[$n] = array('name' => $n, 'type' => $t);
6333  }
6334  $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6335  $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6336  $in = array('parameters' => 'tns:' . $name . '^');
6337 
6338  $elements = array();
6339  foreach ($out as $n => $t) {
6340  $elements[$n] = array('name' => $n, 'type' => $t);
6341  }
6342  $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6343  $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6344  $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6345  }
6346 
6347  // get binding
6348  $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6349  array(
6350  'name' => $name,
6351  'binding' => $this->serviceName . 'Binding',
6352  'endpoint' => $this->endpoint,
6353  'soapAction' => $soapaction,
6354  'style' => $style,
6355  'input' => array(
6356  'use' => $use,
6357  'namespace' => $namespace,
6358  'encodingStyle' => $encodingStyle,
6359  'message' => $name . 'Request',
6360  'parts' => $in),
6361  'output' => array(
6362  'use' => $use,
6363  'namespace' => $namespace,
6364  'encodingStyle' => $encodingStyle,
6365  'message' => $name . 'Response',
6366  'parts' => $out),
6367  'namespace' => $namespace,
6368  'transport' => 'http://schemas.xmlsoap.org/soap/http',
6369  'documentation' => $documentation);
6370  // add portTypes
6371  // add messages
6372  if($in)
6373  {
6374  foreach($in as $pName => $pType)
6375  {
6376  if(strpos($pType,':')) {
6377  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6378  }
6379  $this->messages[$name.'Request'][$pName] = $pType;
6380  }
6381  } else {
6382  $this->messages[$name.'Request']= '0';
6383  }
6384  if($out)
6385  {
6386  foreach($out as $pName => $pType)
6387  {
6388  if(strpos($pType,':')) {
6389  $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6390  }
6391  $this->messages[$name.'Response'][$pName] = $pType;
6392  }
6393  } else {
6394  $this->messages[$name.'Response']= '0';
6395  }
6396  return true;
6397  }
6398 }
6399 ?><?php
6400 
6401 
6402 
6413 
6414  var $xml = '';
6415  var $xml_encoding = '';
6416  var $method = '';
6417  var $root_struct = '';
6420  var $root_header = '';
6421  var $document = ''; // incoming SOAP body (text)
6422  // determines where in the message we are (envelope,header,body,method)
6423  var $status = '';
6424  var $position = 0;
6425  var $depth = 0;
6427  var $namespaces = array();
6428  var $message = array();
6429  var $parent = '';
6430  var $fault = false;
6431  var $fault_code = '';
6432  var $fault_str = '';
6433  var $fault_detail = '';
6434  var $depth_array = array();
6435  var $debug_flag = true;
6436  var $soapresponse = NULL; // parsed SOAP Body
6437  var $soapheader = NULL; // parsed SOAP Header
6438  var $responseHeaders = ''; // incoming SOAP headers (text)
6440  // for multiref parsing:
6441  // array of id => pos
6442  var $ids = array();
6443  // array of id => hrefs => pos
6444  var $multirefs = array();
6445  // toggle for auto-decoding element content
6446  var $decode_utf8 = true;
6447 
6457  function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
6459  $this->xml = $xml;
6460  $this->xml_encoding = $encoding;
6461  $this->method = $method;
6462  $this->decode_utf8 = $decode_utf8;
6463 
6464  // Check whether content has been read.
6465  if(!empty($xml)){
6466  // Check XML encoding
6467  $pos_xml = strpos($xml, '<?xml');
6468  if ($pos_xml !== FALSE) {
6469  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6470  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6471  $xml_encoding = $res[1];
6472  if (strtoupper($xml_encoding) != $encoding) {
6473  $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6474  $this->debug($err);
6475  if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6476  $this->setError($err);
6477  return;
6478  }
6479  // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
6480  } else {
6481  $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6482  }
6483  } else {
6484  $this->debug('No encoding specified in XML declaration');
6485  }
6486  } else {
6487  $this->debug('No XML declaration');
6488  }
6489  $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
6490  // Create an XML parser - why not xml_parser_create_ns?
6491  $this->parser = xml_parser_create($this->xml_encoding);
6492  // Set the options for parsing the XML data.
6493  //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6494  xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6495  xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6496  // Set the object for the parser.
6497  xml_set_object($this->parser, $this);
6498  // Set the element handlers for the parser.
6499  xml_set_element_handler($this->parser, 'start_element','end_element');
6500  xml_set_character_data_handler($this->parser,'character_data');
6501 
6502  // Parse the XML file.
6503  if(!xml_parse($this->parser,$xml,true)){
6504  // Display an error message.
6505  $err = sprintf('XML error parsing SOAP payload on line %d: %s',
6506  xml_get_current_line_number($this->parser),
6507  xml_error_string(xml_get_error_code($this->parser)));
6508  $this->debug($err);
6509  $this->debug("XML payload:\n" . $xml);
6510  $this->setError($err);
6511  } else {
6512  $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
6513  // get final value
6514  $this->soapresponse = $this->message[$this->root_struct]['result'];
6515  // get header value
6516  if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
6517  $this->soapheader = $this->message[$this->root_header]['result'];
6518  }
6519  // resolve hrefs/ids
6520  if(sizeof($this->multirefs) > 0){
6521  foreach($this->multirefs as $id => $hrefs){
6522  $this->debug('resolving multirefs for id: '.$id);
6523  $idVal = $this->buildVal($this->ids[$id]);
6524  if (is_array($idVal) && isset($idVal['!id'])) {
6525  unset($idVal['!id']);
6526  }
6527  foreach($hrefs as $refPos => $ref){
6528  $this->debug('resolving href at pos '.$refPos);
6529  $this->multirefs[$id][$refPos] = $idVal;
6530  }
6531  }
6532  }
6533  }
6534  xml_parser_free($this->parser);
6535  } else {
6536  $this->debug('xml was empty, didn\'t parse!');
6537  $this->setError('xml was empty, didn\'t parse!');
6538  }
6539  }
6540 
6549  function start_element($parser, $name, $attrs) {
6550  // position in a total number of elements, starting from 0
6551  // update class level pos
6552  $pos = $this->position++;
6553  // and set mine
6554  $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
6555  // depth = how many levels removed from root?
6556  // set mine as current global depth and increment global depth value
6557  $this->message[$pos]['depth'] = $this->depth++;
6558 
6559  // else add self as child to whoever the current parent is
6560  if($pos != 0){
6561  $this->message[$this->parent]['children'] .= '|'.$pos;
6562  }
6563  // set my parent
6564  $this->message[$pos]['parent'] = $this->parent;
6565  // set self as current parent
6566  $this->parent = $pos;
6567  // set self as current value for this depth
6568  $this->depth_array[$this->depth] = $pos;
6569  // get element prefix
6570  if(strpos($name,':')){
6571  // get ns prefix
6572  $prefix = substr($name,0,strpos($name,':'));
6573  // get unqualified name
6574  $name = substr(strstr($name,':'),1);
6575  }
6576  // set status
6577  if($name == 'Envelope'){
6578  $this->status = 'envelope';
6579  } elseif($name == 'Header' && $this->status = 'envelope'){
6580  $this->root_header = $pos;
6581  $this->status = 'header';
6582  } elseif($name == 'Body' && $this->status = 'envelope'){
6583  $this->status = 'body';
6584  $this->body_position = $pos;
6585  // set method
6586  } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
6587  $this->status = 'method';
6588  $this->root_struct_name = $name;
6589  $this->root_struct = $pos;
6590  $this->message[$pos]['type'] = 'struct';
6591  $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6592  }
6593  // set my status
6594  $this->message[$pos]['status'] = $this->status;
6595  // set name
6596  $this->message[$pos]['name'] = htmlspecialchars($name);
6597  // set attrs
6598  $this->message[$pos]['attrs'] = $attrs;
6599 
6600  // loop through atts, logging ns and type declarations
6601  $attstr = '';
6602  foreach($attrs as $key => $value){
6603  $key_prefix = $this->getPrefix($key);
6604  $key_localpart = $this->getLocalPart($key);
6605  // if ns declarations, add to class level array of valid namespaces
6606  if($key_prefix == 'xmlns'){
6607  if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){
6608  $this->XMLSchemaVersion = $value;
6609  $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6610  $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
6611  }
6612  $this->namespaces[$key_localpart] = $value;
6613  // set method namespace
6614  if($name == $this->root_struct_name){
6615  $this->methodNamespace = $value;
6616  }
6617  // if it's a type declaration, set type
6618  } elseif($key_localpart == 'type'){
6619  if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6620  // do nothing: already processed arrayType
6621  } else {
6622  $value_prefix = $this->getPrefix($value);
6623  $value_localpart = $this->getLocalPart($value);
6624  $this->message[$pos]['type'] = $value_localpart;
6625  $this->message[$pos]['typePrefix'] = $value_prefix;
6626  if(isset($this->namespaces[$value_prefix])){
6627  $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6628  } else if(isset($attrs['xmlns:'.$value_prefix])) {
6629  $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
6630  }
6631  // should do something here with the namespace of specified type?
6632  }
6633  } elseif($key_localpart == 'arrayType'){
6634  $this->message[$pos]['type'] = 'array';
6635  /* do arrayType ereg here
6636  [1] arrayTypeValue ::= atype asize
6637  [2] atype ::= QName rank*
6638  [3] rank ::= '[' (',')* ']'
6639  [4] asize ::= '[' length~ ']'
6640  [5] length ::= nextDimension* Digit+
6641  [6] nextDimension ::= Digit+ ','
6642  */
6643  $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
6644  if(preg_match($expr,$value,$regs)){
6645  $this->message[$pos]['typePrefix'] = $regs[1];
6646  $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6647  if (isset($this->namespaces[$regs[1]])) {
6648  $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6649  } else if (isset($attrs['xmlns:'.$regs[1]])) {
6650  $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
6651  }
6652  $this->message[$pos]['arrayType'] = $regs[2];
6653  $this->message[$pos]['arraySize'] = $regs[3];
6654  $this->message[$pos]['arrayCols'] = $regs[4];
6655  }
6656  // specifies nil value (or not)
6657  } elseif ($key_localpart == 'nil'){
6658  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6659  // some other attribute
6660  } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6661  $this->message[$pos]['xattrs']['!' . $key] = $value;
6662  }
6663 
6664  if ($key == 'xmlns') {
6665  $this->default_namespace = $value;
6666  }
6667  // log id
6668  if($key == 'id'){
6669  $this->ids[$value] = $pos;
6670  }
6671  // root
6672  if($key_localpart == 'root' && $value == 1){
6673  $this->status = 'method';
6674  $this->root_struct_name = $name;
6675  $this->root_struct = $pos;
6676  $this->debug("found root struct $this->root_struct_name, pos $pos");
6677  }
6678  // for doclit
6679  $attstr .= " $key=\"$value\"";
6680  }
6681  // get namespace - must be done after namespace atts are processed
6682  if(isset($prefix)){
6683  $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6684  $this->default_namespace = $this->namespaces[$prefix];
6685  } else {
6686  $this->message[$pos]['namespace'] = $this->default_namespace;
6687  }
6688  if($this->status == 'header'){
6689  if ($this->root_header != $pos) {
6690  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6691  }
6692  } elseif($this->root_struct_name != ''){
6693  $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6694  }
6695  }
6696 
6704  function end_element($parser, $name) {
6705  // position of current element is equal to the last value left in depth_array for my depth
6706  $pos = $this->depth_array[$this->depth--];
6707 
6708  // get element prefix
6709  if(strpos($name,':')){
6710  // get ns prefix
6711  $prefix = substr($name,0,strpos($name,':'));
6712  // get unqualified name
6713  $name = substr(strstr($name,':'),1);
6714  }
6715 
6716  // build to native type
6717  if(isset($this->body_position) && $pos > $this->body_position){
6718  // deal w/ multirefs
6719  if(isset($this->message[$pos]['attrs']['href'])){
6720  // get id
6721  $id = substr($this->message[$pos]['attrs']['href'],1);
6722  // add placeholder to href array
6723  $this->multirefs[$id][$pos] = 'placeholder';
6724  // add set a reference to it as the result value
6725  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6726  // build complexType values
6727  } elseif($this->message[$pos]['children'] != ''){
6728  // if result has already been generated (struct/array)
6729  if(!isset($this->message[$pos]['result'])){
6730  $this->message[$pos]['result'] = $this->buildVal($pos);
6731  }
6732  // build complexType values of attributes and possibly simpleContent
6733  } elseif (isset($this->message[$pos]['xattrs'])) {
6734  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6735  $this->message[$pos]['xattrs']['!'] = null;
6736  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6737  if (isset($this->message[$pos]['type'])) {
6738  $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'] : '');
6739  } else {
6740  $parent = $this->message[$pos]['parent'];
6741  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6742  $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6743  } else {
6744  $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6745  }
6746  }
6747  }
6748  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6749  // set value of simpleType (or nil complexType)
6750  } else {
6751  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
6752  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6753  $this->message[$pos]['xattrs']['!'] = null;
6754  } elseif (isset($this->message[$pos]['type'])) {
6755  $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'] : '');
6756  } else {
6757  $parent = $this->message[$pos]['parent'];
6758  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6759  $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6760  } else {
6761  $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
6762  }
6763  }
6764 
6765  /* add value to parent's result, if parent is struct/array
6766  $parent = $this->message[$pos]['parent'];
6767  if($this->message[$parent]['type'] != 'map'){
6768  if(strtolower($this->message[$parent]['type']) == 'array'){
6769  $this->message[$parent]['result'][] = $this->message[$pos]['result'];
6770  } else {
6771  $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
6772  }
6773  }
6774  */
6775  }
6776  }
6777 
6778  // for doclit
6779  if($this->status == 'header'){
6780  if ($this->root_header != $pos) {
6781  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6782  }
6783  } elseif($pos >= $this->root_struct){
6784  $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6785  }
6786  // switch status
6787  if($pos == $this->root_struct){
6788  $this->status = 'body';
6789  $this->root_struct_namespace = $this->message[$pos]['namespace'];
6790  } elseif($name == 'Body'){
6791  $this->status = 'envelope';
6792  } elseif($name == 'Header'){
6793  $this->status = 'envelope';
6794  } elseif($name == 'Envelope'){
6795  //
6796  }
6797  // set parent back to my parent
6798  $this->parent = $this->message[$pos]['parent'];
6799  }
6800 
6808  function character_data($parser, $data){
6809  $pos = $this->depth_array[$this->depth];
6810  if ($this->xml_encoding=='UTF-8'){
6811  // TODO: add an option to disable this for folks who want
6812  // raw UTF-8 that, e.g., might not map to iso-8859-1
6813  // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
6814  if($this->decode_utf8){
6815  $data = utf8_decode($data);
6816  }
6817  }
6818  $this->message[$pos]['cdata'] .= $data;
6819  // for doclit
6820  if($this->status == 'header'){
6821  $this->responseHeaders .= $data;
6822  } else {
6823  $this->document .= $data;
6824  }
6825  }
6826 
6834  function get_response(){
6835  return $this->soapresponse;
6836  }
6837 
6844  function get_soapbody(){
6845  return $this->soapresponse;
6846  }
6847 
6854  function get_soapheader(){
6855  return $this->soapheader;
6856  }
6857 
6864  function getHeaders(){
6865  return $this->responseHeaders;
6866  }
6867 
6877  function decodeSimple($value, $type, $typens) {
6878  // TODO: use the namespace!
6879  if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
6880  return (string) $value;
6881  }
6882  if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
6883  return (int) $value;
6884  }
6885  if ($type == 'float' || $type == 'double' || $type == 'decimal') {
6886  return (double) $value;
6887  }
6888  if ($type == 'boolean') {
6889  if (strtolower($value) == 'false' || strtolower($value) == 'f') {
6890  return false;
6891  }
6892  return (boolean) $value;
6893  }
6894  if ($type == 'base64' || $type == 'base64Binary') {
6895  $this->debug('Decode base64 value');
6896  return base64_decode($value);
6897  }
6898  // obscure numeric types
6899  if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
6900  || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
6901  || $type == 'unsignedInt'
6902  || $type == 'unsignedShort' || $type == 'unsignedByte') {
6903  return (int) $value;
6904  }
6905  // bogus: parser treats array with no elements as a simple type
6906  if ($type == 'array') {
6907  return array();
6908  }
6909  // everything else
6910  return (string) $value;
6911  }
6912 
6921  function buildVal($pos){
6922  if(!isset($this->message[$pos]['type'])){
6923  $this->message[$pos]['type'] = '';
6924  }
6925  $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
6926  // if there are children...
6927  if($this->message[$pos]['children'] != ''){
6928  $this->debug('in buildVal, there are children');
6929  $children = explode('|',$this->message[$pos]['children']);
6930  array_shift($children); // knock off empty
6931  // md array
6932  if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
6933  $r=0; // rowcount
6934  $c=0; // colcount
6935  foreach($children as $child_pos){
6936  $this->debug("in buildVal, got an MD array element: $r, $c");
6937  $params[$r][] = $this->message[$child_pos]['result'];
6938  $c++;
6939  if($c == $this->message[$pos]['arrayCols']){
6940  $c = 0;
6941  $r++;
6942  }
6943  }
6944  // array
6945  } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
6946  $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
6947  foreach($children as $child_pos){
6948  $params[] = &$this->message[$child_pos]['result'];
6949  }
6950  // apache Map type: java hashtable
6951  } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
6952  $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
6953  foreach($children as $child_pos){
6954  $kv = explode("|",$this->message[$child_pos]['children']);
6955  $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
6956  }
6957  // generic compound type
6958  //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
6959  } else {
6960  // Apache Vector type: treat as an array
6961  $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
6962  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
6963  $notstruct = 1;
6964  } else {
6965  $notstruct = 0;
6966  }
6967  //
6968  foreach($children as $child_pos){
6969  if($notstruct){
6970  $params[] = &$this->message[$child_pos]['result'];
6971  } else {
6972  if (isset($params[$this->message[$child_pos]['name']])) {
6973  // de-serialize repeated element name into an array
6974  if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
6975  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
6976  }
6977  $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
6978  } else {
6979  $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
6980  }
6981  }
6982  }
6983  }
6984  if (isset($this->message[$pos]['xattrs'])) {
6985  $this->debug('in buildVal, handling attributes');
6986  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
6987  $params[$n] = $v;
6988  }
6989  }
6990  // handle simpleContent
6991  if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6992  $this->debug('in buildVal, handling simpleContent');
6993  if (isset($this->message[$pos]['type'])) {
6994  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6995  } else {
6996  $parent = $this->message[$pos]['parent'];
6997  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6998  $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6999  } else {
7000  $params['!'] = $this->message[$pos]['cdata'];
7001  }
7002  }
7003  }
7004  $ret = is_array($params) ? $params : array();
7005  $this->debug('in buildVal, return:');
7006  $this->appendDebug($this->varDump($ret));
7007  return $ret;
7008  } else {
7009  $this->debug('in buildVal, no children, building scalar');
7010  $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7011  if (isset($this->message[$pos]['type'])) {
7012  $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7013  $this->debug("in buildVal, return: $ret");
7014  return $ret;
7015  }
7016  $parent = $this->message[$pos]['parent'];
7017  if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7018  $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7019  $this->debug("in buildVal, return: $ret");
7020  return $ret;
7021  }
7022  $ret = $this->message[$pos]['cdata'];
7023  $this->debug("in buildVal, return: $ret");
7024  return $ret;
7025  }
7026  }
7027 }
7028 
7032 class soap_parser extends nusoap_parser {
7033 }
7034 
7035 ?><?php
7036 
7037 
7038 
7060 
7061  var $username = ''; // Username for HTTP authentication
7062  var $password = ''; // Password for HTTP authentication
7063  var $authtype = ''; // Type of HTTP authentication
7064  var $certRequest = array(); // Certificate for HTTP SSL authentication
7065  var $requestHeaders = false; // SOAP headers in request (text)
7066  var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
7067  var $responseHeader = NULL; // SOAP Header from response (parsed)
7068  var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
7070  var $forceEndpoint = ''; // overrides WSDL endpoint
7071  var $proxyhost = '';
7072  var $proxyport = '';
7073  var $proxyusername = '';
7074  var $proxypassword = '';
7075  var $xml_encoding = ''; // character set encoding of incoming (response) messages
7076  var $http_encoding = false;
7077  var $timeout = 0; // HTTP connection timeout
7078  var $response_timeout = 30; // HTTP response timeout
7079  var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
7081  var $defaultRpcParams = false; // This is no longer used
7082  var $request = ''; // HTTP request
7083  var $response = ''; // HTTP response
7084  var $responseData = ''; // SOAP payload of response
7085  var $cookies = array(); // Cookies from response or for request
7086  var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
7087  var $operations = array(); // WSDL operations, empty for WSDL initialization error
7088  var $curl_options = array(); // User-specified cURL options
7089  var $bindingType = ''; // WSDL operation binding type
7090  var $use_curl = false; // whether to always try to use cURL
7091 
7092  /*
7093  * fault related variables
7094  */
7099  var $fault;
7115 
7130  function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
7132  $this->endpoint = $endpoint;
7133  $this->proxyhost = $proxyhost;
7134  $this->proxyport = $proxyport;
7135  $this->proxyusername = $proxyusername;
7136  $this->proxypassword = $proxypassword;
7137  $this->timeout = $timeout;
7138  $this->response_timeout = $response_timeout;
7139 
7140  $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7141  $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7142 
7143  // make values
7144  if($wsdl){
7145  if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
7146  $this->wsdl = $endpoint;
7147  $this->endpoint = $this->wsdl->wsdl;
7148  $this->wsdlFile = $this->endpoint;
7149  $this->debug('existing wsdl instance created from ' . $this->endpoint);
7150  $this->checkWSDL();
7151  } else {
7152  $this->wsdlFile = $this->endpoint;
7153  $this->wsdl = null;
7154  $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7155  }
7156  $this->endpointType = 'wsdl';
7157  } else {
7158  $this->debug("instantiate SOAP with endpoint at $endpoint");
7159  $this->endpointType = 'soap';
7160  }
7161  }
7162 
7188  function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
7189  $this->operation = $operation;
7190  $this->fault = false;
7191  $this->setError('');
7192  $this->request = '';
7193  $this->response = '';
7194  $this->responseData = '';
7195  $this->faultstring = '';
7196  $this->faultcode = '';
7197  $this->opData = array();
7198 
7199  $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7200  $this->appendDebug('params=' . $this->varDump($params));
7201  $this->appendDebug('headers=' . $this->varDump($headers));
7202  if ($headers) {
7203  $this->requestHeaders = $headers;
7204  }
7205  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7206  $this->loadWSDL();
7207  if ($this->getError())
7208  return false;
7209  }
7210  // serialize parameters
7211  if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
7212  // use WSDL for operation
7213  $this->opData = $opData;
7214  $this->debug("found operation");
7215  $this->appendDebug('opData=' . $this->varDump($opData));
7216  if (isset($opData['soapAction'])) {
7217  $soapAction = $opData['soapAction'];
7218  }
7219  if (! $this->forceEndpoint) {
7220  $this->endpoint = $opData['endpoint'];
7221  } else {
7222  $this->endpoint = $this->forceEndpoint;
7223  }
7224  $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7225  $style = $opData['style'];
7226  $use = $opData['input']['use'];
7227  // add ns to ns array
7228  if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
7229  $nsPrefix = 'ns' . rand(1000, 9999);
7230  $this->wsdl->namespaces[$nsPrefix] = $namespace;
7231  }
7232  $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7233  // serialize payload
7234  if (is_string($params)) {
7235  $this->debug("serializing param string for WSDL operation $operation");
7236  $payload = $params;
7237  } elseif (is_array($params)) {
7238  $this->debug("serializing param array for WSDL operation $operation");
7239  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
7240  } else {
7241  $this->debug('params must be array or string');
7242  $this->setError('params must be array or string');
7243  return false;
7244  }
7245  $usedNamespaces = $this->wsdl->usedNamespaces;
7246  if (isset($opData['input']['encodingStyle'])) {
7247  $encodingStyle = $opData['input']['encodingStyle'];
7248  } else {
7249  $encodingStyle = '';
7250  }
7251  $this->appendDebug($this->wsdl->getDebug());
7252  $this->wsdl->clearDebug();
7253  if ($errstr = $this->wsdl->getError()) {
7254  $this->debug('got wsdl error: '.$errstr);
7255  $this->setError('wsdl error: '.$errstr);
7256  return false;
7257  }
7258  } elseif($this->endpointType == 'wsdl') {
7259  // operation not in WSDL
7260  $this->appendDebug($this->wsdl->getDebug());
7261  $this->wsdl->clearDebug();
7262  $this->setError( 'operation '.$operation.' not present.');
7263  $this->debug("operation '$operation' not present.");
7264  return false;
7265  } else {
7266  // no WSDL
7267  //$this->namespaces['ns1'] = $namespace;
7268  $nsPrefix = 'ns' . rand(1000, 9999);
7269  // serialize
7270  $payload = '';
7271  if (is_string($params)) {
7272  $this->debug("serializing param string for operation $operation");
7273  $payload = $params;
7274  } elseif (is_array($params)) {
7275  $this->debug("serializing param array for operation $operation");
7276  foreach($params as $k => $v){
7277  $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
7278  }
7279  } else {
7280  $this->debug('params must be array or string');
7281  $this->setError('params must be array or string');
7282  return false;
7283  }
7284  $usedNamespaces = array();
7285  if ($use == 'encoded') {
7286  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7287  } else {
7288  $encodingStyle = '';
7289  }
7290  }
7291  // wrap RPC calls with method element
7292  if ($style == 'rpc') {
7293  if ($use == 'literal') {
7294  $this->debug("wrapping RPC request with literal method element");
7295  if ($namespace) {
7296  // 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
7297  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7298  $payload .
7299  "</$nsPrefix:$operation>";
7300  } else {
7301  $payload = "<$operation>" . $payload . "</$operation>";
7302  }
7303  } else {
7304  $this->debug("wrapping RPC request with encoded method element");
7305  if ($namespace) {
7306  $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7307  $payload .
7308  "</$nsPrefix:$operation>";
7309  } else {
7310  $payload = "<$operation>" .
7311  $payload .
7312  "</$operation>";
7313  }
7314  }
7315  }
7316  // serialize envelope
7317  $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
7318  $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7319  $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7320  // send
7321  $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
7322  if($errstr = $this->getError()){
7323  $this->debug('Error: '.$errstr);
7324  return false;
7325  } else {
7326  $this->return = $return;
7327  $this->debug('sent message successfully and got a(n) '.gettype($return));
7328  $this->appendDebug('return=' . $this->varDump($return));
7329 
7330  // fault?
7331  if(is_array($return) && isset($return['faultcode'])){
7332  $this->debug('got fault');
7333  $this->setError($return['faultcode'].': '.$return['faultstring']);
7334  $this->fault = true;
7335  foreach($return as $k => $v){
7336  $this->$k = $v;
7337  $this->debug("$k = $v<br>");
7338  }
7339  return $return;
7340  } elseif ($style == 'document') {
7341  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7342  // we are only going to return the first part here...sorry about that
7343  return $return;
7344  } else {
7345  // array of return values
7346  if(is_array($return)){
7347  // multiple 'out' parameters, which we return wrapped up
7348  // in the array
7349  if(sizeof($return) > 1){
7350  return $return;
7351  }
7352  // single 'out' parameter (normally the return value)
7353  $return = array_shift($return);
7354  $this->debug('return shifted value: ');
7355  $this->appendDebug($this->varDump($return));
7356  return $return;
7357  // nothing returned (ie, echoVoid)
7358  } else {
7359  return "";
7360  }
7361  }
7362  }
7363  }
7364 
7370  function checkWSDL() {
7371  $this->appendDebug($this->wsdl->getDebug());
7372  $this->wsdl->clearDebug();
7373  $this->debug('checkWSDL');
7374  // catch errors
7375  if ($errstr = $this->wsdl->getError()) {
7376  $this->debug('got wsdl error: '.$errstr);
7377  $this->setError('wsdl error: '.$errstr);
7378  } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
7379  $this->bindingType = 'soap';
7380  $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7381  } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
7382  $this->bindingType = 'soap12';
7383  $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7384  $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7385  } else {
7386  $this->debug('getOperations returned false');
7387  $this->setError('no operations defined in the WSDL document!');
7388  }
7389  }
7390 
7396  function loadWSDL() {
7397  $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
7398  $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
7399  $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7400  $this->wsdl->fetchWSDL($this->wsdlFile);
7401  $this->checkWSDL();
7402  }
7403 
7411  function getOperationData($operation){
7412  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7413  $this->loadWSDL();
7414  if ($this->getError())
7415  return false;
7416  }
7417  if(isset($this->operations[$operation])){
7418  return $this->operations[$operation];
7419  }
7420  $this->debug("No data for operation: $operation");
7421  }
7422 
7437  function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
7438  $this->checkCookies();
7439  // detect transport
7440  switch(true){
7441  // http(s)
7442  case preg_match('/^http/',$this->endpoint):
7443  $this->debug('transporting via HTTP');
7444  if($this->persistentConnection == true && is_object($this->persistentConnection)){
7445  $http =& $this->persistentConnection;
7446  } else {
7447  $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7448  if ($this->persistentConnection) {
7449  $http->usePersistentConnection();
7450  }
7451  }
7452  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7453  $http->setSOAPAction($soapaction);
7454  if($this->proxyhost && $this->proxyport){
7455  $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
7456  }
7457  if($this->authtype != '') {
7458  $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
7459  }
7460  if($this->http_encoding != ''){
7461  $http->setEncoding($this->http_encoding);
7462  }
7463  $this->debug('sending message, length='.strlen($msg));
7464  if(preg_match('/^http:/',$this->endpoint)){
7465  //if(strpos($this->endpoint,'http:')){
7466  $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
7467  } elseif(preg_match('/^https/',$this->endpoint)){
7468  //} elseif(strpos($this->endpoint,'https:')){
7469  //if(phpversion() == '4.3.0-dev'){
7470  //$response = $http->send($msg,$timeout,$response_timeout);
7471  //$this->request = $http->outgoing_payload;
7472  //$this->response = $http->incoming_payload;
7473  //} else
7474  $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
7475  } else {
7476  $this->setError('no http/s in endpoint url');
7477  }
7478  $this->request = $http->outgoing_payload;
7479  $this->response = $http->incoming_payload;
7480  $this->appendDebug($http->getDebug());
7481  $this->UpdateCookies($http->incoming_cookies);
7482 
7483  // save transport object if using persistent connections
7484  if ($this->persistentConnection) {
7485  $http->clearDebug();
7486  if (!is_object($this->persistentConnection)) {
7487  $this->persistentConnection = $http;
7488  }
7489  }
7490 
7491  if($err = $http->getError()){
7492  $this->setError('HTTP Error: '.$err);
7493  return false;
7494  } elseif($this->getError()){
7495  return false;
7496  } else {
7497  $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
7498  return $this->parseResponse($http->incoming_headers, $this->responseData);
7499  }
7500  break;
7501  default:
7502  $this->setError('no transport found, or selected transport is not yet supported!');
7503  return false;
7504  break;
7505  }
7506  }
7507 
7516  function parseResponse($headers, $data) {
7517  $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7518  $this->appendDebug($this->varDump($headers));
7519  if (!strstr($headers['content-type'], 'text/xml')) {
7520  $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7521  return false;
7522  }
7523  if (strpos($headers['content-type'], '=')) {
7524  $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
7525  $this->debug('Got response encoding: ' . $enc);
7526  if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
7527  $this->xml_encoding = strtoupper($enc);
7528  } else {
7529  $this->xml_encoding = 'US-ASCII';
7530  }
7531  } else {
7532  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
7533  $this->xml_encoding = 'ISO-8859-1';
7534  }
7535  $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7536  $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
7537  // add parser debug data to our debug
7538  $this->appendDebug($parser->getDebug());
7539  // if parse errors
7540  if($errstr = $parser->getError()){
7541  $this->setError( $errstr);
7542  // destroy the parser object
7543  unset($parser);
7544  return false;
7545  } else {
7546  // get SOAP headers
7547  $this->responseHeaders = $parser->getHeaders();
7548  // get SOAP headers
7549  $this->responseHeader = $parser->get_soapheader();
7550  // get decoded message
7551  $return = $parser->get_soapbody();
7552  // add document for doclit support
7553  $this->document = $parser->document;
7554  // destroy the parser object
7555  unset($parser);
7556  // return decode message
7557  return $return;
7558  }
7559  }
7560 
7568  function setCurlOption($option, $value) {
7569  $this->debug("setCurlOption option=$option, value=");
7570  $this->appendDebug($this->varDump($value));
7571  $this->curl_options[$option] = $value;
7572  }
7573 
7581  $this->debug("setEndpoint(\"$endpoint\")");
7582  $this->forceEndpoint = $endpoint;
7583  }
7584 
7591  function setHeaders($headers){
7592  $this->debug("setHeaders headers=");
7593  $this->appendDebug($this->varDump($headers));
7594  $this->requestHeaders = $headers;
7595  }
7596 
7603  function getHeaders(){
7604  return $this->responseHeaders;
7605  }
7606 
7613  function getHeader(){
7614  return $this->responseHeader;
7615  }
7616 
7627  $this->proxyhost = $proxyhost;
7628  $this->proxyport = $proxyport;
7629  $this->proxyusername = $proxyusername;
7630  $this->proxypassword = $proxypassword;
7631  }
7632 
7642  function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
7643  $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7644  $this->appendDebug($this->varDump($certRequest));
7645  $this->username = $username;
7646  $this->password = $password;
7647  $this->authtype = $authtype;
7648  $this->certRequest = $certRequest;
7649  }
7650 
7657  function setHTTPEncoding($enc='gzip, deflate'){
7658  $this->debug("setHTTPEncoding(\"$enc\")");
7659  $this->http_encoding = $enc;
7660  }
7661 
7668  function setUseCURL($use) {
7669  $this->debug("setUseCURL($use)");
7670  $this->use_curl = $use;
7671  }
7672 
7679  $this->debug("useHTTPPersistentConnection");
7680  $this->persistentConnection = true;
7681  }
7682 
7694  function getDefaultRpcParams() {
7695  return $this->defaultRpcParams;
7696  }
7697 
7709  function setDefaultRpcParams($rpcParams) {
7710  $this->defaultRpcParams = $rpcParams;
7711  }
7712 
7720  function getProxy() {
7721  $r = rand();
7722  $evalStr = $this->_getProxyClassCode($r);
7723  //$this->debug("proxy class: $evalStr");
7724  if ($this->getError()) {
7725  $this->debug("Error from _getProxyClassCode, so return NULL");
7726  return null;
7727  }
7728  // eval the class
7729  eval($evalStr);
7730  // instantiate proxy object
7731  eval("\$proxy = new nusoap_proxy_$r('');");
7732  // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
7733  $proxy->endpointType = 'wsdl';
7734  $proxy->wsdlFile = $this->wsdlFile;
7735  $proxy->wsdl = $this->wsdl;
7736  $proxy->operations = $this->operations;
7737  $proxy->defaultRpcParams = $this->defaultRpcParams;
7738  // transfer other state
7739  $proxy->soap_defencoding = $this->soap_defencoding;
7740  $proxy->username = $this->username;
7741  $proxy->password = $this->password;
7742  $proxy->authtype = $this->authtype;
7743  $proxy->certRequest = $this->certRequest;
7744  $proxy->requestHeaders = $this->requestHeaders;
7745  $proxy->endpoint = $this->endpoint;
7746  $proxy->forceEndpoint = $this->forceEndpoint;
7747  $proxy->proxyhost = $this->proxyhost;
7748  $proxy->proxyport = $this->proxyport;
7749  $proxy->proxyusername = $this->proxyusername;
7750  $proxy->proxypassword = $this->proxypassword;
7751  $proxy->http_encoding = $this->http_encoding;
7752  $proxy->timeout = $this->timeout;
7753  $proxy->response_timeout = $this->response_timeout;
7754  $proxy->persistentConnection = &$this->persistentConnection;
7755  $proxy->decode_utf8 = $this->decode_utf8;
7756  $proxy->curl_options = $this->curl_options;
7757  $proxy->bindingType = $this->bindingType;
7758  $proxy->use_curl = $this->use_curl;
7759  return $proxy;
7760  }
7761 
7768  function _getProxyClassCode($r) {
7769  $this->debug("in getProxy endpointType=$this->endpointType");
7770  $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
7771  if ($this->endpointType != 'wsdl') {
7772  $evalStr = 'A proxy can only be created for a WSDL client';
7773  $this->setError($evalStr);
7774  $evalStr = "echo \"$evalStr\";";
7775  return $evalStr;
7776  }
7777  if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7778  $this->loadWSDL();
7779  if ($this->getError()) {
7780  return "echo \"" . $this->getError() . "\";";
7781  }
7782  }
7783  $evalStr = '';
7784  foreach ($this->operations as $operation => $opData) {
7785  if ($operation != '') {
7786  // create param string and param comment string
7787  if (sizeof($opData['input']['parts']) > 0) {
7788  $paramStr = '';
7789  $paramArrayStr = '';
7790  $paramCommentStr = '';
7791  foreach ($opData['input']['parts'] as $name => $type) {
7792  $paramStr .= "\$$name, ";
7793  $paramArrayStr .= "'$name' => \$$name, ";
7794  $paramCommentStr .= "$type \$$name, ";
7795  }
7796  $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
7797  $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
7798  $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
7799  } else {
7800  $paramStr = '';
7801  $paramArrayStr = '';
7802  $paramCommentStr = 'void';
7803  }
7804  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7805  $evalStr .= "// $paramCommentStr
7806  function " . str_replace('.', '__', $operation) . "($paramStr) {
7807  \$params = array($paramArrayStr);
7808  return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
7809  }
7810  ";
7811  unset($paramStr);
7812  unset($paramCommentStr);
7813  }
7814  }
7815  $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
7816  '.$evalStr.'
7817 }';
7818  return $evalStr;
7819  }
7820 
7827  function getProxyClassCode() {
7828  $r = rand();
7829  return $this->_getProxyClassCode($r);
7830  }
7831 
7839  function getHTTPBody($soapmsg) {
7840  return $soapmsg;
7841  }
7842 
7851  function getHTTPContentType() {
7852  return 'text/xml';
7853  }
7854 
7865  return $this->soap_defencoding;
7866  }
7867 
7868  /*
7869  * whether or not parser should decode utf8 element content
7870  *
7871  * @return always returns true
7872  * @access public
7873  */
7874  function decodeUTF8($bool){
7875  $this->decode_utf8 = $bool;
7876  return true;
7877  }
7878 
7887  function setCookie($name, $value) {
7888  if (strlen($name) == 0) {
7889  return false;
7890  }
7891  $this->cookies[] = array('name' => $name, 'value' => $value);
7892  return true;
7893  }
7894 
7901  function getCookies() {
7902  return $this->cookies;
7903  }
7904 
7911  function checkCookies() {
7912  if (sizeof($this->cookies) == 0) {
7913  return true;
7914  }
7915  $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
7916  $curr_cookies = $this->cookies;
7917  $this->cookies = array();
7918  foreach ($curr_cookies as $cookie) {
7919  if (! is_array($cookie)) {
7920  $this->debug('Remove cookie that is not an array');
7921  continue;
7922  }
7923  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
7924  if (strtotime($cookie['expires']) > time()) {
7925  $this->cookies[] = $cookie;
7926  } else {
7927  $this->debug('Remove expired cookie ' . $cookie['name']);
7928  }
7929  } else {
7930  $this->cookies[] = $cookie;
7931  }
7932  }
7933  $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
7934  return true;
7935  }
7936 
7945  if (sizeof($this->cookies) == 0) {
7946  // no existing cookies: take whatever is new
7947  if (sizeof($cookies) > 0) {
7948  $this->debug('Setting new cookie(s)');
7949  $this->cookies = $cookies;
7950  }
7951  return true;
7952  }
7953  if (sizeof($cookies) == 0) {
7954  // no new cookies: keep what we've got
7955  return true;
7956  }
7957  // merge
7958  foreach ($cookies as $newCookie) {
7959  if (!is_array($newCookie)) {
7960  continue;
7961  }
7962  if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
7963  continue;
7964  }
7965  $newName = $newCookie['name'];
7966 
7967  $found = false;
7968  for ($i = 0; $i < count($this->cookies); $i++) {
7969  $cookie = $this->cookies[$i];
7970  if (!is_array($cookie)) {
7971  continue;
7972  }
7973  if (!isset($cookie['name'])) {
7974  continue;
7975  }
7976  if ($newName != $cookie['name']) {
7977  continue;
7978  }
7979  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
7980  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
7981  if ($newDomain != $domain) {
7982  continue;
7983  }
7984  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
7985  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
7986  if ($newPath != $path) {
7987  continue;
7988  }
7989  $this->cookies[$i] = $newCookie;
7990  $found = true;
7991  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
7992  break;
7993  }
7994  if (! $found) {
7995  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
7996  $this->cookies[] = $newCookie;
7997  }
7998  }
7999  return true;
8000  }
8001 }
8002 
8003 if (!extension_loaded('soap')) {
8007  class soapclient extends nusoap_client {
8008  }
8009 }
8010 ?>