[ Index ]
 

Code source de Mantis 1.1.0rc3

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/api/soap/nusoap/ -> nusoap.php (source)

   1  <?php
   2  
   3  /*

   4  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

   5  

   6  NuSOAP - Web Services Toolkit for PHP

   7  

   8  Copyright (c) 2002 NuSphere Corporation

   9  

  10  This library is free software; you can redistribute it and/or

  11  modify it under the terms of the GNU Lesser General Public

  12  License as published by the Free Software Foundation; either

  13  version 2.1 of the License, or (at your option) any later version.

  14  

  15  This library is distributed in the hope that it will be useful,

  16  but WITHOUT ANY WARRANTY; without even the implied warranty of

  17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

  18  Lesser General Public License for more details.

  19  

  20  You should have received a copy of the GNU Lesser General Public

  21  License along with this library; if not, write to the Free Software

  22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  23  

  24  The NuSOAP project home is:

  25  http://sourceforge.net/projects/nusoap/

  26  

  27  The primary support for NuSOAP is the mailing list:

  28  nusoap-general@lists.sourceforge.net

  29  

  30  If you have any questions or comments, please email:

  31  

  32  Dietrich Ayala

  33  dietrich@ganx4.com

  34  http://dietrich.ganx4.com/nusoap

  35  

  36  NuSphere Corporation

  37  http://www.nusphere.com

  38  

  39  */
  40  
  41  /*

  42   *    Some of the standards implmented in whole or part by NuSOAP:

  43   *

  44   *    SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)

  45   *    WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)

  46   *    SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)

  47   *    XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)

  48   *    Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)

  49   *    XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)

  50   *    RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies

  51   *    RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1

  52   *    RFC 2617 HTTP Authentication: Basic and Digest Access Authentication

  53   */
  54  
  55  /* load classes

  56  

  57  // necessary classes

  58  require_once('class.soapclient.php');

  59  require_once('class.soap_val.php');

  60  require_once('class.soap_parser.php');

  61  require_once('class.soap_fault.php');

  62  

  63  // transport classes

  64  require_once('class.soap_transport_http.php');

  65  

  66  // optional add-on classes

  67  require_once('class.xmlschema.php');

  68  require_once('class.wsdl.php');

  69  

  70  // server class

  71  require_once('class.soap_server.php');*/
  72  
  73  // class variable emulation

  74  // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html

  75  $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
  76  
  77  /**

  78  *

  79  * nusoap_base

  80  *

  81  * @author   Dietrich Ayala <dietrich@ganx4.com>

  82  * @author   Scott Nichol <snichol@users.sourceforge.net>

  83  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

  84  * @access   public

  85  */
  86  class nusoap_base {
  87      /**

  88       * Identification for HTTP headers.

  89       *

  90       * @var string

  91       * @access private

  92       */
  93      var $title = 'NuSOAP';
  94      /**

  95       * Version for HTTP headers.

  96       *

  97       * @var string

  98       * @access private

  99       */
 100      var $version = '0.7.3';
 101      /**

 102       * CVS revision for HTTP headers.

 103       *

 104       * @var string

 105       * @access private

 106       */
 107      var $revision = '$Revision: 1.114 $';
 108      /**

 109       * Current error string (manipulated by getError/setError)

 110       *

 111       * @var string

 112       * @access private

 113       */
 114      var $error_str = '';
 115      /**

 116       * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)

 117       *

 118       * @var string

 119       * @access private

 120       */
 121      var $debug_str = '';
 122      /**

 123       * toggles automatic encoding of special characters as entities

 124       * (should always be true, I think)

 125       *

 126       * @var boolean

 127       * @access private

 128       */
 129      var $charencoding = true;
 130      /**

 131       * the debug level for this instance

 132       *

 133       * @var    integer

 134       * @access private

 135       */
 136      var $debugLevel;
 137  
 138      /**

 139      * set schema version

 140      *

 141      * @var      string

 142      * @access   public

 143      */
 144      var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
 145      
 146      /**

 147      * charset encoding for outgoing messages

 148      *

 149      * @var      string

 150      * @access   public

 151      */
 152      var $soap_defencoding = 'ISO-8859-1';
 153      //var $soap_defencoding = 'UTF-8';

 154  
 155      /**

 156      * namespaces in an array of prefix => uri

 157      *

 158      * this is "seeded" by a set of constants, but it may be altered by code

 159      *

 160      * @var      array

 161      * @access   public

 162      */
 163      var $namespaces = array(
 164          'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
 165          'xsd' => 'http://www.w3.org/2001/XMLSchema',
 166          'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
 167          'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
 168          );
 169  
 170      /**

 171      * namespaces used in the current context, e.g. during serialization

 172      *

 173      * @var      array

 174      * @access   private

 175      */
 176      var $usedNamespaces = array();
 177  
 178      /**

 179      * XML Schema types in an array of uri => (array of xml type => php type)

 180      * is this legacy yet?

 181      * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.

 182      * @var      array

 183      * @access   public

 184      */
 185      var $typemap = array(
 186      'http://www.w3.org/2001/XMLSchema' => array(
 187          'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
 188          'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
 189          'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
 190          // abstract "any" types

 191          'anyType'=>'string','anySimpleType'=>'string',
 192          // derived datatypes

 193          'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
 194          'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
 195          'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
 196          'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
 197      'http://www.w3.org/2000/10/XMLSchema' => array(
 198          'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
 199          'float'=>'double','dateTime'=>'string',
 200          'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
 201      'http://www.w3.org/1999/XMLSchema' => array(
 202          'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
 203          'float'=>'double','dateTime'=>'string',
 204          'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
 205      'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
 206      'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
 207      'http://xml.apache.org/xml-soap' => array('Map')
 208      );
 209  
 210      /**

 211      * XML entities to convert

 212      *

 213      * @var      array

 214      * @access   public

 215      * @deprecated

 216      * @see    expandEntities

 217      */
 218      var $xmlEntities = array('quot' => '"','amp' => '&',
 219          'lt' => '<','gt' => '>','apos' => "'");
 220  
 221      /**

 222      * constructor

 223      *

 224      * @access    public

 225      */
 226  	function nusoap_base() {
 227          $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
 228      }
 229  
 230      /**

 231      * gets the global debug level, which applies to future instances

 232      *

 233      * @return    integer    Debug level 0-9, where 0 turns off

 234      * @access    public

 235      */
 236  	function getGlobalDebugLevel() {
 237          return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
 238      }
 239  
 240      /**

 241      * sets the global debug level, which applies to future instances

 242      *

 243      * @param    int    $level    Debug level 0-9, where 0 turns off

 244      * @access    public

 245      */
 246  	function setGlobalDebugLevel($level) {
 247          $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
 248      }
 249  
 250      /**

 251      * gets the debug level for this instance

 252      *

 253      * @return    int    Debug level 0-9, where 0 turns off

 254      * @access    public

 255      */
 256  	function getDebugLevel() {
 257          return $this->debugLevel;
 258      }
 259  
 260      /**

 261      * sets the debug level for this instance

 262      *

 263      * @param    int    $level    Debug level 0-9, where 0 turns off

 264      * @access    public

 265      */
 266  	function setDebugLevel($level) {
 267          $this->debugLevel = $level;
 268      }
 269  
 270      /**

 271      * adds debug data to the instance debug string with formatting

 272      *

 273      * @param    string $string debug data

 274      * @access   private

 275      */
 276  	function debug($string){
 277          if ($this->debugLevel > 0) {
 278              $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
 279          }
 280      }
 281  
 282      /**

 283      * adds debug data to the instance debug string without formatting

 284      *

 285      * @param    string $string debug data

 286      * @access   public

 287      */
 288  	function appendDebug($string){
 289          if ($this->debugLevel > 0) {
 290              // it would be nice to use a memory stream here to use

 291              // memory more efficiently

 292              $this->debug_str .= $string;
 293          }
 294      }
 295  
 296      /**

 297      * clears the current debug data for this instance

 298      *

 299      * @access   public

 300      */
 301  	function clearDebug() {
 302          // it would be nice to use a memory stream here to use

 303          // memory more efficiently

 304          $this->debug_str = '';
 305      }
 306  
 307      /**

 308      * gets the current debug data for this instance

 309      *

 310      * @return   debug data

 311      * @access   public

 312      */
 313      function &getDebug() {
 314          // it would be nice to use a memory stream here to use

 315          // memory more efficiently

 316          return $this->debug_str;
 317      }
 318  
 319      /**

 320      * gets the current debug data for this instance as an XML comment

 321      * this may change the contents of the debug data

 322      *

 323      * @return   debug data as an XML comment

 324      * @access   public

 325      */
 326      function &getDebugAsXMLComment() {
 327          // it would be nice to use a memory stream here to use

 328          // memory more efficiently

 329          while (strpos($this->debug_str, '--')) {
 330              $this->debug_str = str_replace('--', '- -', $this->debug_str);
 331          }
 332          $ret = "<!--\n" . $this->debug_str . "\n-->";
 333          return $ret;
 334      }
 335  
 336      /**

 337      * expands entities, e.g. changes '<' to '&lt;'.

 338      *

 339      * @param    string    $val    The string in which to expand entities.

 340      * @access    private

 341      */
 342  	function expandEntities($val) {
 343          if ($this->charencoding) {
 344              $val = str_replace('&', '&amp;', $val);
 345              $val = str_replace("'", '&apos;', $val);
 346              $val = str_replace('"', '&quot;', $val);
 347              $val = str_replace('<', '&lt;', $val);
 348              $val = str_replace('>', '&gt;', $val);
 349          }
 350          return $val;
 351      }
 352  
 353      /**

 354      * returns error string if present

 355      *

 356      * @return   mixed error string or false

 357      * @access   public

 358      */
 359  	function getError(){
 360          if($this->error_str != ''){
 361              return $this->error_str;
 362          }
 363          return false;
 364      }
 365  
 366      /**

 367      * sets error string

 368      *

 369      * @return   boolean $string error string

 370      * @access   private

 371      */
 372  	function setError($str){
 373          $this->error_str = $str;
 374      }
 375  
 376      /**

 377      * detect if array is a simple array or a struct (associative array)

 378      *

 379      * @param    mixed    $val    The PHP array

 380      * @return    string    (arraySimple|arrayStruct)

 381      * @access    private

 382      */
 383  	function isArraySimpleOrStruct($val) {
 384          $keyList = array_keys($val);
 385          foreach ($keyList as $keyListValue) {
 386              if (!is_int($keyListValue)) {
 387                  return 'arrayStruct';
 388              }
 389          }
 390          return 'arraySimple';
 391      }
 392  
 393      /**

 394      * serializes PHP values in accordance w/ section 5. Type information is

 395      * not serialized if $use == 'literal'.

 396      *

 397      * @param    mixed    $val    The value to serialize

 398      * @param    string    $name    The name (local part) of the XML element

 399      * @param    string    $type    The XML schema type (local part) for the element

 400      * @param    string    $name_ns    The namespace for the name of the XML element

 401      * @param    string    $type_ns    The namespace for the type of the element

 402      * @param    array    $attributes    The attributes to serialize as name=>value pairs

 403      * @param    string    $use    The WSDL "use" (encoded|literal)

 404      * @param    boolean    $soapval    Whether this is called from soapval.

 405      * @return    string    The serialized element, possibly with child elements

 406      * @access    public

 407      */
 408  	function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
 409          $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
 410          $this->appendDebug('value=' . $this->varDump($val));
 411          $this->appendDebug('attributes=' . $this->varDump($attributes));
 412          
 413          if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
 414              $this->debug("serialize_val: serialize soapval");
 415              $xml = $val->serialize($use);
 416              $this->appendDebug($val->getDebug());
 417              $val->clearDebug();
 418              $this->debug("serialize_val of soapval returning $xml");
 419              return $xml;
 420          }
 421          // force valid name if necessary

 422          if (is_numeric($name)) {
 423              $name = '__numeric_' . $name;
 424          } elseif (! $name) {
 425              $name = 'noname';
 426          }
 427          // if name has ns, add ns prefix to name

 428          $xmlns = '';
 429          if($name_ns){
 430              $prefix = 'nu'.rand(1000,9999);
 431              $name = $prefix.':'.$name;
 432              $xmlns .= " xmlns:$prefix=\"$name_ns\"";
 433          }
 434          // if type is prefixed, create type prefix

 435          if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
 436              // need to fix this. shouldn't default to xsd if no ns specified

 437              // w/o checking against typemap

 438              $type_prefix = 'xsd';
 439          } elseif($type_ns){
 440              $type_prefix = 'ns'.rand(1000,9999);
 441              $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
 442          }
 443          // serialize attributes if present

 444          $atts = '';
 445          if($attributes){
 446              foreach($attributes as $k => $v){
 447                  $atts .= " $k=\"".$this->expandEntities($v).'"';
 448              }
 449          }
 450          // serialize null value

 451          if (is_null($val)) {
 452              $this->debug("serialize_val: serialize null");
 453              if ($use == 'literal') {
 454                  // TODO: depends on minOccurs

 455                  $xml = "<$name$xmlns$atts/>";
 456                  $this->debug("serialize_val returning $xml");
 457                  return $xml;
 458              } else {
 459                  if (isset($type) && isset($type_prefix)) {
 460                      $type_str = " xsi:type=\"$type_prefix:$type\"";
 461                  } else {
 462                      $type_str = '';
 463                  }
 464                  $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
 465                  $this->debug("serialize_val returning $xml");
 466                  return $xml;
 467              }
 468          }
 469          // serialize if an xsd built-in primitive type

 470          if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
 471              $this->debug("serialize_val: serialize xsd built-in primitive type");
 472              if (is_bool($val)) {
 473                  if ($type == 'boolean') {
 474                      $val = $val ? 'true' : 'false';
 475                  } elseif (! $val) {
 476                      $val = 0;
 477                  }
 478              } else if (is_string($val)) {
 479                  $val = $this->expandEntities($val);
 480              }
 481              if ($use == 'literal') {
 482                  $xml = "<$name$xmlns$atts>$val</$name>";
 483                  $this->debug("serialize_val returning $xml");
 484                  return $xml;
 485              } else {
 486                  $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
 487                  $this->debug("serialize_val returning $xml");
 488                  return $xml;
 489              }
 490          }
 491          // detect type and serialize

 492          $xml = '';
 493          switch(true) {
 494              case (is_bool($val) || $type == 'boolean'):
 495                     $this->debug("serialize_val: serialize boolean");
 496                  if ($type == 'boolean') {
 497                      $val = $val ? 'true' : 'false';
 498                  } elseif (! $val) {
 499                      $val = 0;
 500                  }
 501                  if ($use == 'literal') {
 502                      $xml .= "<$name$xmlns$atts>$val</$name>";
 503                  } else {
 504                      $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
 505                  }
 506                  break;
 507              case (is_int($val) || is_long($val) || $type == 'int'):
 508                     $this->debug("serialize_val: serialize int");
 509                  if ($use == 'literal') {
 510                      $xml .= "<$name$xmlns$atts>$val</$name>";
 511                  } else {
 512                      $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
 513                  }
 514                  break;
 515              case (is_float($val)|| is_double($val) || $type == 'float'):
 516                     $this->debug("serialize_val: serialize float");
 517                  if ($use == 'literal') {
 518                      $xml .= "<$name$xmlns$atts>$val</$name>";
 519                  } else {
 520                      $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
 521                  }
 522                  break;
 523              case (is_string($val) || $type == 'string'):
 524                     $this->debug("serialize_val: serialize string");
 525                  $val = $this->expandEntities($val);
 526                  if ($use == 'literal') {
 527                      $xml .= "<$name$xmlns$atts>$val</$name>";
 528                  } else {
 529                      $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
 530                  }
 531                  break;
 532              case is_object($val):
 533                     $this->debug("serialize_val: serialize object");
 534                  if (get_class($val) == 'soapval') {
 535                      $this->debug("serialize_val: serialize soapval object");
 536                      $pXml = $val->serialize($use);
 537                      $this->appendDebug($val->getDebug());
 538                      $val->clearDebug();
 539                  } else {
 540                      if (! $name) {
 541                          $name = get_class($val);
 542                          $this->debug("In serialize_val, used class name $name as element name");
 543                      } else {
 544                          $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
 545                      }
 546                      foreach(get_object_vars($val) as $k => $v){
 547                          $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
 548                      }
 549                  }
 550                  if(isset($type) && isset($type_prefix)){
 551                      $type_str = " xsi:type=\"$type_prefix:$type\"";
 552                  } else {
 553                      $type_str = '';
 554                  }
 555                  if ($use == 'literal') {
 556                      $xml .= "<$name$xmlns$atts>$pXml</$name>";
 557                  } else {
 558                      $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
 559                  }
 560                  break;
 561              break;
 562              case (is_array($val) || $type):
 563                  // detect if struct or array

 564                  $valueType = $this->isArraySimpleOrStruct($val);
 565                  if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
 566                         $this->debug("serialize_val: serialize array");
 567                      $i = 0;
 568                      if(is_array($val) && count($val)> 0){
 569                          foreach($val as $v){
 570                              if(is_object($v) && get_class($v) ==  'soapval'){
 571                                  $tt_ns = $v->type_ns;
 572                                  $tt = $v->type;
 573                              } elseif (is_array($v)) {
 574                                  $tt = $this->isArraySimpleOrStruct($v);
 575                              } else {
 576                                  $tt = gettype($v);
 577                              }
 578                              $array_types[$tt] = 1;
 579                              // TODO: for literal, the name should be $name

 580                              $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
 581                              ++$i;
 582                          }
 583                          if(count($array_types) > 1){
 584                              $array_typename = 'xsd:anyType';
 585                          } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
 586                              if ($tt == 'integer') {
 587                                  $tt = 'int';
 588                              }
 589                              $array_typename = 'xsd:'.$tt;
 590                          } elseif(isset($tt) && $tt == 'arraySimple'){
 591                              $array_typename = 'SOAP-ENC:Array';
 592                          } elseif(isset($tt) && $tt == 'arrayStruct'){
 593                              $array_typename = 'unnamed_struct_use_soapval';
 594                          } else {
 595                              // if type is prefixed, create type prefix

 596                              if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
 597                                   $array_typename = 'xsd:' . $tt;
 598                              } elseif ($tt_ns) {
 599                                  $tt_prefix = 'ns' . rand(1000, 9999);
 600                                  $array_typename = "$tt_prefix:$tt";
 601                                  $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
 602                              } else {
 603                                  $array_typename = $tt;
 604                              }
 605                          }
 606                          $array_type = $i;
 607                          if ($use == 'literal') {
 608                              $type_str = '';
 609                          } else if (isset($type) && isset($type_prefix)) {
 610                              $type_str = " xsi:type=\"$type_prefix:$type\"";
 611                          } else {
 612                              $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
 613                          }
 614                      // empty array

 615                      } else {
 616                          if ($use == 'literal') {
 617                              $type_str = '';
 618                          } else if (isset($type) && isset($type_prefix)) {
 619                              $type_str = " xsi:type=\"$type_prefix:$type\"";
 620                          } else {
 621                              $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
 622                          }
 623                      }
 624                      // TODO: for array in literal, there is no wrapper here

 625                      $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
 626                  } else {
 627                      // got a struct

 628                         $this->debug("serialize_val: serialize struct");
 629                      if(isset($type) && isset($type_prefix)){
 630                          $type_str = " xsi:type=\"$type_prefix:$type\"";
 631                      } else {
 632                          $type_str = '';
 633                      }
 634                      if ($use == 'literal') {
 635                          $xml .= "<$name$xmlns$atts>";
 636                      } else {
 637                          $xml .= "<$name$xmlns$type_str$atts>";
 638                      }
 639                      foreach($val as $k => $v){
 640                          // Apache Map

 641                          if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
 642                              $xml .= '<item>';
 643                              $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
 644                              $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
 645                              $xml .= '</item>';
 646                          } else {
 647                              $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
 648                          }
 649                      }
 650                      $xml .= "</$name>";
 651                  }
 652                  break;
 653              default:
 654                     $this->debug("serialize_val: serialize unknown");
 655                  $xml .= 'not detected, got '.gettype($val).' for '.$val;
 656                  break;
 657          }
 658          $this->debug("serialize_val returning $xml");
 659          return $xml;
 660      }
 661  
 662      /**

 663      * serializes a message

 664      *

 665      * @param string $body the XML of the SOAP body

 666      * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array

 667      * @param array $namespaces optional the namespaces used in generating the body and headers

 668      * @param string $style optional (rpc|document)

 669      * @param string $use optional (encoded|literal)

 670      * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)

 671      * @return string the message

 672      * @access public

 673      */
 674      function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
 675      // TODO: add an option to automatically run utf8_encode on $body and $headers

 676      // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows

 677      // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1

 678  
 679      $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
 680      $this->debug("headers:");
 681      $this->appendDebug($this->varDump($headers));
 682      $this->debug("namespaces:");
 683      $this->appendDebug($this->varDump($namespaces));
 684  
 685      // serialize namespaces

 686      $ns_string = '';
 687      foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
 688          $ns_string .= " xmlns:$k=\"$v\"";
 689      }
 690      if($encodingStyle) {
 691          $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
 692      }
 693  
 694      // serialize headers

 695      if($headers){
 696          if (is_array($headers)) {
 697              $xml = '';
 698              foreach ($headers as $k => $v) {
 699                  if (is_object($v) && get_class($v) == 'soapval') {
 700                      $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
 701                  } else {
 702                      $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
 703                  }
 704              }
 705              $headers = $xml;
 706              $this->debug("In serializeEnvelope, serialized array of headers to $headers");
 707          }
 708          $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
 709      }
 710      // serialize envelope

 711      return
 712      '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
 713      '<SOAP-ENV:Envelope'.$ns_string.">".
 714      $headers.
 715      "<SOAP-ENV:Body>".
 716          $body.
 717      "</SOAP-ENV:Body>".
 718      "</SOAP-ENV:Envelope>";
 719      }
 720  
 721      /**

 722       * formats a string to be inserted into an HTML stream

 723       *

 724       * @param string $str The string to format

 725       * @return string The formatted string

 726       * @access public

 727       * @deprecated

 728       */
 729      function formatDump($str){
 730          $str = htmlspecialchars($str);
 731          return nl2br($str);
 732      }
 733  
 734      /**

 735      * contracts (changes namespace to prefix) a qualified name

 736      *

 737      * @param    string $qname qname

 738      * @return    string contracted qname

 739      * @access   private

 740      */
 741  	function contractQname($qname){
 742          // get element namespace

 743          //$this->xdebug("Contract $qname");

 744          if (strrpos($qname, ':')) {
 745              // get unqualified name

 746              $name = substr($qname, strrpos($qname, ':') + 1);
 747              // get ns

 748              $ns = substr($qname, 0, strrpos($qname, ':'));
 749              $p = $this->getPrefixFromNamespace($ns);
 750              if ($p) {
 751                  return $p . ':' . $name;
 752              }
 753              return $qname;
 754          } else {
 755              return $qname;
 756          }
 757      }
 758  
 759      /**

 760      * expands (changes prefix to namespace) a qualified name

 761      *

 762      * @param    string $qname qname

 763      * @return    string expanded qname

 764      * @access   private

 765      */
 766  	function expandQname($qname){
 767          // get element prefix

 768          if(strpos($qname,':') && !ereg('^http://',$qname)){
 769              // get unqualified name

 770              $name = substr(strstr($qname,':'),1);
 771              // get ns prefix

 772              $prefix = substr($qname,0,strpos($qname,':'));
 773              if(isset($this->namespaces[$prefix])){
 774                  return $this->namespaces[$prefix].':'.$name;
 775              } else {
 776                  return $qname;
 777              }
 778          } else {
 779              return $qname;
 780          }
 781      }
 782  
 783      /**

 784      * returns the local part of a prefixed string

 785      * returns the original string, if not prefixed

 786      *

 787      * @param string $str The prefixed string

 788      * @return string The local part

 789      * @access public

 790      */
 791  	function getLocalPart($str){
 792          if($sstr = strrchr($str,':')){
 793              // get unqualified name

 794              return substr( $sstr, 1 );
 795          } else {
 796              return $str;
 797          }
 798      }
 799  
 800      /**

 801      * returns the prefix part of a prefixed string

 802      * returns false, if not prefixed

 803      *

 804      * @param string $str The prefixed string

 805      * @return mixed The prefix or false if there is no prefix

 806      * @access public

 807      */
 808  	function getPrefix($str){
 809          if($pos = strrpos($str,':')){
 810              // get prefix

 811              return substr($str,0,$pos);
 812          }
 813          return false;
 814      }
 815  
 816      /**

 817      * pass it a prefix, it returns a namespace

 818      *

 819      * @param string $prefix The prefix

 820      * @return mixed The namespace, false if no namespace has the specified prefix

 821      * @access public

 822      */
 823  	function getNamespaceFromPrefix($prefix){
 824          if (isset($this->namespaces[$prefix])) {
 825              return $this->namespaces[$prefix];
 826          }
 827          //$this->setError("No namespace registered for prefix '$prefix'");

 828          return false;
 829      }
 830  
 831      /**

 832      * returns the prefix for a given namespace (or prefix)

 833      * or false if no prefixes registered for the given namespace

 834      *

 835      * @param string $ns The namespace

 836      * @return mixed The prefix, false if the namespace has no prefixes

 837      * @access public

 838      */
 839  	function getPrefixFromNamespace($ns) {
 840          foreach ($this->namespaces as $p => $n) {
 841              if ($ns == $n || $ns == $p) {
 842                  $this->usedNamespaces[$p] = $n;
 843                  return $p;
 844              }
 845          }
 846          return false;
 847      }
 848  
 849      /**

 850      * returns the time in ODBC canonical form with microseconds

 851      *

 852      * @return string The time in ODBC canonical form with microseconds

 853      * @access public

 854      */
 855  	function getmicrotime() {
 856          if (function_exists('gettimeofday')) {
 857              $tod = gettimeofday();
 858              $sec = $tod['sec'];
 859              $usec = $tod['usec'];
 860          } else {
 861              $sec = time();
 862              $usec = 0;
 863          }
 864          return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
 865      }
 866  
 867      /**

 868       * Returns a string with the output of var_dump

 869       *

 870       * @param mixed $data The variable to var_dump

 871       * @return string The output of var_dump

 872       * @access public

 873       */
 874      function varDump($data) {
 875          ob_start();
 876          var_dump($data);
 877          $ret_val = ob_get_contents();
 878          ob_end_clean();
 879          return $ret_val;
 880      }
 881  
 882      /**

 883      * represents the object as a string

 884      *

 885      * @return    string

 886      * @access   public

 887      */
 888  	function __toString() {
 889          return $this->varDump($this);
 890      }
 891  }
 892  
 893  // XML Schema Datatype Helper Functions

 894  
 895  //xsd:dateTime helpers

 896  
 897  /**

 898  * convert unix timestamp to ISO 8601 compliant date string

 899  *

 900  * @param    string $timestamp Unix time stamp

 901  * @param    boolean $utc Whether the time stamp is UTC or local

 902  * @access   public

 903  */
 904  function timestamp_to_iso8601($timestamp,$utc=true){
 905      $datestr = date('Y-m-d\TH:i:sO',$timestamp);
 906      if($utc){
 907          $eregStr =
 908          '([0-9]{4})-'.    // centuries & years CCYY-
 909          '([0-9]{2})-'.    // months MM-
 910          '([0-9]{2})'.    // days DD
 911          'T'.            // separator T
 912          '([0-9]{2}):'.    // hours hh:
 913          '([0-9]{2}):'.    // minutes mm:
 914          '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
 915          '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's

 916  
 917          if(ereg($eregStr,$datestr,$regs)){
 918              return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
 919          }
 920          return false;
 921      } else {
 922          return $datestr;
 923      }
 924  }
 925  
 926  /**

 927  * convert ISO 8601 compliant date string to unix timestamp

 928  *

 929  * @param    string $datestr ISO 8601 compliant date string

 930  * @access   public

 931  */
 932  function iso8601_to_timestamp($datestr){
 933      $eregStr =
 934      '([0-9]{4})-'.    // centuries & years CCYY-
 935      '([0-9]{2})-'.    // months MM-
 936      '([0-9]{2})'.    // days DD
 937      'T'.            // separator T
 938      '([0-9]{2}):'.    // hours hh:
 939      '([0-9]{2}):'.    // minutes mm:
 940      '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
 941      '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's

 942      if(ereg($eregStr,$datestr,$regs)){
 943          // not utc

 944          if($regs[8] != 'Z'){
 945              $op = substr($regs[8],0,1);
 946              $h = substr($regs[8],1,2);
 947              $m = substr($regs[8],strlen($regs[8])-2,2);
 948              if($op == '-'){
 949                  $regs[4] = $regs[4] + $h;
 950                  $regs[5] = $regs[5] + $m;
 951              } elseif($op == '+'){
 952                  $regs[4] = $regs[4] - $h;
 953                  $regs[5] = $regs[5] - $m;
 954              }
 955          }
 956          return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
 957  //        return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");

 958      } else {
 959          return false;
 960      }
 961  }
 962  
 963  /**

 964  * sleeps some number of microseconds

 965  *

 966  * @param    string $usec the number of microseconds to sleep

 967  * @access   public

 968  * @deprecated

 969  */
 970  function usleepWindows($usec)
 971  {
 972      $start = gettimeofday();
 973      
 974      do
 975      {
 976          $stop = gettimeofday();
 977          $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
 978          + $stop['usec'] - $start['usec'];
 979      }
 980      while ($timePassed < $usec);
 981  }
 982  
 983  ?><?php
 984  
 985  
 986  
 987  /**

 988  * Contains information for a SOAP fault.

 989  * Mainly used for returning faults from deployed functions

 990  * in a server instance.

 991  * @author   Dietrich Ayala <dietrich@ganx4.com>

 992  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

 993  * @access public

 994  */
 995  class nusoap_fault extends nusoap_base {
 996      /**

 997       * The fault code (client|server)

 998       * @var string

 999       * @access private

1000       */
1001      var $faultcode;
1002      /**

1003       * The fault actor

1004       * @var string

1005       * @access private

1006       */
1007      var $faultactor;
1008      /**

1009       * The fault string, a description of the fault

1010       * @var string

1011       * @access private

1012       */
1013      var $faultstring;
1014      /**

1015       * The fault detail, typically a string or array of string

1016       * @var mixed

1017       * @access private

1018       */
1019      var $faultdetail;
1020  
1021      /**

1022      * constructor

1023      *

1024      * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)

1025      * @param string $faultactor only used when msg routed between multiple actors

1026      * @param string $faultstring human readable error message

1027      * @param mixed $faultdetail detail, typically a string or array of string

1028      */
1029  	function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
1030          parent::nusoap_base();
1031          $this->faultcode = $faultcode;
1032          $this->faultactor = $faultactor;
1033          $this->faultstring = $faultstring;
1034          $this->faultdetail = $faultdetail;
1035      }
1036  
1037      /**

1038      * serialize a fault

1039      *

1040      * @return    string    The serialization of the fault instance.

1041      * @access   public

1042      */
1043  	function serialize(){
1044          $ns_string = '';
1045          foreach($this->namespaces as $k => $v){
1046              $ns_string .= "\n  xmlns:$k=\"$v\"";
1047          }
1048          $return_msg =
1049              '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1050              '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1051                  '<SOAP-ENV:Body>'.
1052                  '<SOAP-ENV:Fault>'.
1053                      $this->serialize_val($this->faultcode, 'faultcode').
1054                      $this->serialize_val($this->faultactor, 'faultactor').
1055                      $this->serialize_val($this->faultstring, 'faultstring').
1056                      $this->serialize_val($this->faultdetail, 'detail').
1057                  '</SOAP-ENV:Fault>'.
1058                  '</SOAP-ENV:Body>'.
1059              '</SOAP-ENV:Envelope>';
1060          return $return_msg;
1061      }
1062  }
1063  
1064  /**

1065   * Backward compatibility

1066   */
1067  class soap_fault extends nusoap_fault {
1068  }
1069  
1070  ?><?php
1071  
1072  
1073  
1074  /**

1075  * parses an XML Schema, allows access to it's data, other utility methods.

1076  * imperfect, no validation... yet, but quite functional.

1077  *

1078  * @author   Dietrich Ayala <dietrich@ganx4.com>

1079  * @author   Scott Nichol <snichol@users.sourceforge.net>

1080  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

1081  * @access   public

1082  */
1083  class nusoap_xmlschema extends nusoap_base  {
1084      
1085      // files

1086      var $schema = '';
1087      var $xml = '';
1088      // namespaces

1089      var $enclosingNamespaces;
1090      // schema info

1091      var $schemaInfo = array();
1092      var $schemaTargetNamespace = '';
1093      // types, elements, attributes defined by the schema

1094      var $attributes = array();
1095      var $complexTypes = array();
1096      var $complexTypeStack = array();
1097      var $currentComplexType = null;
1098      var $elements = array();
1099      var $elementStack = array();
1100      var $currentElement = null;
1101      var $simpleTypes = array();
1102      var $simpleTypeStack = array();
1103      var $currentSimpleType = null;
1104      // imports

1105      var $imports = array();
1106      // parser vars

1107      var $parser;
1108      var $position = 0;
1109      var $depth = 0;
1110      var $depth_array = array();
1111      var $message = array();
1112      var $defaultNamespace = array();
1113      
1114      /**

1115      * constructor

1116      *

1117      * @param    string $schema schema document URI

1118      * @param    string $xml xml document URI

1119      * @param    string $namespaces namespaces defined in enclosing XML

1120      * @access   public

1121      */
1122  	function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
1123          parent::nusoap_base();
1124          $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1125          // files

1126          $this->schema = $schema;
1127          $this->xml = $xml;
1128  
1129          // namespaces

1130          $this->enclosingNamespaces = $namespaces;
1131          $this->namespaces = array_merge($this->namespaces, $namespaces);
1132  
1133          // parse schema file

1134          if($schema != ''){
1135              $this->debug('initial schema file: '.$schema);
1136              $this->parseFile($schema, 'schema');
1137          }
1138  
1139          // parse xml file

1140          if($xml != ''){
1141              $this->debug('initial xml file: '.$xml);
1142              $this->parseFile($xml, 'xml');
1143          }
1144  
1145      }
1146  
1147      /**

1148      * parse an XML file

1149      *

1150      * @param string $xml path/URL to XML file

1151      * @param string $type (schema | xml)

1152      * @return boolean

1153      * @access public

1154      */
1155  	function parseFile($xml,$type){
1156          // parse xml file

1157          if($xml != ""){
1158              $xmlStr = @join("",@file($xml));
1159              if($xmlStr == ""){
1160                  $msg = 'Error reading XML from '.$xml;
1161                  $this->setError($msg);
1162                  $this->debug($msg);
1163              return false;
1164              } else {
1165                  $this->debug("parsing $xml");
1166                  $this->parseString($xmlStr,$type);
1167                  $this->debug("done parsing $xml");
1168              return true;
1169              }
1170          }
1171          return false;
1172      }
1173  
1174      /**

1175      * parse an XML string

1176      *

1177      * @param    string $xml path or URL

1178      * @param    string $type (schema|xml)

1179      * @access   private

1180      */
1181  	function parseString($xml,$type){
1182          // parse xml string

1183          if($xml != ""){
1184  
1185              // Create an XML parser.

1186              $this->parser = xml_parser_create();
1187              // Set the options for parsing the XML data.

1188              xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1189  
1190              // Set the object for the parser.

1191              xml_set_object($this->parser, $this);
1192  
1193              // Set the element handlers for the parser.

1194              if($type == "schema"){
1195                  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1196                  xml_set_character_data_handler($this->parser,'schemaCharacterData');
1197              } elseif($type == "xml"){
1198                  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1199                  xml_set_character_data_handler($this->parser,'xmlCharacterData');
1200              }
1201  
1202              // Parse the XML file.

1203              if(!xml_parse($this->parser,$xml,true)){
1204              // Display an error message.

1205                  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1206                  xml_get_current_line_number($this->parser),
1207                  xml_error_string(xml_get_error_code($this->parser))
1208                  );
1209                  $this->debug($errstr);
1210                  $this->debug("XML payload:\n" . $xml);
1211                  $this->setError($errstr);
1212              }
1213              
1214              xml_parser_free($this->parser);
1215          } else{
1216              $this->debug('no xml passed to parseString()!!');
1217              $this->setError('no xml passed to parseString()!!');
1218          }
1219      }
1220  
1221      /**

1222       * gets a type name for an unnamed type

1223       *

1224       * @param    string    Element name

1225       * @return    string    A type name for an unnamed type

1226       * @access    private

1227       */
1228  	function CreateTypeName($ename) {
1229          $scope = '';
1230          for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1231              $scope .= $this->complexTypeStack[$i] . '_';
1232          }
1233          return $scope . $ename . '_ContainedType';
1234      }
1235      
1236      /**

1237      * start-element handler

1238      *

1239      * @param    string $parser XML parser object

1240      * @param    string $name element name

1241      * @param    string $attrs associative array of attributes

1242      * @access   private

1243      */
1244  	function schemaStartElement($parser, $name, $attrs) {
1245          
1246          // position in the total number of elements, starting from 0

1247          $pos = $this->position++;
1248          $depth = $this->depth++;
1249          // set self as current value for this depth

1250          $this->depth_array[$depth] = $pos;
1251          $this->message[$pos] = array('cdata' => ''); 
1252          if ($depth > 0) {
1253              $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1254          } else {
1255              $this->defaultNamespace[$pos] = false;
1256          }
1257  
1258          // get element prefix

1259          if($prefix = $this->getPrefix($name)){
1260              // get unqualified name

1261              $name = $this->getLocalPart($name);
1262          } else {
1263              $prefix = '';
1264          }
1265          
1266          // loop thru attributes, expanding, and registering namespace declarations

1267          if(count($attrs) > 0){
1268              foreach($attrs as $k => $v){
1269                  // if ns declarations, add to class level array of valid namespaces

1270                  if(ereg("^xmlns",$k)){
1271                      //$this->xdebug("$k: $v");

1272                      //$this->xdebug('ns_prefix: '.$this->getPrefix($k));

1273                      if($ns_prefix = substr(strrchr($k,':'),1)){
1274                          //$this->xdebug("Add namespace[$ns_prefix] = $v");

1275                          $this->namespaces[$ns_prefix] = $v;
1276                      } else {
1277                          $this->defaultNamespace[$pos] = $v;
1278                          if (! $this->getPrefixFromNamespace($v)) {
1279                              $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1280                          }
1281                      }
1282                      if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1283                          $this->XMLSchemaVersion = $v;
1284                          $this->namespaces['xsi'] = $v.'-instance';
1285                      }
1286                  }
1287              }
1288              foreach($attrs as $k => $v){
1289                  // expand each attribute

1290                  $k = strpos($k,':') ? $this->expandQname($k) : $k;
1291                  $v = strpos($v,':') ? $this->expandQname($v) : $v;
1292                  $eAttrs[$k] = $v;
1293              }
1294              $attrs = $eAttrs;
1295          } else {
1296              $attrs = array();
1297          }
1298          // find status, register data

1299          switch($name){
1300              case 'all':            // (optional) compositor content for a complexType
1301              case 'choice':
1302              case 'group':
1303              case 'sequence':
1304                  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");

1305                  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1306                  //if($name == 'all' || $name == 'sequence'){

1307                  //    $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';

1308                  //}

1309              break;
1310              case 'attribute':    // complexType attribute
1311                  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);

1312                  $this->xdebug("parsing attribute:");
1313                  $this->appendDebug($this->varDump($attrs));
1314                  if (!isset($attrs['form'])) {
1315                      $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1316                  }
1317                  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1318                      $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1319                      if (!strpos($v, ':')) {
1320                          // no namespace in arrayType attribute value...

1321                          if ($this->defaultNamespace[$pos]) {
1322                              // ...so use the default

1323                              $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1324                          }
1325                      }
1326                  }
1327                  if(isset($attrs['name'])){
1328                      $this->attributes[$attrs['name']] = $attrs;
1329                      $aname = $attrs['name'];
1330                  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1331                      if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1332                          $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1333                      } else {
1334                          $aname = '';
1335                      }
1336                  } elseif(isset($attrs['ref'])){
1337                      $aname = $attrs['ref'];
1338                      $this->attributes[$attrs['ref']] = $attrs;
1339                  }
1340                  
1341                  if($this->currentComplexType){    // This should *always* be
1342                      $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1343                  }
1344                  // arrayType attribute

1345                  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1346                      $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1347                      $prefix = $this->getPrefix($aname);
1348                      if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1349                          $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1350                      } else {
1351                          $v = '';
1352                      }
1353                      if(strpos($v,'[,]')){
1354                          $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1355                      }
1356                      $v = substr($v,0,strpos($v,'[')); // clip the []

1357                      if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1358                          $v = $this->XMLSchemaVersion.':'.$v;
1359                      }
1360                      $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1361                  }
1362              break;
1363              case 'complexContent':    // (optional) content for a complexType
1364              break;
1365              case 'complexType':
1366                  array_push($this->complexTypeStack, $this->currentComplexType);
1367                  if(isset($attrs['name'])){
1368                      // TODO: what is the scope of named complexTypes that appear

1369                      //       nested within other c complexTypes?

1370                      $this->xdebug('processing named complexType '.$attrs['name']);
1371                      //$this->currentElement = false;

1372                      $this->currentComplexType = $attrs['name'];
1373                      $this->complexTypes[$this->currentComplexType] = $attrs;
1374                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1375                      // This is for constructs like

1376                      //           <complexType name="ListOfString" base="soap:Array">

1377                      //                <sequence>

1378                      //                    <element name="string" type="xsd:string"

1379                      //                        minOccurs="0" maxOccurs="unbounded" />

1380                      //                </sequence>

1381                      //            </complexType>

1382                      if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1383                          $this->xdebug('complexType is unusual array');
1384                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1385                      } else {
1386                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1387                      }
1388                  } else {
1389                      $name = $this->CreateTypeName($this->currentElement);
1390                      $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1391                      $this->currentComplexType = $name;
1392                      //$this->currentElement = false;

1393                      $this->complexTypes[$this->currentComplexType] = $attrs;
1394                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1395                      // This is for constructs like

1396                      //           <complexType name="ListOfString" base="soap:Array">

1397                      //                <sequence>

1398                      //                    <element name="string" type="xsd:string"

1399                      //                        minOccurs="0" maxOccurs="unbounded" />

1400                      //                </sequence>

1401                      //            </complexType>

1402                      if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1403                          $this->xdebug('complexType is unusual array');
1404                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1405                      } else {
1406                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1407                      }
1408                  }
1409              break;
1410              case 'element':
1411                  array_push($this->elementStack, $this->currentElement);
1412                  if (!isset($attrs['form'])) {
1413                      $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1414                  }
1415                  if(isset($attrs['type'])){
1416                      $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1417                      if (! $this->getPrefix($attrs['type'])) {
1418                          if ($this->defaultNamespace[$pos]) {
1419                              $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1420                              $this->xdebug('used default namespace to make type ' . $attrs['type']);
1421                          }
1422                      }
1423                      // This is for constructs like

1424                      //           <complexType name="ListOfString" base="soap:Array">

1425                      //                <sequence>

1426                      //                    <element name="string" type="xsd:string"

1427                      //                        minOccurs="0" maxOccurs="unbounded" />

1428                      //                </sequence>

1429                      //            </complexType>

1430                      if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1431                          $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1432                          $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1433                      }
1434                      $this->currentElement = $attrs['name'];
1435                      $ename = $attrs['name'];
1436                  } elseif(isset($attrs['ref'])){
1437                      $this->xdebug("processing element as ref to ".$attrs['ref']);
1438                      $this->currentElement = "ref to ".$attrs['ref'];
1439                      $ename = $this->getLocalPart($attrs['ref']);
1440                  } else {
1441                      $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1442                      $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
1443                      $this->currentElement = $attrs['name'];
1444                      $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
1445                      $ename = $attrs['name'];
1446                  }
1447                  if (isset($ename) && $this->currentComplexType) {
1448                      $this->xdebug("add element $ename to complexType $this->currentComplexType");
1449                      $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1450                  } elseif (!isset($attrs['ref'])) {
1451                      $this->xdebug("add element $ename to elements array");
1452                      $this->elements[ $attrs['name'] ] = $attrs;
1453                      $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1454                  }
1455              break;
1456              case 'enumeration':    //    restriction value list member
1457                  $this->xdebug('enumeration ' . $attrs['value']);
1458                  if ($this->currentSimpleType) {
1459                      $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1460                  } elseif ($this->currentComplexType) {
1461                      $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1462                  }
1463              break;
1464              case 'extension':    // simpleContent or complexContent type extension
1465                  $this->xdebug('extension ' . $attrs['base']);
1466                  if ($this->currentComplexType) {
1467                      $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1468                  }
1469              break;
1470              case 'import':
1471                  if (isset($attrs['schemaLocation'])) {
1472                      //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);

1473                      $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1474                  } else {
1475                      //$this->xdebug('import namespace ' . $attrs['namespace']);

1476                      $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1477                      if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1478                          $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1479                      }
1480                  }
1481              break;
1482              case 'list':    // simpleType value list
1483              break;
1484              case 'restriction':    // simpleType, simpleContent or complexContent value restriction
1485                  $this->xdebug('restriction ' . $attrs['base']);
1486                  if($this->currentSimpleType){
1487                      $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1488                  } elseif($this->currentComplexType){
1489                      $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1490                      if(strstr($attrs['base'],':') == ':Array'){
1491                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1492                      }
1493                  }
1494              break;
1495              case 'schema':
1496                  $this->schemaInfo = $attrs;
1497                  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1498                  if (isset($attrs['targetNamespace'])) {
1499                      $this->schemaTargetNamespace = $attrs['targetNamespace'];
1500                  }
1501                  if (!isset($attrs['elementFormDefault'])) {
1502                      $this->schemaInfo['elementFormDefault'] = 'unqualified';
1503                  }
1504                  if (!isset($attrs['attributeFormDefault'])) {
1505                      $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1506                  }
1507              break;
1508              case 'simpleContent':    // (optional) content for a complexType
1509              break;
1510              case 'simpleType':
1511                  array_push($this->simpleTypeStack, $this->currentSimpleType);
1512                  if(isset($attrs['name'])){
1513                      $this->xdebug("processing simpleType for name " . $attrs['name']);
1514                      $this->currentSimpleType = $attrs['name'];
1515                      $this->simpleTypes[ $attrs['name'] ] = $attrs;
1516                      $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1517                      $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1518                  } else {
1519                      $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1520                      $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1521                      $this->currentSimpleType = $name;
1522                      //$this->currentElement = false;

1523                      $this->simpleTypes[$this->currentSimpleType] = $attrs;
1524                      $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1525                  }
1526              break;
1527              case 'union':    // simpleType type list
1528              break;
1529              default:
1530                  //$this->xdebug("do not have anything to do for element $name");

1531          }
1532      }
1533  
1534      /**

1535      * end-element handler

1536      *

1537      * @param    string $parser XML parser object

1538      * @param    string $name element name

1539      * @access   private

1540      */
1541  	function schemaEndElement($parser, $name) {
1542          // bring depth down a notch

1543          $this->depth--;
1544          // position of current element is equal to the last value left in depth_array for my depth

1545          if(isset($this->depth_array[$this->depth])){
1546              $pos = $this->depth_array[$this->depth];
1547          }
1548          // get element prefix

1549          if ($prefix = $this->getPrefix($name)){
1550              // get unqualified name

1551              $name = $this->getLocalPart($name);
1552          } else {
1553              $prefix = '';
1554          }
1555          // move on...

1556          if($name == 'complexType'){
1557              $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1558              $this->currentComplexType = array_pop($this->complexTypeStack);
1559              //$this->currentElement = false;

1560          }
1561          if($name == 'element'){
1562              $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1563              $this->currentElement = array_pop($this->elementStack);
1564          }
1565          if($name == 'simpleType'){
1566              $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1567              $this->currentSimpleType = array_pop($this->simpleTypeStack);
1568          }
1569      }
1570  
1571      /**

1572      * element content handler

1573      *

1574      * @param    string $parser XML parser object

1575      * @param    string $data element content

1576      * @access   private

1577      */
1578  	function schemaCharacterData($parser, $data){
1579          $pos = $this->depth_array[$this->depth - 1];
1580          $this->message[$pos]['cdata'] .= $data;
1581      }
1582  
1583      /**

1584      * serialize the schema

1585      *

1586      * @access   public

1587      */
1588  	function serializeSchema(){
1589  
1590          $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1591          $xml = '';
1592          // imports

1593          if (sizeof($this->imports) > 0) {
1594              foreach($this->imports as $ns => $list) {
1595                  foreach ($list as $ii) {
1596                      if ($ii['location'] != '') {
1597                          $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1598                      } else {
1599                          $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1600                      }
1601                  }
1602              } 
1603          } 
1604          // complex types

1605          foreach($this->complexTypes as $typeName => $attrs){
1606              $contentStr = '';
1607              // serialize child elements

1608              if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1609                  foreach($attrs['elements'] as $element => $eParts){
1610                      if(isset($eParts['ref'])){
1611                          $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
1612                      } else {
1613                          $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1614                          foreach ($eParts as $aName => $aValue) {
1615                              // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable

1616                              if ($aName != 'name' && $aName != 'type') {
1617                                  $contentStr .= " $aName=\"$aValue\"";
1618                              }
1619                          }
1620                          $contentStr .= "/>\n";
1621                      }
1622                  }
1623                  // compositor wraps elements

1624                  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1625                      $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
1626                  }
1627              }
1628              // attributes

1629              if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1630                  foreach($attrs['attrs'] as $attr => $aParts){
1631                      $contentStr .= "    <$schemaPrefix:attribute";
1632                      foreach ($aParts as $a => $v) {
1633                          if ($a == 'ref' || $a == 'type') {
1634                              $contentStr .= " $a=\"".$this->contractQName($v).'"';
1635                          } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1636                              $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1637                              $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1638                          } else {
1639                              $contentStr .= " $a=\"$v\"";
1640                          }
1641                      }
1642                      $contentStr .= "/>\n";
1643                  }
1644              }
1645              // if restriction

1646              if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1647                  $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
1648                  // complex or simple content

1649                  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1650                      $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
1651                  }
1652              }
1653              // finalize complex type

1654              if($contentStr != ''){
1655                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1656              } else {
1657                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1658              }
1659              $xml .= $contentStr;
1660          }
1661          // simple types

1662          if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1663              foreach($this->simpleTypes as $typeName => $eParts){
1664                  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
1665                  if (isset($eParts['enumeration'])) {
1666                      foreach ($eParts['enumeration'] as $e) {
1667                          $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
1668                      }
1669                  }
1670                  $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1671              }
1672          }
1673          // elements

1674          if(isset($this->elements) && count($this->elements) > 0){
1675              foreach($this->elements as $element => $eParts){
1676                  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1677              }
1678          }
1679          // attributes

1680          if(isset($this->attributes) && count($this->attributes) > 0){
1681              foreach($this->attributes as $attr => $aParts){
1682                  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1683              }
1684          }
1685          // finish 'er up

1686          $attr = '';
1687          foreach ($this->schemaInfo as $k => $v) {
1688              if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
1689                  $attr .= " $k=\"$v\"";
1690              }
1691          }
1692          $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1693          foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1694              $el .= " xmlns:$nsp=\"$ns\"";
1695          }
1696          $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1697          return $xml;
1698      }
1699  
1700      /**

1701      * adds debug data to the clas level debug string

1702      *

1703      * @param    string $string debug data

1704      * @access   private

1705      */
1706  	function xdebug($string){
1707          $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1708      }
1709  
1710      /**

1711      * get the PHP type of a user defined type in the schema

1712      * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays

1713      * returns false if no type exists, or not w/ the given namespace

1714      * else returns a string that is either a native php type, or 'struct'

1715      *

1716      * @param string $type name of defined type

1717      * @param string $ns namespace of type

1718      * @return mixed

1719      * @access public

1720      * @deprecated

1721      */
1722  	function getPHPType($type,$ns){
1723          if(isset($this->typemap[$ns][$type])){
1724              //print "found type '$type' and ns $ns in typemap<br>";

1725              return $this->typemap[$ns][$type];
1726          } elseif(isset($this->complexTypes[$type])){
1727              //print "getting type '$type' and ns $ns from complexTypes array<br>";

1728              return $this->complexTypes[$type]['phpType'];
1729          }
1730          return false;
1731      }
1732  
1733      /**

1734      * returns an associative array of information about a given type

1735      * returns false if no type exists by the given name

1736      *

1737      *    For a complexType typeDef = array(

1738      *    'restrictionBase' => '',

1739      *    'phpType' => '',

1740      *    'compositor' => '(sequence|all)',

1741      *    'elements' => array(), // refs to elements array

1742      *    'attrs' => array() // refs to attributes array

1743      *    ... and so on (see addComplexType)

1744      *    )

1745      *

1746      *   For simpleType or element, the array has different keys.

1747      *

1748      * @param string $type

1749      * @return mixed

1750      * @access public

1751      * @see addComplexType

1752      * @see addSimpleType

1753      * @see addElement

1754      */
1755  	function getTypeDef($type){
1756          //$this->debug("in getTypeDef for type $type");

1757          if (substr($type, -1) == '^') {
1758              $is_element = 1;
1759              $type = substr($type, 0, -1);
1760          } else {
1761              $is_element = 0;
1762          }
1763  
1764          if((! $is_element) && isset($this->complexTypes[$type])){
1765              $this->xdebug("in getTypeDef, found complexType $type");
1766              return $this->complexTypes[$type];
1767          } elseif((! $is_element) && isset($this->simpleTypes[$type])){
1768              $this->xdebug("in getTypeDef, found simpleType $type");
1769              if (!isset($this->simpleTypes[$type]['phpType'])) {
1770                  // get info for type to tack onto the simple type

1771                  // TODO: can this ever really apply (i.e. what is a simpleType really?)

1772                  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1773                  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1774                  $etype = $this->getTypeDef($uqType);
1775                  if ($etype) {
1776                      $this->xdebug("in getTypeDef, found type for simpleType $type:");
1777                      $this->xdebug($this->varDump($etype));
1778                      if (isset($etype['phpType'])) {
1779                          $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1780                      }
1781                      if (isset($etype['elements'])) {
1782                          $this->simpleTypes[$type]['elements'] = $etype['elements'];
1783                      }
1784                  }
1785              }
1786              return $this->simpleTypes[$type];
1787          } elseif(isset($this->elements[$type])){
1788              $this->xdebug("in getTypeDef, found element $type");
1789              if (!isset($this->elements[$type]['phpType'])) {
1790                  // get info for type to tack onto the element

1791                  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1792                  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1793                  $etype = $this->getTypeDef($uqType);
1794                  if ($etype) {
1795                      $this->xdebug("in getTypeDef, found type for element $type:");
1796                      $this->xdebug($this->varDump($etype));
1797                      if (isset($etype['phpType'])) {
1798                          $this->elements[$type]['phpType'] = $etype['phpType'];
1799                      }
1800                      if (isset($etype['elements'])) {
1801                          $this->elements[$type]['elements'] = $etype['elements'];
1802                      }
1803                  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1804                      $this->xdebug("in getTypeDef, element $type is an XSD type");
1805                      $this->elements[$type]['phpType'] = 'scalar';
1806                  }
1807              }
1808              return $this->elements[$type];
1809          } elseif(isset($this->attributes[$type])){
1810              $this->xdebug("in getTypeDef, found attribute $type");
1811              return $this->attributes[$type];
1812          } elseif (ereg('_ContainedType$', $type)) {
1813              $this->xdebug("in getTypeDef, have an untyped element $type");
1814              $typeDef['typeClass'] = 'simpleType';
1815              $typeDef['phpType'] = 'scalar';
1816              $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1817              return $typeDef;
1818          }
1819          $this->xdebug("in getTypeDef, did not find $type");
1820          return false;
1821      }
1822  
1823      /**

1824      * returns a sample serialization of a given type, or false if no type by the given name

1825      *

1826      * @param string $type name of type

1827      * @return mixed

1828      * @access public

1829      * @deprecated

1830      */
1831      function serializeTypeDef($type){
1832          //print "in sTD() for type $type<br>";

1833      if($typeDef = $this->getTypeDef($type)){
1834          $str .= '<'.$type;
1835          if(is_array($typeDef['attrs'])){
1836          foreach($typeDef['attrs'] as $attName => $data){
1837              $str .= " $attName=\"{type = ".$data['type']."}\"";
1838          }
1839          }
1840          $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1841          if(count($typeDef['elements']) > 0){
1842          $str .= ">";
1843          foreach($typeDef['elements'] as $element => $eData){
1844              $str .= $this->serializeTypeDef($element);
1845          }
1846          $str .= "</$type>";
1847          } elseif($typeDef['typeClass'] == 'element') {
1848          $str .= "></$type>";
1849          } else {
1850          $str .= "/>";
1851          }
1852              return $str;
1853      }
1854          return false;
1855      }
1856  
1857      /**

1858      * returns HTML form elements that allow a user

1859      * to enter values for creating an instance of the given type.

1860      *

1861      * @param string $name name for type instance

1862      * @param string $type name of type

1863      * @return string

1864      * @access public

1865      * @deprecated

1866      */
1867  	function typeToForm($name,$type){
1868          // get typedef

1869          if($typeDef = $this->getTypeDef($type)){
1870              // if struct

1871              if($typeDef['phpType'] == 'struct'){
1872                  $buffer .= '<table>';
1873                  foreach($typeDef['elements'] as $child => $childDef){
1874                      $buffer .= "
1875                      <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1876                      <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1877                  }
1878                  $buffer .= '</table>';
1879              // if array

1880              } elseif($typeDef['phpType'] == 'array'){
1881                  $buffer .= '<table>';
1882                  for($i=0;$i < 3; $i++){
1883                      $buffer .= "
1884                      <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1885                      <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1886                  }
1887                  $buffer .= '</table>';
1888              // if scalar

1889              } else {
1890                  $buffer .= "<input type='text' name='parameters[$name]'>";
1891              }
1892          } else {
1893              $buffer .= "<input type='text' name='parameters[$name]'>";
1894          }
1895          return $buffer;
1896      }
1897      
1898      /**

1899      * adds a complex type to the schema

1900      * 

1901      * example: array

1902      * 

1903      * addType(

1904      *     'ArrayOfstring',

1905      *     'complexType',

1906      *     'array',

1907      *     '',

1908      *     'SOAP-ENC:Array',

1909      *     array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),

1910      *     'xsd:string'

1911      * );

1912      * 

1913      * example: PHP associative array ( SOAP Struct )

1914      * 

1915      * addType(

1916      *     'SOAPStruct',

1917      *     'complexType',

1918      *     'struct',

1919      *     'all',

1920      *     array('myVar'=> array('name'=>'myVar','type'=>'string')

1921      * );

1922      * 

1923      * @param name

1924      * @param typeClass (complexType|simpleType|attribute)

1925      * @param phpType: currently supported are array and struct (php assoc array)

1926      * @param compositor (all|sequence|choice)

1927      * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)

1928      * @param elements = array ( name = array(name=>'',type=>'') )

1929      * @param attrs = array(

1930      *     array(

1931      *        'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",

1932      *        "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"

1933      *     )

1934      * )

1935      * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)

1936      * @access public

1937      * @see getTypeDef

1938      */
1939  	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1940          $this->complexTypes[$name] = array(
1941          'name'        => $name,
1942          'typeClass'    => $typeClass,
1943          'phpType'    => $phpType,
1944          'compositor'=> $compositor,
1945          'restrictionBase' => $restrictionBase,
1946          'elements'    => $elements,
1947          'attrs'        => $attrs,
1948          'arrayType'    => $arrayType
1949          );
1950          
1951          $this->xdebug("addComplexType $name:");
1952          $this->appendDebug($this->varDump($this->complexTypes[$name]));
1953      }
1954      
1955      /**

1956      * adds a simple type to the schema

1957      *

1958      * @param string $name

1959      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)

1960      * @param string $typeClass (should always be simpleType)

1961      * @param string $phpType (should always be scalar)

1962      * @param array $enumeration array of values

1963      * @access public

1964      * @see nusoap_xmlschema

1965      * @see getTypeDef

1966      */
1967  	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1968          $this->simpleTypes[$name] = array(
1969          'name'            => $name,
1970          'typeClass'        => $typeClass,
1971          'phpType'        => $phpType,
1972          'type'            => $restrictionBase,
1973          'enumeration'    => $enumeration
1974          );
1975          
1976          $this->xdebug("addSimpleType $name:");
1977          $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1978      }
1979  
1980      /**

1981      * adds an element to the schema

1982      *

1983      * @param array $attrs attributes that must include name and type

1984      * @see nusoap_xmlschema

1985      * @access public

1986      */
1987  	function addElement($attrs) {
1988          if (! $this->getPrefix($attrs['type'])) {
1989              $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
1990          }
1991          $this->elements[ $attrs['name'] ] = $attrs;
1992          $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1993          
1994          $this->xdebug("addElement " . $attrs['name']);
1995          $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
1996      }
1997  }
1998  
1999  /**

2000   * Backward compatibility

2001   */
2002  class XMLSchema extends nusoap_xmlschema {
2003  }
2004  
2005  ?><?php
2006  
2007  
2008  
2009  /**

2010  * For creating serializable abstractions of native PHP types.  This class

2011  * allows element name/namespace, XSD type, and XML attributes to be

2012  * associated with a value.  This is extremely useful when WSDL is not

2013  * used, but is also useful when WSDL is used with polymorphic types, including

2014  * xsd:anyType and user-defined types.

2015  *

2016  * @author   Dietrich Ayala <dietrich@ganx4.com>

2017  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

2018  * @access   public

2019  */
2020  class soapval extends nusoap_base {
2021      /**

2022       * The XML element name

2023       *

2024       * @var string

2025       * @access private

2026       */
2027      var $name;
2028      /**

2029       * The XML type name (string or false)

2030       *

2031       * @var mixed

2032       * @access private

2033       */
2034      var $type;
2035      /**

2036       * The PHP value

2037       *

2038       * @var mixed

2039       * @access private

2040       */
2041      var $value;
2042      /**

2043       * The XML element namespace (string or false)

2044       *

2045       * @var mixed

2046       * @access private

2047       */
2048      var $element_ns;
2049      /**

2050       * The XML type namespace (string or false)

2051       *

2052       * @var mixed

2053       * @access private

2054       */
2055      var $type_ns;
2056      /**

2057       * The XML element attributes (array or false)

2058       *

2059       * @var mixed

2060       * @access private

2061       */
2062      var $attributes;
2063  
2064      /**

2065      * constructor

2066      *

2067      * @param    string $name optional name

2068      * @param    mixed $type optional type name

2069      * @param    mixed $value optional value

2070      * @param    mixed $element_ns optional namespace of value

2071      * @param    mixed $type_ns optional namespace of type

2072      * @param    mixed $attributes associative array of attributes to add to element serialization

2073      * @access   public

2074      */
2075    	function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
2076          parent::nusoap_base();
2077          $this->name = $name;
2078          $this->type = $type;
2079          $this->value = $value;
2080          $this->element_ns = $element_ns;
2081          $this->type_ns = $type_ns;
2082          $this->attributes = $attributes;
2083      }
2084  
2085      /**

2086      * return serialized value

2087      *

2088      * @param    string $use The WSDL use value (encoded|literal)

2089      * @return    string XML data

2090      * @access   public

2091      */
2092  	function serialize($use='encoded') {
2093          return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2094      }
2095  
2096      /**

2097      * decodes a soapval object into a PHP native type

2098      *

2099      * @return    mixed

2100      * @access   public

2101      */
2102  	function decode(){
2103          return $this->value;
2104      }
2105  }
2106  
2107  
2108  
2109  ?><?php
2110  
2111  
2112  
2113  /**

2114  * transport class for sending/receiving data via HTTP and HTTPS

2115  * NOTE: PHP must be compiled with the CURL extension for HTTPS support

2116  *

2117  * @author   Dietrich Ayala <dietrich@ganx4.com>

2118  * @author   Scott Nichol <snichol@users.sourceforge.net>

2119  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

2120  * @access public

2121  */
2122  class soap_transport_http extends nusoap_base {
2123  
2124      var $url = '';
2125      var $uri = '';
2126      var $digest_uri = '';
2127      var $scheme = '';
2128      var $host = '';
2129      var $port = '';
2130      var $path = '';
2131      var $request_method = 'POST';
2132      var $protocol_version = '1.0';
2133      var $encoding = '';
2134      var $outgoing_headers = array();
2135      var $incoming_headers = array();
2136      var $incoming_cookies = array();
2137      var $outgoing_payload = '';
2138      var $incoming_payload = '';
2139      var $response_status_line;    // HTTP response status line

2140      var $useSOAPAction = true;
2141      var $persistentConnection = false;
2142      var $ch = false;    // cURL handle

2143      var $ch_options = array();    // cURL custom options

2144      var $use_curl = false;        // force cURL use

2145      var $proxy = null;            // proxy information (associative array)

2146      var $username = '';
2147      var $password = '';
2148      var $authtype = '';
2149      var $digestRequest = array();
2150      var $certRequest = array();    // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)

2151                                  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'

2152                                  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'

2153                                  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'

2154                                  // passphrase: SSL key password/passphrase

2155                                  // certpassword: SSL certificate password

2156                                  // verifypeer: default is 1

2157                                  // verifyhost: default is 1

2158  
2159      /**

2160      * constructor

2161      *

2162      * @param string $url The URL to which to connect

2163      * @param array $curl_options User-specified cURL options

2164      * @param boolean $use_curl Whether to try to force cURL use

2165      * @access public

2166      */
2167  	function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
2168          parent::nusoap_base();
2169          $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2170          $this->appendDebug($this->varDump($curl_options));
2171          $this->setURL($url);
2172          if (is_array($curl_options)) {
2173              $this->ch_options = $curl_options;
2174          }
2175          $this->use_curl = $use_curl;
2176          ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
2177          $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
2178      }
2179  
2180      /**

2181      * sets a cURL option

2182      *

2183      * @param    mixed $option The cURL option (always integer?)

2184      * @param    mixed $value The cURL option value

2185      * @access   private

2186      */
2187  	function setCurlOption($option, $value) {
2188          $this->debug("setCurlOption option=$option, value=");
2189          $this->appendDebug($this->varDump($value));
2190          curl_setopt($this->ch, $option, $value);
2191      }
2192  
2193      /**

2194      * sets an HTTP header

2195      *

2196      * @param string $name The name of the header

2197      * @param string $value The value of the header

2198      * @access private

2199      */
2200  	function setHeader($name, $value) {
2201          $this->outgoing_headers[$name] = $value;
2202          $this->debug("set header $name: $value");
2203      }
2204  
2205      /**

2206      * unsets an HTTP header

2207      *

2208      * @param string $name The name of the header

2209      * @access private

2210      */
2211  	function unsetHeader($name) {
2212          if (isset($this->outgoing_headers[$name])) {
2213              $this->debug("unset header $name");
2214              unset($this->outgoing_headers[$name]);
2215          }
2216      }
2217  
2218      /**

2219      * sets the URL to which to connect

2220      *

2221      * @param string $url The URL to which to connect

2222      * @access private

2223      */
2224  	function setURL($url) {
2225          $this->url = $url;
2226  
2227          $u = parse_url($url);
2228          foreach($u as $k => $v){
2229              $this->debug("parsed URL $k = $v");
2230              $this->$k = $v;
2231          }
2232          
2233          // add any GET params to path

2234          if(isset($u['query']) && $u['query'] != ''){
2235              $this->path .= '?' . $u['query'];
2236          }
2237          
2238          // set default port

2239          if(!isset($u['port'])){
2240              if($u['scheme'] == 'https'){
2241                  $this->port = 443;
2242              } else {
2243                  $this->port = 80;
2244              }
2245          }
2246          
2247          $this->uri = $this->path;
2248          $this->digest_uri = $this->uri;
2249          
2250          // build headers

2251          if (!isset($u['port'])) {
2252              $this->setHeader('Host', $this->host);
2253          } else {
2254              $this->setHeader('Host', $this->host.':'.$this->port);
2255          }
2256  
2257          if (isset($u['user']) && $u['user'] != '') {
2258              $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2259          }
2260      }
2261  
2262      /**

2263      * gets the I/O method to use

2264      *

2265      * @return    string    I/O method to use (socket|curl|unknown)

2266      * @access    private

2267      */
2268  	function io_method() {
2269          if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
2270              return 'curl';
2271          if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
2272              return 'socket';
2273          return 'unknown';
2274      }
2275  
2276      /**

2277      * establish an HTTP connection

2278      *

2279      * @param    integer $timeout set connection timeout in seconds

2280      * @param    integer $response_timeout set response timeout in seconds

2281      * @return    boolean true if connected, false if not

2282      * @access   private

2283      */
2284  	function connect($connection_timeout=0,$response_timeout=30){
2285            // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like

2286            // "regular" socket.

2287            // TODO: disabled for now because OpenSSL must be *compiled* in (not just

2288            //       loaded), and until PHP5 stream_get_wrappers is not available.

2289  //          if ($this->scheme == 'https') {

2290  //              if (version_compare(phpversion(), '4.3.0') >= 0) {

2291  //                  if (extension_loaded('openssl')) {

2292  //                      $this->scheme = 'ssl';

2293  //                      $this->debug('Using SSL over OpenSSL');

2294  //                  }

2295  //              }

2296  //        }

2297          $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2298        if ($this->io_method() == 'socket') {
2299          if (!is_array($this->proxy)) {
2300              $host = $this->host;
2301              $port = $this->port;
2302          } else {
2303              $host = $this->proxy['host'];
2304              $port = $this->proxy['port'];
2305          }
2306  
2307          // use persistent connection

2308          if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
2309              if (!feof($this->fp)) {
2310                  $this->debug('Re-use persistent connection');
2311                  return true;
2312              }
2313              fclose($this->fp);
2314              $this->debug('Closed persistent connection at EOF');
2315          }
2316  
2317          // munge host if using OpenSSL

2318          if ($this->scheme == 'ssl') {
2319              $host = 'ssl://' . $host;
2320          }
2321          $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2322  
2323          // open socket

2324          if($connection_timeout > 0){
2325              $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2326          } else {
2327              $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
2328          }
2329          
2330          // test pointer

2331          if(!$this->fp) {
2332              $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2333              if ($this->errno) {
2334                  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2335              } else {
2336                  $msg .= ' prior to connect().  This is often a problem looking up the host name.';
2337              }
2338              $this->debug($msg);
2339              $this->setError($msg);
2340              return false;
2341          }
2342          
2343          // set response timeout

2344          $this->debug('set response timeout to ' . $response_timeout);
2345          socket_set_timeout( $this->fp, $response_timeout);
2346  
2347          $this->debug('socket connected');
2348          return true;
2349        } else if ($this->io_method() == 'curl') {
2350          if (!extension_loaded('curl')) {
2351  //            $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');

2352              $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.');
2353              return false;
2354          }
2355          // Avoid warnings when PHP does not have these options

2356          if (defined('CURLOPT_CONNECTIONTIMEOUT'))
2357              $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2358          else
2359              $CURLOPT_CONNECTIONTIMEOUT = 78;
2360          if (defined('CURLOPT_HTTPAUTH'))
2361              $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2362          else
2363              $CURLOPT_HTTPAUTH = 107;
2364          if (defined('CURLOPT_PROXYAUTH'))
2365              $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2366          else
2367              $CURLOPT_PROXYAUTH = 111;
2368          if (defined('CURLAUTH_BASIC'))
2369              $CURLAUTH_BASIC = CURLAUTH_BASIC;
2370          else
2371              $CURLAUTH_BASIC = 1;
2372          if (defined('CURLAUTH_DIGEST'))
2373              $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2374          else
2375              $CURLAUTH_DIGEST = 2;
2376          if (defined('CURLAUTH_NTLM'))
2377              $CURLAUTH_NTLM = CURLAUTH_NTLM;
2378          else
2379              $CURLAUTH_NTLM = 8;
2380  
2381          $this->debug('connect using cURL');
2382          // init CURL

2383          $this->ch = curl_init();
2384          // set url

2385          $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2386          // add path

2387          $hostURL .= $this->path;
2388          $this->setCurlOption(CURLOPT_URL, $hostURL);
2389          // follow location headers (re-directs)

2390          if (ini_get('safe_mode') || ini_get('open_basedir')) {
2391              $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
2392              $this->debug('safe_mode = ');
2393              $this->appendDebug($this->varDump(ini_get('safe_mode')));
2394              $this->debug('open_basedir = ');
2395              $this->appendDebug($this->varDump(ini_get('open_basedir')));
2396          } else {
2397              $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2398          }
2399          // ask for headers in the response output

2400          $this->setCurlOption(CURLOPT_HEADER, 1);
2401          // ask for the response output as the return value

2402          $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2403          // encode

2404          // We manage this ourselves through headers and encoding

2405  //        if(function_exists('gzuncompress')){

2406  //            $this->setCurlOption(CURLOPT_ENCODING, 'deflate');

2407  //        }

2408          // persistent connection

2409          if ($this->persistentConnection) {
2410              // I believe the following comment is now bogus, having applied to

2411              // the code when it used CURLOPT_CUSTOMREQUEST to send the request.

2412              // The way we send data, we cannot use persistent connections, since

2413              // there will be some "junk" at the end of our request.

2414              //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);

2415              $this->persistentConnection = false;
2416              $this->setHeader('Connection', 'close');
2417          }
2418          // set timeouts

2419          if ($connection_timeout != 0) {
2420              $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2421          }
2422          if ($response_timeout != 0) {
2423              $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2424          }
2425  
2426          if ($this->scheme == 'https') {
2427              $this->debug('set cURL SSL verify options');
2428              // recent versions of cURL turn on peer/host checking by default,

2429              // while PHP binaries are not compiled with a default location for the

2430              // CA cert bundle, so disable peer/host checking.

2431              //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');        

2432              $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2433              $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2434      
2435              // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)

2436              if ($this->authtype == 'certificate') {
2437                  $this->debug('set cURL certificate options');
2438                  if (isset($this->certRequest['cainfofile'])) {
2439                      $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2440                  }
2441                  if (isset($this->certRequest['verifypeer'])) {
2442                      $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2443                  } else {
2444                      $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2445                  }
2446                  if (isset($this->certRequest['verifyhost'])) {
2447                      $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2448                  } else {
2449                      $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2450                  }
2451                  if (isset($this->certRequest['sslcertfile'])) {
2452                      $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2453                  }
2454                  if (isset($this->certRequest['sslkeyfile'])) {
2455                      $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2456                  }
2457                  if (isset($this->certRequest['passphrase'])) {
2458                      $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2459                  }
2460                  if (isset($this->certRequest['certpassword'])) {
2461                      $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2462                  }
2463              }
2464          }
2465          if ($this->authtype && ($this->authtype != 'certificate')) {
2466              if ($this->username) {
2467                  $this->debug('set cURL username/password');
2468                  $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2469              }
2470              if ($this->authtype == 'basic') {
2471                  $this->debug('set cURL for Basic authentication');
2472                  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2473              }
2474              if ($this->authtype == 'digest') {
2475                  $this->debug('set cURL for digest authentication');
2476                  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2477              }
2478              if ($this->authtype == 'ntlm') {
2479                  $this->debug('set cURL for NTLM authentication');
2480                  $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2481              }
2482          }
2483          if (is_array($this->proxy)) {
2484              $this->debug('set cURL proxy options');
2485              if ($this->proxy['port'] != '') {
2486                  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
2487              } else {
2488                  $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2489              }
2490              if ($this->proxy['username'] || $this->proxy['password']) {
2491                  $this->debug('set cURL proxy authentication options');
2492                  $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
2493                  if ($this->proxy['authtype'] == 'basic') {
2494                      $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2495                  }
2496                  if ($this->proxy['authtype'] == 'ntlm') {
2497                      $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2498                  }
2499              }
2500          }
2501          $this->debug('cURL connection set up');
2502          return true;
2503        } else {
2504          $this->setError('Unknown scheme ' . $this->scheme);
2505          $this->debug('Unknown scheme ' . $this->scheme);
2506          return false;
2507        }
2508      }
2509  
2510      /**

2511      * sends the SOAP request and gets the SOAP response via HTTP[S]

2512      *

2513      * @param    string $data message data

2514      * @param    integer $timeout set connection timeout in seconds

2515      * @param    integer $response_timeout set response timeout in seconds

2516      * @param    array $cookies cookies to send

2517      * @return    string data

2518      * @access   public

2519      */
2520  	function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
2521          
2522          $this->debug('entered send() with data of length: '.strlen($data));
2523  
2524          $this->tryagain = true;
2525          $tries = 0;
2526          while ($this->tryagain) {
2527              $this->tryagain = false;
2528              if ($tries++ < 2) {
2529                  // make connnection

2530                  if (!$this->connect($timeout, $response_timeout)){
2531                      return false;
2532                  }
2533                  
2534                  // send request

2535                  if (!$this->sendRequest($data, $cookies)){
2536                      return false;
2537                  }
2538                  
2539                  // get response

2540                  $respdata = $this->getResponse();
2541              } else {
2542                  $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2543              }
2544          }        
2545          $this->debug('end of send()');
2546          return $respdata;
2547      }
2548  
2549  
2550      /**

2551      * sends the SOAP request and gets the SOAP response via HTTPS using CURL

2552      *

2553      * @param    string $data message data

2554      * @param    integer $timeout set connection timeout in seconds

2555      * @param    integer $response_timeout set response timeout in seconds

2556      * @param    array $cookies cookies to send

2557      * @return    string data

2558      * @access   public

2559      * @deprecated

2560      */
2561  	function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
2562          return $this->send($data, $timeout, $response_timeout, $cookies);
2563      }
2564      
2565      /**

2566      * if authenticating, set user credentials here

2567      *

2568      * @param    string $username

2569      * @param    string $password

2570      * @param    string $authtype (basic|digest|certificate|ntlm)

2571      * @param    array $digestRequest (keys must be nonce, nc, realm, qop)

2572      * @param    array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)

2573      * @access   public

2574      */
2575  	function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
2576          $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2577          $this->appendDebug($this->varDump($digestRequest));
2578          $this->debug("certRequest=");
2579          $this->appendDebug($this->varDump($certRequest));
2580          // cf. RFC 2617

2581          if ($authtype == 'basic') {
2582              $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
2583          } elseif ($authtype == 'digest') {
2584              if (isset($digestRequest['nonce'])) {
2585                  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2586                  
2587                  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)

2588      
2589                  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd

2590                  $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2591      
2592                  // H(A1) = MD5(A1)

2593                  $HA1 = md5($A1);
2594      
2595                  // A2 = Method ":" digest-uri-value

2596                  $A2 = $this->request_method . ':' . $this->digest_uri;
2597      
2598                  // H(A2)

2599                  $HA2 =  md5($A2);
2600      
2601                  // KD(secret, data) = H(concat(secret, ":", data))

2602                  // if qop == auth:

2603                  // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)

2604                  //                              ":" nc-value

2605                  //                              ":" unq(cnonce-value)

2606                  //                              ":" unq(qop-value)

2607                  //                              ":" H(A2)

2608                  //                            ) <">

2609                  // if qop is missing,

2610                  // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">

2611      
2612                  $unhashedDigest = '';
2613                  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2614                  $cnonce = $nonce;
2615                  if ($digestRequest['qop'] != '') {
2616                      $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2617                  } else {
2618                      $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2619                  }
2620      
2621                  $hashedDigest = md5($unhashedDigest);
2622      
2623                  $opaque = '';    
2624                  if (isset($digestRequest['opaque'])) {
2625                      $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2626                  }
2627  
2628                  $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 . '"');
2629              }
2630          } elseif ($authtype == 'certificate') {
2631              $this->certRequest = $certRequest;
2632              $this->debug('Authorization header not set for certificate');
2633          } elseif ($authtype == 'ntlm') {
2634              // do nothing

2635              $this->debug('Authorization header not set for ntlm');
2636          }
2637          $this->username = $username;
2638          $this->password = $password;
2639          $this->authtype = $authtype;
2640          $this->digestRequest = $digestRequest;
2641      }
2642      
2643      /**

2644      * set the soapaction value

2645      *

2646      * @param    string $soapaction

2647      * @access   public

2648      */
2649  	function setSOAPAction($soapaction) {
2650          $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2651      }
2652      
2653      /**

2654      * use http encoding

2655      *

2656      * @param    string $enc encoding style. supported values: gzip, deflate, or both

2657      * @access   public

2658      */
2659  	function setEncoding($enc='gzip, deflate') {
2660          if (function_exists('gzdeflate')) {
2661              $this->protocol_version = '1.1';
2662              $this->setHeader('Accept-Encoding', $enc);
2663              if (!isset($this->outgoing_headers['Connection'])) {
2664                  $this->setHeader('Connection', 'close');
2665                  $this->persistentConnection = false;
2666              }
2667              set_magic_quotes_runtime(0);
2668              // deprecated

2669              $this->encoding = $enc;
2670          }
2671      }
2672      
2673      /**

2674      * set proxy info here

2675      *

2676      * @param    string $proxyhost use an empty string to remove proxy

2677      * @param    string $proxyport

2678      * @param    string $proxyusername

2679      * @param    string $proxypassword

2680      * @param    string $proxyauthtype (basic|ntlm)

2681      * @access   public

2682      */
2683  	function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
2684          if ($proxyhost) {
2685              $this->proxy = array(
2686                  'host' => $proxyhost,
2687                  'port' => $proxyport,
2688                  'username' => $proxyusername,
2689                  'password' => $proxypassword,
2690                  'authtype' => $proxyauthtype
2691              );
2692              if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2693                  $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
2694              }
2695          } else {
2696              $this->debug('remove proxy');
2697              $proxy = null;
2698              unsetHeader('Proxy-Authorization');
2699          }
2700      }
2701      
2702  
2703      /**

2704       * Test if the given string starts with a header that is to be skipped.

2705       * Skippable headers result from chunked transfer and proxy requests.

2706       *

2707       * @param    string $data The string to check.

2708       * @returns    boolean    Whether a skippable header was found.

2709       * @access    private

2710       */
2711  	function isSkippableCurlHeader(&$data) {
2712          $skipHeaders = array(    'HTTP/1.1 100',
2713                                  'HTTP/1.0 301',
2714                                  'HTTP/1.1 301',
2715                                  'HTTP/1.0 302',
2716                                  'HTTP/1.1 302',
2717                                  'HTTP/1.0 401',
2718                                  'HTTP/1.1 401',
2719                                  'HTTP/1.0 200 Connection established');
2720          foreach ($skipHeaders as $hd) {
2721              $prefix = substr($data, 0, strlen($hd));
2722              if ($prefix == $hd) return true;
2723          }
2724  
2725          return false;
2726      }
2727  
2728      /**

2729      * decode a string that is encoded w/ "chunked' transfer encoding

2730       * as defined in RFC2068 19.4.6

2731      *

2732      * @param    string $buffer

2733      * @param    string $lb

2734      * @returns    string

2735      * @access   public

2736      * @deprecated

2737      */
2738  	function decodeChunked($buffer, $lb){
2739          // length := 0

2740          $length = 0;
2741          $new = '';
2742          
2743          // read chunk-size, chunk-extension (if any) and CRLF

2744          // get the position of the linebreak

2745          $chunkend = strpos($buffer, $lb);
2746          if ($chunkend == FALSE) {
2747              $this->debug('no linebreak found in decodeChunked');
2748              return $new;
2749          }
2750          $temp = substr($buffer,0,$chunkend);
2751          $chunk_size = hexdec( trim($temp) );
2752          $chunkstart = $chunkend + strlen($lb);
2753          // while (chunk-size > 0) {

2754          while ($chunk_size > 0) {
2755              $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2756              $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2757                
2758              // Just in case we got a broken connection

2759                if ($chunkend == FALSE) {
2760                    $chunk = substr($buffer,$chunkstart);
2761                  // append chunk-data to entity-body

2762                  $new .= $chunk;
2763                    $length += strlen($chunk);
2764                    break;
2765              }
2766              
2767                // read chunk-data and CRLF

2768                $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2769                // append chunk-data to entity-body

2770                $new .= $chunk;
2771                // length := length + chunk-size

2772                $length += strlen($chunk);
2773                // read chunk-size and CRLF

2774                $chunkstart = $chunkend + strlen($lb);
2775              
2776                $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2777              if ($chunkend == FALSE) {
2778                  break; //Just in case we got a broken connection

2779              }
2780              $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2781              $chunk_size = hexdec( trim($temp) );
2782              $chunkstart = $chunkend;
2783          }
2784          return $new;
2785      }
2786      
2787      /**

2788       * Writes the payload, including HTTP headers, to $this->outgoing_payload.

2789       *

2790       * @param    string $data HTTP body

2791       * @param    string $cookie_str data for HTTP Cookie header

2792       * @return    void

2793       * @access    private

2794       */
2795  	function buildPayload($data, $cookie_str = '') {
2796          // Note: for cURL connections, $this->outgoing_payload is ignored,

2797          // as is the Content-Length header, but these are still created as

2798          // debugging guides.

2799  
2800          // add content-length header

2801          $this->setHeader('Content-Length', strlen($data));
2802  
2803          // start building outgoing payload:

2804          if ($this->proxy) {
2805              $uri = $this->url;
2806          } else {
2807              $uri = $this->uri;
2808          }
2809          $req = "$this->request_method $uri HTTP/$this->protocol_version";
2810          $this->debug("HTTP request: $req");
2811          $this->outgoing_payload = "$req\r\n";
2812  
2813          // loop thru headers, serializing

2814          foreach($this->outgoing_headers as $k => $v){
2815              $hdr = $k.': '.$v;
2816              $this->debug("HTTP header: $hdr");
2817              $this->outgoing_payload .= "$hdr\r\n";
2818          }
2819  
2820          // add any cookies

2821          if ($cookie_str != '') {
2822              $hdr = 'Cookie: '.$cookie_str;
2823              $this->debug("HTTP header: $hdr");
2824              $this->outgoing_payload .= "$hdr\r\n";
2825          }
2826  
2827          // header/body separator

2828          $this->outgoing_payload .= "\r\n";
2829          
2830          // add data

2831          $this->outgoing_payload .= $data;
2832      }
2833  
2834      /**

2835      * sends the SOAP request via HTTP[S]

2836      *

2837      * @param    string $data message data

2838      * @param    array $cookies cookies to send

2839      * @return    boolean    true if OK, false if problem

2840      * @access   private

2841      */
2842  	function sendRequest($data, $cookies = NULL) {
2843          // build cookie string

2844          $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2845  
2846          // build payload

2847          $this->buildPayload($data, $cookie_str);
2848  
2849        if ($this->io_method() == 'socket') {
2850          // send payload

2851          if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2852              $this->setError('couldn\'t write message data to socket');
2853              $this->debug('couldn\'t write message data to socket');
2854              return false;
2855          }
2856          $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2857          return true;
2858        } else if ($this->io_method() == 'curl') {
2859          // set payload

2860          // cURL does say this should only be the verb, and in fact it

2861          // turns out that the URI and HTTP version are appended to this, which

2862          // some servers refuse to work with (so we no longer use this method!)

2863          //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);

2864          $curl_headers = array();
2865          foreach($this->outgoing_headers as $k => $v){
2866              if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
2867                  $this->debug("Skip cURL header $k: $v");
2868              } else {
2869                  $curl_headers[] = "$k: $v";
2870              }
2871          }
2872          if ($cookie_str != '') {
2873              $curl_headers[] = 'Cookie: ' . $cookie_str;
2874          }
2875          $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
2876          $this->debug('set cURL HTTP headers');
2877          if ($this->request_method == "POST") {
2878                $this->setCurlOption(CURLOPT_POST, 1);
2879                $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
2880              $this->debug('set cURL POST data');
2881            } else {
2882            }
2883          // insert custom user-set cURL options

2884          foreach ($this->ch_options as $key => $val) {
2885              $this->setCurlOption($key, $val);
2886          }
2887  
2888          $this->debug('set cURL payload');
2889          return true;
2890        }
2891      }
2892  
2893      /**

2894      * gets the SOAP response via HTTP[S]

2895      *

2896      * @return    string the response (also sets member variables like incoming_payload)

2897      * @access   private

2898      */
2899  	function getResponse(){
2900          $this->incoming_payload = '';
2901          
2902        if ($this->io_method() == 'socket') {
2903          // loop until headers have been retrieved

2904          $data = '';
2905          while (!isset($lb)){
2906  
2907              // We might EOF during header read.

2908              if(feof($this->fp)) {
2909                  $this->incoming_payload = $data;
2910                  $this->debug('found no headers before EOF after length ' . strlen($data));
2911                  $this->debug("received before EOF:\n" . $data);
2912                  $this->setError('server failed to send headers');
2913                  return false;
2914              }
2915  
2916              $tmp = fgets($this->fp, 256);
2917              $tmplen = strlen($tmp);
2918              $this->debug("read line of $tmplen bytes: " . trim($tmp));
2919  
2920              if ($tmplen == 0) {
2921                  $this->incoming_payload = $data;
2922                  $this->debug('socket read of headers timed out after length ' . strlen($data));
2923                  $this->debug("read before timeout: " . $data);
2924                  $this->setError('socket read of headers timed out');
2925                  return false;
2926              }
2927  
2928              $data .= $tmp;
2929              $pos = strpos($data,"\r\n\r\n");
2930              if($pos > 1){
2931                  $lb = "\r\n";
2932              } else {
2933                  $pos = strpos($data,"\n\n");
2934                  if($pos > 1){
2935                      $lb = "\n";
2936                  }
2937              }
2938              // remove 100 headers

2939              if (isset($lb) && ereg('^HTTP/1.1 100',$data)) {
2940                  unset($lb);
2941                  $data = '';
2942              }//

2943          }
2944          // store header data

2945          $this->incoming_payload .= $data;
2946          $this->debug('found end of headers after length ' . strlen($data));
2947          // process headers

2948          $header_data = trim(substr($data,0,$pos));
2949          $header_array = explode($lb,$header_data);
2950          $this->incoming_headers = array();
2951          $this->incoming_cookies = array();
2952          foreach($header_array as $header_line){
2953              $arr = explode(':',$header_line, 2);
2954              if(count($arr) > 1){
2955                  $header_name = strtolower(trim($arr[0]));
2956                  $this->incoming_headers[$header_name] = trim($arr[1]);
2957                  if ($header_name == 'set-cookie') {
2958                      // TODO: allow multiple cookies from parseCookie

2959                      $cookie = $this->parseCookie(trim($arr[1]));
2960                      if ($cookie) {
2961                          $this->incoming_cookies[] = $cookie;
2962                          $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2963                      } else {
2964                          $this->debug('did not find cookie in ' . trim($arr[1]));
2965                      }
2966                  }
2967              } else if (isset($header_name)) {
2968                  // append continuation line to previous header

2969                  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2970              }
2971          }
2972          
2973          // loop until msg has been received

2974          if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2975              $content_length =  2147483647;    // ignore any content-length header

2976              $chunked = true;
2977              $this->debug("want to read chunked content");
2978          } elseif (isset($this->incoming_headers['content-length'])) {
2979              $content_length = $this->incoming_headers['content-length'];
2980              $chunked = false;
2981              $this->debug("want to read content of length $content_length");
2982          } else {
2983              $content_length =  2147483647;
2984              $chunked = false;
2985              $this->debug("want to read content to EOF");
2986          }
2987          $data = '';
2988          do {
2989              if ($chunked) {
2990                  $tmp = fgets($this->fp, 256);
2991                  $tmplen = strlen($tmp);
2992                  $this->debug("read chunk line of $tmplen bytes");
2993                  if ($tmplen == 0) {
2994                      $this->incoming_payload = $data;
2995                      $this->debug('socket read of chunk length timed out after length ' . strlen($data));
2996                      $this->debug("read before timeout:\n" . $data);
2997                      $this->setError('socket read of chunk length timed out');
2998                      return false;
2999                  }
3000                  $content_length = hexdec(trim($tmp));
3001                  $this->debug("chunk length $content_length");
3002              }
3003              $strlen = 0;
3004              while (($strlen < $content_length) && (!feof($this->fp))) {
3005                  $readlen = min(8192, $content_length - $strlen);
3006                  $tmp = fread($this->fp, $readlen);
3007                  $tmplen = strlen($tmp);
3008                  $this->debug("read buffer of $tmplen bytes");
3009                  if (($tmplen == 0) && (!feof($this->fp))) {
3010                      $this->incoming_payload = $data;
3011                      $this->debug('socket read of body timed out after length ' . strlen($data));
3012                      $this->debug("read before timeout:\n" . $data);
3013                      $this->setError('socket read of body timed out');
3014                      return false;
3015                  }
3016                  $strlen += $tmplen;
3017                  $data .= $tmp;
3018              }
3019              if ($chunked && ($content_length > 0)) {
3020                  $tmp = fgets($this->fp, 256);
3021                  $tmplen = strlen($tmp);
3022                  $this->debug("read chunk terminator of $tmplen bytes");
3023                  if ($tmplen == 0) {
3024                      $this->incoming_payload = $data;
3025                      $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3026                      $this->debug("read before timeout:\n" . $data);
3027                      $this->setError('socket read of chunk terminator timed out');
3028                      return false;
3029                  }
3030              }
3031          } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3032          if (feof($this->fp)) {
3033              $this->debug('read to EOF');
3034          }
3035          $this->debug('read body of length ' . strlen($data));
3036          $this->incoming_payload .= $data;
3037          $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
3038          
3039          // close filepointer

3040          if(
3041              (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 
3042              (! $this->persistentConnection) || feof($this->fp)){
3043              fclose($this->fp);
3044              $this->fp = false;
3045              $this->debug('closed socket');
3046          }
3047          
3048          // connection was closed unexpectedly

3049          if($this->incoming_payload == ''){
3050              $this->setError('no response from server');
3051              return false;
3052          }
3053          
3054          // decode transfer-encoding

3055  //        if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){

3056  //            if(!$data = $this->decodeChunked($data, $lb)){

3057  //                $this->setError('Decoding of chunked data failed');

3058  //                return false;

3059  //            }

3060              //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";

3061              // set decoded payload

3062  //            $this->incoming_payload = $header_data.$lb.$lb.$data;

3063  //        }

3064      
3065        } else if ($this->io_method() == 'curl') {
3066          // send and receive

3067          $this->debug('send and receive with cURL');
3068          $this->incoming_payload = curl_exec($this->ch);
3069          $data = $this->incoming_payload;
3070  
3071          $cErr = curl_error($this->ch);
3072          if ($cErr != '') {
3073              $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
3074              // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE

3075              foreach(curl_getinfo($this->ch) as $k => $v){
3076                  $err .= "$k: $v<br>";
3077              }
3078              $this->debug($err);
3079              $this->setError($err);
3080              curl_close($this->ch);
3081              return false;
3082          } else {
3083              //echo '<pre>';

3084              //var_dump(curl_getinfo($this->ch));

3085              //echo '</pre>';

3086          }
3087          // close curl

3088          $this->debug('No cURL error, closing cURL');
3089          curl_close($this->ch);
3090          
3091          // try removing skippable headers

3092          $savedata = $data;
3093          while ($this->isSkippableCurlHeader($data)) {
3094              $this->debug("Found HTTP header to skip");
3095              if ($pos = strpos($data,"\r\n\r\n")) {
3096                  $data = ltrim(substr($data,$pos));
3097              } elseif($pos = strpos($data,"\n\n") ) {
3098                  $data = ltrim(substr($data,$pos));
3099              }
3100          }
3101  
3102          if ($data == '') {
3103              // have nothing left; just remove 100 header(s)

3104              $data = $savedata;
3105              while (ereg('^HTTP/1.1 100',$data)) {
3106                  if ($pos = strpos($data,"\r\n\r\n")) {
3107                      $data = ltrim(substr($data,$pos));
3108                  } elseif($pos = strpos($data,"\n\n") ) {
3109                      $data = ltrim(substr($data,$pos));
3110                  }
3111              }
3112          }
3113          
3114          // separate content from HTTP headers

3115          if ($pos = strpos($data,"\r\n\r\n")) {
3116              $lb = "\r\n";
3117          } elseif( $pos = strpos($data,"\n\n")) {
3118              $lb = "\n";
3119          } else {
3120              $this->debug('no proper separation of headers and document');
3121              $this->setError('no proper separation of headers and document');
3122              return false;
3123          }
3124          $header_data = trim(substr($data,0,$pos));
3125          $header_array = explode($lb,$header_data);
3126          $data = ltrim(substr($data,$pos));
3127          $this->debug('found proper separation of headers and document');
3128          $this->debug('cleaned data, stringlen: '.strlen($data));
3129          // clean headers

3130          foreach ($header_array as $header_line) {
3131              $arr = explode(':',$header_line,2);
3132              if(count($arr) > 1){
3133                  $header_name = strtolower(trim($arr[0]));
3134                  $this->incoming_headers[$header_name] = trim($arr[1]);
3135                  if ($header_name == 'set-cookie') {
3136                      // TODO: allow multiple cookies from parseCookie

3137                      $cookie = $this->parseCookie(trim($arr[1]));
3138                      if ($cookie) {
3139                          $this->incoming_cookies[] = $cookie;
3140                          $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3141                      } else {
3142                          $this->debug('did not find cookie in ' . trim($arr[1]));
3143                      }
3144                  }
3145              } else if (isset($header_name)) {
3146                  // append continuation line to previous header

3147                  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3148              }
3149          }
3150        }
3151  
3152          $this->response_status_line = $header_array[0];
3153          $arr = explode(' ', $this->response_status_line, 3);
3154          $http_version = $arr[0];
3155          $http_status = intval($arr[1]);
3156          $http_reason = count($arr) > 2 ? $arr[2] : '';
3157  
3158           // see if we need to resend the request with http digest authentication

3159           if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3160               $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3161               $this->setURL($this->incoming_headers['location']);
3162              $this->tryagain = true;
3163              return false;
3164          }
3165  
3166           // see if we need to resend the request with http digest authentication

3167           if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3168               $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3169               if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
3170                   $this->debug('Server wants digest authentication');
3171                   // remove "Digest " from our elements

3172                   $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3173                   
3174                   // parse elements into array

3175                   $digestElements = explode(',', $digestString);
3176                   foreach ($digestElements as $val) {
3177                       $tempElement = explode('=', trim($val), 2);
3178                       $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
3179                   }
3180  
3181                  // should have (at least) qop, realm, nonce

3182                   if (isset($digestRequest['nonce'])) {
3183                       $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3184                       $this->tryagain = true;
3185                       return false;
3186                   }
3187               }
3188              $this->debug('HTTP authentication failed');
3189              $this->setError('HTTP authentication failed');
3190              return false;
3191           }
3192          
3193          if (
3194              ($http_status >= 300 && $http_status <= 307) ||
3195              ($http_status >= 400 && $http_status <= 417) ||
3196              ($http_status >= 501 && $http_status <= 505)
3197             ) {
3198              $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3199              return false;
3200          }
3201  
3202          // decode content-encoding

3203          if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
3204              if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
3205                  // if decoding works, use it. else assume data wasn't gzencoded

3206                  if(function_exists('gzinflate')){
3207                      //$timer->setMarker('starting decoding of gzip/deflated content');

3208                      // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)

3209                      // this means there are no Zlib headers, although there should be

3210                      $this->debug('The gzinflate function exists');
3211                      $datalen = strlen($data);
3212                      if ($this->incoming_headers['content-encoding'] == 'deflate') {
3213                          if ($degzdata = @gzinflate($data)) {
3214                              $data = $degzdata;
3215                              $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3216                              if (strlen($data) < $datalen) {
3217                                  // test for the case that the payload has been compressed twice

3218                                  $this->debug('The inflated payload is smaller than the gzipped one; try again');
3219                                  if ($degzdata = @gzinflate($data)) {
3220                                      $data = $degzdata;
3221                                      $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3222                                  }
3223                              }
3224                          } else {
3225                              $this->debug('Error using gzinflate to inflate the payload');
3226                              $this->setError('Error using gzinflate to inflate the payload');
3227                          }
3228                      } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
3229                          if ($degzdata = @gzinflate(substr($data, 10))) {    // do our best
3230                              $data = $degzdata;
3231                              $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3232                              if (strlen($data) < $datalen) {
3233                                  // test for the case that the payload has been compressed twice

3234                                  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3235                                  if ($degzdata = @gzinflate(substr($data, 10))) {
3236                                      $data = $degzdata;
3237                                      $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3238                                  }
3239                              }
3240                          } else {
3241                              $this->debug('Error using gzinflate to un-gzip the payload');
3242                              $this->setError('Error using gzinflate to un-gzip the payload');
3243                          }
3244                      }
3245                      //$timer->setMarker('finished decoding of gzip/deflated content');

3246                      //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";

3247                      // set decoded payload

3248                      $this->incoming_payload = $header_data.$lb.$lb.$data;
3249                  } else {
3250                      $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3251                      $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3252                  }
3253              } else {
3254                  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3255                  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3256              }
3257          } else {
3258              $this->debug('No Content-Encoding header');
3259          }
3260          
3261          if(strlen($data) == 0){
3262              $this->debug('no data after headers!');
3263              $this->setError('no data present after HTTP headers');
3264              return false;
3265          }
3266          
3267          return $data;
3268      }
3269  
3270      /**

3271       * sets the content-type for the SOAP message to be sent

3272       *

3273       * @param    string $type the content type, MIME style

3274       * @param    mixed $charset character set used for encoding (or false)

3275       * @access    public

3276       */
3277  	function setContentType($type, $charset = false) {
3278          $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3279      }
3280  
3281      /**

3282       * specifies that an HTTP persistent connection should be used

3283       *

3284       * @return    boolean whether the request was honored by this method.

3285       * @access    public

3286       */
3287  	function usePersistentConnection(){
3288          if (isset($this->outgoing_headers['Accept-Encoding'])) {
3289              return false;
3290          }
3291          $this->protocol_version = '1.1';
3292          $this->persistentConnection = true;
3293          $this->setHeader('Connection', 'Keep-Alive');
3294          return true;
3295      }
3296  
3297      /**

3298       * parse an incoming Cookie into it's parts

3299       *

3300       * @param    string $cookie_str content of cookie

3301       * @return    array with data of that cookie

3302       * @access    private

3303       */
3304      /*

3305       * TODO: allow a Set-Cookie string to be parsed into multiple cookies

3306       */
3307  	function parseCookie($cookie_str) {
3308          $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3309          $data = split(';', $cookie_str);
3310          $value_str = $data[0];
3311  
3312          $cookie_param = 'domain=';
3313          $start = strpos($cookie_str, $cookie_param);
3314          if ($start > 0) {
3315              $domain = substr($cookie_str, $start + strlen($cookie_param));
3316              $domain = substr($domain, 0, strpos($domain, ';'));
3317          } else {
3318              $domain = '';
3319          }
3320  
3321          $cookie_param = 'expires=';
3322          $start = strpos($cookie_str, $cookie_param);
3323          if ($start > 0) {
3324              $expires = substr($cookie_str, $start + strlen($cookie_param));
3325              $expires = substr($expires, 0, strpos($expires, ';'));
3326          } else {
3327              $expires = '';
3328          }
3329  
3330          $cookie_param = 'path=';
3331          $start = strpos($cookie_str, $cookie_param);
3332          if ( $start > 0 ) {
3333              $path = substr($cookie_str, $start + strlen($cookie_param));
3334              $path = substr($path, 0, strpos($path, ';'));
3335          } else {
3336              $path = '/';
3337          }
3338                          
3339          $cookie_param = ';secure;';
3340          if (strpos($cookie_str, $cookie_param) !== FALSE) {
3341              $secure = true;
3342          } else {
3343              $secure = false;
3344          }
3345  
3346          $sep_pos = strpos($value_str, '=');
3347  
3348          if ($sep_pos) {
3349              $name = substr($value_str, 0, $sep_pos);
3350              $value = substr($value_str, $sep_pos + 1);
3351              $cookie= array(    'name' => $name,
3352                              'value' => $value,
3353                              'domain' => $domain,
3354                              'path' => $path,
3355                              'expires' => $expires,
3356                              'secure' => $secure
3357                              );        
3358              return $cookie;
3359          }
3360          return false;
3361      }
3362    
3363      /**

3364       * sort out cookies for the current request

3365       *

3366       * @param    array $cookies array with all cookies

3367       * @param    boolean $secure is the send-content secure or not?

3368       * @return    string for Cookie-HTTP-Header

3369       * @access    private

3370       */
3371  	function getCookiesForRequest($cookies, $secure=false) {
3372          $cookie_str = '';
3373          if ((! is_null($cookies)) && (is_array($cookies))) {
3374              foreach ($cookies as $cookie) {
3375                  if (! is_array($cookie)) {
3376                      continue;
3377                  }
3378                  $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
3379                  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3380                      if (strtotime($cookie['expires']) <= time()) {
3381                          $this->debug('cookie has expired');
3382                          continue;
3383                      }
3384                  }
3385                  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3386                      $domain = preg_quote($cookie['domain']);
3387                      if (! preg_match("'.*$domain$'i", $this->host)) {
3388                          $this->debug('cookie has different domain');
3389                          continue;
3390                      }
3391                  }
3392                  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3393                      $path = preg_quote($cookie['path']);
3394                      if (! preg_match("'^$path.*'i", $this->path)) {
3395                          $this->debug('cookie is for a different path');
3396                          continue;
3397                      }
3398                  }
3399                  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3400                      $this->debug('cookie is secure, transport is not');
3401                      continue;
3402                  }
3403                  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3404                  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3405              }
3406          }
3407          return $cookie_str;
3408    }
3409  }
3410  
3411  ?><?php
3412  
3413  
3414  
3415  /**

3416  *

3417  * nusoap_server allows the user to create a SOAP server

3418  * that is capable of receiving messages and returning responses

3419  *

3420  * @author   Dietrich Ayala <dietrich@ganx4.com>

3421  * @author   Scott Nichol <snichol@users.sourceforge.net>

3422  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

3423  * @access   public

3424  */
3425  class nusoap_server extends nusoap_base {
3426      /**

3427       * HTTP headers of request

3428       * @var array

3429       * @access private

3430       */
3431      var $headers = array();
3432      /**

3433       * HTTP request

3434       * @var string

3435       * @access private

3436       */
3437      var $request = '';
3438      /**

3439       * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)

3440       * @var string

3441       * @access public

3442       */
3443      var $requestHeaders = '';
3444      /**

3445       * SOAP Headers from request (parsed)

3446       * @var mixed

3447       * @access public

3448       */
3449      var $requestHeader = NULL;
3450      /**

3451       * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)

3452       * @var string

3453       * @access public

3454       */
3455      var $document = '';
3456      /**

3457       * SOAP payload for request (text)

3458       * @var string

3459       * @access public

3460       */
3461      var $requestSOAP = '';
3462      /**

3463       * requested method namespace URI

3464       * @var string

3465       * @access private

3466       */
3467      var $methodURI = '';
3468      /**

3469       * name of method requested

3470       * @var string

3471       * @access private

3472       */
3473      var $methodname = '';
3474      /**

3475       * method parameters from request

3476       * @var array

3477       * @access private

3478       */
3479      var $methodparams = array();
3480      /**

3481       * SOAP Action from request

3482       * @var string

3483       * @access private

3484       */
3485      var $SOAPAction = '';
3486      /**

3487       * character set encoding of incoming (request) messages

3488       * @var string

3489       * @access public

3490       */
3491      var $xml_encoding = '';
3492      /**

3493       * toggles whether the parser decodes element content w/ utf8_decode()

3494       * @var boolean

3495       * @access public

3496       */
3497      var $decode_utf8 = true;
3498  
3499      /**

3500       * HTTP headers of response

3501       * @var array

3502       * @access public

3503       */
3504      var $outgoing_headers = array();
3505      /**

3506       * HTTP response

3507       * @var string

3508       * @access private

3509       */
3510      var $response = '';
3511      /**

3512       * SOAP headers for response (text or array of soapval or associative array)

3513       * @var mixed

3514       * @access public

3515       */
3516      var $responseHeaders = '';
3517      /**

3518       * SOAP payload for response (text)

3519       * @var string

3520       * @access private

3521       */
3522      var $responseSOAP = '';
3523      /**

3524       * method return value to place in response

3525       * @var mixed

3526       * @access private

3527       */
3528      var $methodreturn = false;
3529      /**

3530       * whether $methodreturn is a string of literal XML

3531       * @var boolean

3532       * @access public

3533       */
3534      var $methodreturnisliteralxml = false;
3535      /**

3536       * SOAP fault for response (or false)

3537       * @var mixed

3538       * @access private

3539       */
3540      var $fault = false;
3541      /**

3542       * text indication of result (for debugging)

3543       * @var string

3544       * @access private

3545       */
3546      var $result = 'successful';
3547  
3548      /**

3549       * assoc array of operations => opData; operations are added by the register()

3550       * method or by parsing an external WSDL definition

3551       * @var array

3552       * @access private

3553       */
3554      var $operations = array();
3555      /**

3556       * wsdl instance (if one)

3557       * @var mixed

3558       * @access private

3559       */
3560      var $wsdl = false;
3561      /**

3562       * URL for WSDL (if one)

3563       * @var mixed

3564       * @access private

3565       */
3566      var $externalWSDLURL = false;
3567      /**

3568       * whether to append debug to response as XML comment

3569       * @var boolean

3570       * @access public

3571       */
3572      var $debug_flag = false;
3573  
3574  
3575      /**

3576      * constructor

3577      * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.

3578      *

3579      * @param mixed $wsdl file path or URL (string), or wsdl instance (object)

3580      * @access   public

3581      */
3582  	function nusoap_server($wsdl=false){
3583          parent::nusoap_base();
3584          // turn on debugging?

3585          global $debug;
3586          global $HTTP_SERVER_VARS;
3587  
3588          if (isset($_SERVER)) {
3589              $this->debug("_SERVER is defined:");
3590              $this->appendDebug($this->varDump($_SERVER));
3591          } elseif (isset($HTTP_SERVER_VARS)) {
3592              $this->debug("HTTP_SERVER_VARS is defined:");
3593              $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3594          } else {
3595              $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3596          }
3597  
3598          if (isset($debug)) {
3599              $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3600              $this->debug_flag = $debug;
3601          } elseif (isset($_SERVER['QUERY_STRING'])) {
3602              $qs = explode('&', $_SERVER['QUERY_STRING']);
3603              foreach ($qs as $v) {
3604                  if (substr($v, 0, 6) == 'debug=') {
3605                      $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3606                      $this->debug_flag = substr($v, 6);
3607                  }
3608              }
3609          } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3610              $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3611              foreach ($qs as $v) {
3612                  if (substr($v, 0, 6) == 'debug=') {
3613                      $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3614                      $this->debug_flag = substr($v, 6);
3615                  }
3616              }
3617          }
3618  
3619          // wsdl

3620          if($wsdl){
3621              $this->debug("In nusoap_server, WSDL is specified");
3622              if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3623                  $this->wsdl = $wsdl;
3624                  $this->externalWSDLURL = $this->wsdl->wsdl;
3625                  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3626              } else {
3627                  $this->debug('Create wsdl from ' . $wsdl);
3628                  $this->wsdl = new wsdl($wsdl);
3629                  $this->externalWSDLURL = $wsdl;
3630              }
3631              $this->appendDebug($this->wsdl->getDebug());
3632              $this->wsdl->clearDebug();
3633              if($err = $this->wsdl->getError()){
3634                  die('WSDL ERROR: '.$err);
3635              }
3636          }
3637      }
3638  
3639      /**

3640      * processes request and returns response

3641      *

3642      * @param    string $data usually is the value of $HTTP_RAW_POST_DATA

3643      * @access   public

3644      */
3645  	function service($data){
3646          global $HTTP_SERVER_VARS;
3647  
3648          if (isset($_SERVER['QUERY_STRING'])) {
3649              $qs = $_SERVER['QUERY_STRING'];
3650          } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3651              $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3652          } else {
3653              $qs = '';
3654          }
3655          $this->debug("In service, query string=$qs");
3656  
3657          if (ereg('wsdl', $qs) ){
3658              $this->debug("In service, this is a request for WSDL");
3659              if($this->externalWSDLURL){
3660                if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
3661                  header('Location: '.$this->externalWSDLURL);
3662                } else { // assume file
3663                  header("Content-Type: text/xml\r\n");
3664                  $fp = fopen($this->externalWSDLURL, 'r');
3665                  fpassthru($fp);
3666                }
3667              } elseif ($this->wsdl) {
3668                  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3669                  print $this->wsdl->serialize($this->debug_flag);
3670                  if ($this->debug_flag) {
3671                      $this->debug('wsdl:');
3672                      $this->appendDebug($this->varDump($this->wsdl));
3673                      print $this->getDebugAsXMLComment();
3674                  }
3675              } else {
3676                  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3677                  print "This service does not provide WSDL";
3678              }
3679          } elseif ($data == '' && $this->wsdl) {
3680              $this->debug("In service, there is no data, so return Web description");
3681              print $this->wsdl->webDescription();
3682          } else {
3683              $this->debug("In service, invoke the request");
3684              $this->parse_request($data);
3685              if (! $this->fault) {
3686                  $this->invoke_method();
3687              }
3688              if (! $this->fault) {
3689                  $this->serialize_return();
3690              }
3691              $this->send_response();
3692          }
3693      }
3694  
3695      /**

3696      * parses HTTP request headers.

3697      *

3698      * The following fields are set by this function (when successful)

3699      *

3700      * headers

3701      * request

3702      * xml_encoding

3703      * SOAPAction

3704      *

3705      * @access   private

3706      */
3707  	function parse_http_headers() {
3708          global $HTTP_SERVER_VARS;
3709  
3710          $this->request = '';
3711          $this->SOAPAction = '';
3712          if(function_exists('getallheaders')){
3713              $this->debug("In parse_http_headers, use getallheaders");
3714              $headers = getallheaders();
3715              foreach($headers as $k=>$v){
3716                  $k = strtolower($k);
3717                  $this->headers[$k] = $v;
3718                  $this->request .= "$k: $v\r\n";
3719                  $this->debug("$k: $v");
3720              }
3721              // get SOAPAction header

3722              if(isset($this->headers['soapaction'])){
3723                  $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
3724              }
3725              // get the character encoding of the incoming request

3726              if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
3727                  $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
3728                  if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
3729                      $this->xml_encoding = strtoupper($enc);
3730                  } else {
3731                      $this->xml_encoding = 'US-ASCII';
3732                  }
3733              } else {
3734                  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1

3735                  $this->xml_encoding = 'ISO-8859-1';
3736              }
3737          } elseif(isset($_SERVER) && is_array($_SERVER)){
3738              $this->debug("In parse_http_headers, use _SERVER");
3739              foreach ($_SERVER as $k => $v) {
3740                  if (substr($k, 0, 5) == 'HTTP_') {
3741                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
3742                  } else {
3743                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
3744                  }
3745                  if ($k == 'soapaction') {
3746                      // get SOAPAction header

3747                      $k = 'SOAPAction';
3748                      $v = str_replace('"', '', $v);
3749                      $v = str_replace('\\', '', $v);
3750                      $this->SOAPAction = $v;
3751                  } else if ($k == 'content-type') {
3752                      // get the character encoding of the incoming request

3753                      if (strpos($v, '=')) {
3754                          $enc = substr(strstr($v, '='), 1);
3755                          $enc = str_replace('"', '', $enc);
3756                          $enc = str_replace('\\', '', $enc);
3757                          if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
3758                              $this->xml_encoding = strtoupper($enc);
3759                          } else {
3760                              $this->xml_encoding = 'US-ASCII';
3761                          }
3762                      } else {
3763                          // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1

3764                          $this->xml_encoding = 'ISO-8859-1';
3765                      }
3766                  }
3767                  $this->headers[$k] = $v;
3768                  $this->request .= "$k: $v\r\n";
3769                  $this->debug("$k: $v");
3770              }
3771          } elseif (is_array($HTTP_SERVER_VARS)) {
3772              $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3773              foreach ($HTTP_SERVER_VARS as $k => $v) {
3774                  if (substr($k, 0, 5) == 'HTTP_') {
3775                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                              $k = strtolower(substr($k, 5));
3776                  } else {
3777                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                              $k = strtolower($k);
3778                  }
3779                  if ($k == 'soapaction') {
3780                      // get SOAPAction header

3781                      $k = 'SOAPAction';
3782                      $v = str_replace('"', '', $v);
3783                      $v = str_replace('\\', '', $v);
3784                      $this->SOAPAction = $v;
3785                  } else if ($k == 'content-type') {
3786                      // get the character encoding of the incoming request

3787                      if (strpos($v, '=')) {
3788                          $enc = substr(strstr($v, '='), 1);
3789                          $enc = str_replace('"', '', $enc);
3790                          $enc = str_replace('\\', '', $enc);
3791                          if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
3792                              $this->xml_encoding = strtoupper($enc);
3793                          } else {
3794                              $this->xml_encoding = 'US-ASCII';
3795                          }
3796                      } else {
3797                          // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1

3798                          $this->xml_encoding = 'ISO-8859-1';
3799                      }
3800                  }
3801                  $this->headers[$k] = $v;
3802                  $this->request .= "$k: $v\r\n";
3803                  $this->debug("$k: $v");
3804              }
3805          } else {
3806              $this->debug("In parse_http_headers, HTTP headers not accessible");
3807              $this->setError("HTTP headers not accessible");
3808          }
3809      }
3810  
3811      /**

3812      * parses a request

3813      *

3814      * The following fields are set by this function (when successful)

3815      *

3816      * headers

3817      * request

3818      * xml_encoding

3819      * SOAPAction

3820      * request

3821      * requestSOAP

3822      * methodURI

3823      * methodname

3824      * methodparams

3825      * requestHeaders

3826      * document

3827      *

3828      * This sets the fault field on error

3829      *

3830      * @param    string $data XML string

3831      * @access   private

3832      */
3833  	function parse_request($data='') {
3834          $this->debug('entering parse_request()');
3835          $this->parse_http_headers();
3836          $this->debug('got character encoding: '.$this->xml_encoding);
3837          // uncompress if necessary

3838          if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3839              $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3840              if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3841                  // if decoding works, use it. else assume data wasn't gzencoded

3842                  if (function_exists('gzuncompress')) {
3843                      if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3844                          $data = $degzdata;
3845                      } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3846                          $data = $degzdata;
3847                      } else {
3848                          $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3849                          return;
3850                      }
3851                  } else {
3852                      $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3853                      return;
3854                  }
3855              }
3856          }
3857          $this->request .= "\r\n".$data;
3858          $data = $this->parseRequest($this->headers, $data);
3859          $this->requestSOAP = $data;
3860          $this->debug('leaving parse_request');
3861      }
3862  
3863      /**

3864      * invokes a PHP function for the requested SOAP method

3865      *

3866      * The following fields are set by this function (when successful)

3867      *

3868      * methodreturn

3869      *

3870      * Note that the PHP function that is called may also set the following

3871      * fields to affect the response sent to the client

3872      *

3873      * responseHeaders

3874      * outgoing_headers

3875      *

3876      * This sets the fault field on error

3877      *

3878      * @access   private

3879      */
3880  	function invoke_method() {
3881          $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3882  
3883          if ($this->wsdl) {
3884              if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3885                  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3886                  $this->appendDebug('opData=' . $this->varDump($this->opData));
3887              } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3888                  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element

3889                  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3890                  $this->appendDebug('opData=' . $this->varDump($this->opData));
3891                  $this->methodname = $this->opData['name'];
3892              } else {
3893                  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3894                  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3895                  return;
3896              }
3897          } else {
3898              $this->debug('in invoke_method, no WSDL to validate method');
3899          }
3900  
3901          // if a . is present in $this->methodname, we see if there is a class in scope,

3902          // which could be referred to. We will also distinguish between two deliminators,

3903          // to allow methods to be called a the class or an instance

3904          $class = '';
3905          $method = '';
3906          if (strpos($this->methodname, '..') > 0) {
3907              $delim = '..';
3908          } else if (strpos($this->methodname, '.') > 0) {
3909              $delim = '.';
3910          } else {
3911              $delim = '';
3912          }
3913  
3914          if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3915              class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3916              // get the class and method name

3917              $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3918              $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3919              $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3920          }
3921  
3922          // does method exist?

3923          if ($class == '') {
3924              if (!function_exists($this->methodname)) {
3925                  $this->debug("in invoke_method, function '$this->methodname' not found!");
3926                  $this->result = 'fault: method not found';
3927                  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3928                  return;
3929              }
3930          } else {
3931              $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
3932              if (!in_array($method_to_compare, get_class_methods($class))) {
3933                  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
3934                  $this->result = 'fault: method not found';
3935                  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3936                  return;
3937              }
3938          }
3939  
3940          // evaluate message, getting back parameters

3941          // verify that request parameters match the method's signature

3942          if(! $this->verify_method($this->methodname,$this->methodparams)){
3943              // debug

3944              $this->debug('ERROR: request not verified against method signature');
3945              $this->result = 'fault: request failed validation against method signature';
3946              // return fault

3947              $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
3948              return;
3949          }
3950  
3951          // if there are parameters to pass

3952          $this->debug('in invoke_method, params:');
3953          $this->appendDebug($this->varDump($this->methodparams));
3954          $this->debug("in invoke_method, calling '$this->methodname'");
3955          if (!function_exists('call_user_func_array')) {
3956              if ($class == '') {
3957                  $this->debug('in invoke_method, calling function using eval()');
3958                  $funcCall = "\$this->methodreturn = $this->methodname(";
3959              } else {
3960                  if ($delim == '..') {
3961                      $this->debug('in invoke_method, calling class method using eval()');
3962                      $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
3963                  } else {
3964                      $this->debug('in invoke_method, calling instance method using eval()');
3965                      // generate unique instance name

3966                      $instname = "\$inst_".time();
3967                      $funcCall = $instname." = new ".$class."(); ";
3968                      $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
3969                  }
3970              }
3971              if ($this->methodparams) {
3972                  foreach ($this->methodparams as $param) {
3973                      if (is_array($param) || is_object($param)) {
3974                          $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
3975                          return;
3976                      }
3977                      $funcCall .= "\"$param\",";
3978                  }
3979                  $funcCall = substr($funcCall, 0, -1);
3980              }
3981              $funcCall .= ');';
3982              $this->debug('in invoke_method, function call: '.$funcCall);
3983              @eval($funcCall);
3984          } else {
3985              if ($class == '') {
3986                  $this->debug('in invoke_method, calling function using call_user_func_array()');
3987                  $call_arg = "$this->methodname";    // straight assignment changes $this->methodname to lower case after call_user_func_array()

3988              } elseif ($delim == '..') {
3989                  $this->debug('in invoke_method, calling class method using call_user_func_array()');
3990                  $call_arg = array ($class, $method);
3991              } else {
3992                  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
3993                  $instance = new $class ();
3994                  $call_arg = array(&$instance, $method);
3995              }
3996              if (is_array($this->methodparams)) {
3997                  $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
3998              } else {
3999                  $this->methodreturn = call_user_func_array($call_arg, array());
4000              }
4001          }
4002          $this->debug('in invoke_method, methodreturn:');
4003          $this->appendDebug($this->varDump($this->methodreturn));
4004          $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
4005      }
4006  
4007      /**

4008      * serializes the return value from a PHP function into a full SOAP Envelope

4009      *

4010      * The following fields are set by this function (when successful)

4011      *

4012      * responseSOAP

4013      *

4014      * This sets the fault field on error

4015      *

4016      * @access   private

4017      */
4018  	function serialize_return() {
4019          $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4020          // if fault

4021          if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
4022              $this->debug('got a fault object from method');
4023              $this->fault = $this->methodreturn;
4024              return;
4025          } elseif ($this->methodreturnisliteralxml) {
4026              $return_val = $this->methodreturn;
4027          // returned value(s)

4028          } else {
4029              $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
4030              $this->debug('serializing return value');
4031              if($this->wsdl){
4032                  if (sizeof($this->opData['output']['parts']) > 1) {
4033                      $this->debug('more than one output part, so use the method return unchanged');
4034                      $opParams = $this->methodreturn;
4035                  } elseif (sizeof($this->opData['output']['parts']) == 1) {
4036                      $this->debug('exactly one output part, so wrap the method return in a simple array');
4037                      // TODO: verify that it is not already wrapped!

4038                      //foreach ($this->opData['output']['parts'] as $name => $type) {

4039                      //    $this->debug('wrap in element named ' . $name);

4040                      //}

4041                      $opParams = array($this->methodreturn);
4042                  }
4043                  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
4044                  $this->appendDebug($this->wsdl->getDebug());
4045                  $this->wsdl->clearDebug();
4046                  if($errstr = $this->wsdl->getError()){
4047                      $this->debug('got wsdl error: '.$errstr);
4048                      $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4049                      return;
4050                  }
4051              } else {
4052                  if (isset($this->methodreturn)) {
4053                      $return_val = $this->serialize_val($this->methodreturn, 'return');
4054                  } else {
4055                      $return_val = '';
4056                      $this->debug('in absence of WSDL, assume void return for backward compatibility');
4057                  }
4058              }
4059          }
4060          $this->debug('return value:');
4061          $this->appendDebug($this->varDump($return_val));
4062  
4063          $this->debug('serializing response');
4064          if ($this->wsdl) {
4065              $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4066              if ($this->opData['style'] == 'rpc') {
4067                  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4068                  if ($this->opData['output']['use'] == 'literal') {
4069                      // 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

4070                      $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4071                  } else {
4072                      $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4073                  }
4074              } else {
4075                  $this->debug('style is not rpc for serialization: assume document');
4076                  $payload = $return_val;
4077              }
4078          } else {
4079              $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4080              $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
4081          }
4082          $this->result = 'successful';
4083          if($this->wsdl){
4084              //if($this->debug_flag){

4085                  $this->appendDebug($this->wsdl->getDebug());
4086              //    }

4087              if (isset($opData['output']['encodingStyle'])) {
4088                  $encodingStyle = $opData['output']['encodingStyle'];
4089              } else {
4090                  $encodingStyle = '';
4091              }
4092              // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.

4093              $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
4094          } else {
4095              $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
4096          }
4097          $this->debug("Leaving serialize_return");
4098      }
4099  
4100      /**

4101      * sends an HTTP response

4102      *

4103      * The following fields are set by this function (when successful)

4104      *

4105      * outgoing_headers

4106      * response

4107      *

4108      * @access   private

4109      */
4110  	function send_response() {
4111          $this->debug('Enter send_response');
4112          if ($this->fault) {
4113              $payload = $this->fault->serialize();
4114              $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
4115              $this->outgoing_headers[] = "Status: 500 Internal Server Error";
4116          } else {
4117              $payload = $this->responseSOAP;
4118              // Some combinations of PHP+Web server allow the Status

4119              // to come through as a header.  Since OK is the default

4120              // just do nothing.

4121              // $this->outgoing_headers[] = "HTTP/1.0 200 OK";

4122              // $this->outgoing_headers[] = "Status: 200 OK";

4123          }
4124          // add debug data if in debug mode

4125          if(isset($this->debug_flag) && $this->debug_flag){
4126              $payload .= $this->getDebugAsXMLComment();
4127          }
4128          $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4129          ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
4130          $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
4131          // Let the Web server decide about this

4132          //$this->outgoing_headers[] = "Connection: Close\r\n";

4133          $payload = $this->getHTTPBody($payload);
4134          $type = $this->getHTTPContentType();
4135          $charset = $this->getHTTPContentTypeCharset();
4136          $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4137          //begin code to compress payload - by John

4138          // NOTE: there is no way to know whether the Web server will also compress

4139          // this data.

4140          if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {    
4141              if (strstr($this->headers['accept-encoding'], 'gzip')) {
4142                  if (function_exists('gzencode')) {
4143                      if (isset($this->debug_flag) && $this->debug_flag) {
4144                          $payload .= "<!-- Content being gzipped -->";
4145                      }
4146                      $this->outgoing_headers[] = "Content-Encoding: gzip";
4147                      $payload = gzencode($payload);
4148                  } else {
4149                      if (isset($this->debug_flag) && $this->debug_flag) {
4150                          $payload .= "<!-- Content will not be gzipped: no gzencode -->";
4151                      }
4152                  }
4153              } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
4154                  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),

4155                  // instead of gzcompress output,

4156                  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)

4157                  if (function_exists('gzdeflate')) {
4158                      if (isset($this->debug_flag) && $this->debug_flag) {
4159                          $payload .= "<!-- Content being deflated -->";
4160                      }
4161                      $this->outgoing_headers[] = "Content-Encoding: deflate";
4162                      $payload = gzdeflate($payload);
4163                  } else {
4164                      if (isset($this->debug_flag) && $this->debug_flag) {
4165                          $payload .= "<!-- Content will not be deflated: no gzcompress -->";
4166                      }
4167                  }
4168              }
4169          }
4170          //end code

4171          $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
4172          reset($this->outgoing_headers);
4173          foreach($this->outgoing_headers as $hdr){
4174              header($hdr, false);
4175          }
4176          print $payload;
4177          $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
4178      }
4179  
4180      /**

4181      * takes the value that was created by parsing the request

4182      * and compares to the method's signature, if available.

4183      *

4184      * @param    string    $operation    The operation to be invoked

4185      * @param    array    $request    The array of parameter values

4186      * @return    boolean    Whether the operation was found

4187      * @access   private

4188      */
4189  	function verify_method($operation,$request){
4190          if(isset($this->wsdl) && is_object($this->wsdl)){
4191              if($this->wsdl->getOperationData($operation)){
4192                  return true;
4193              }
4194          } elseif(isset($this->operations[$operation])){
4195              return true;
4196          }
4197          return false;
4198      }
4199  
4200      /**

4201      * processes SOAP message received from client

4202      *

4203      * @param    array    $headers    The HTTP headers

4204      * @param    string    $data        unprocessed request data from client

4205      * @return    mixed    value of the message, decoded into a PHP type

4206      * @access   private

4207      */
4208      function parseRequest($headers, $data) {
4209          $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
4210          if (!strstr($headers['content-type'], 'text/xml')) {
4211              $this->setError('Request not of type text/xml');
4212              return false;
4213          }
4214          if (strpos($headers['content-type'], '=')) {
4215              $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
4216              $this->debug('Got response encoding: ' . $enc);
4217              if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
4218                  $this->xml_encoding = strtoupper($enc);
4219              } else {
4220                  $this->xml_encoding = 'US-ASCII';
4221              }
4222          } else {
4223              // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1

4224              $this->xml_encoding = 'ISO-8859-1';
4225          }
4226          $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4227          // parse response, get soap parser obj

4228          $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
4229          // parser debug

4230          $this->debug("parser debug: \n".$parser->getDebug());
4231          // if fault occurred during message parsing

4232          if($err = $parser->getError()){
4233              $this->result = 'fault: error in msg parsing: '.$err;
4234              $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
4235          // else successfully parsed request into soapval object

4236          } else {
4237              // get/set methodname

4238              $this->methodURI = $parser->root_struct_namespace;
4239              $this->methodname = $parser->root_struct_name;
4240              $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
4241              $this->debug('calling parser->get_soapbody()');
4242              $this->methodparams = $parser->get_soapbody();
4243              // get SOAP headers

4244              $this->requestHeaders = $parser->getHeaders();
4245              // get SOAP Header

4246              $this->requestHeader = $parser->get_soapheader();
4247              // add document for doclit support

4248              $this->document = $parser->document;
4249          }
4250       }
4251  
4252      /**

4253      * gets the HTTP body for the current response.

4254      *

4255      * @param string $soapmsg The SOAP payload

4256      * @return string The HTTP body, which includes the SOAP payload

4257      * @access private

4258      */
4259  	function getHTTPBody($soapmsg) {
4260          return $soapmsg;
4261      }
4262      
4263      /**

4264      * gets the HTTP content type for the current response.

4265      *

4266      * Note: getHTTPBody must be called before this.

4267      *

4268      * @return string the HTTP content type for the current response.

4269      * @access private

4270      */
4271  	function getHTTPContentType() {
4272          return 'text/xml';
4273      }
4274      
4275      /**

4276      * gets the HTTP content type charset for the current response.

4277      * returns false for non-text content types.

4278      *

4279      * Note: getHTTPBody must be called before this.

4280      *

4281      * @return string the HTTP content type charset for the current response.

4282      * @access private

4283      */
4284  	function getHTTPContentTypeCharset() {
4285          return $this->soap_defencoding;
4286      }
4287  
4288      /**

4289      * add a method to the dispatch map (this has been replaced by the register method)

4290      *

4291      * @param    string $methodname

4292      * @param    string $in array of input values

4293      * @param    string $out array of output values

4294      * @access   public

4295      * @deprecated

4296      */
4297  	function add_to_map($methodname,$in,$out){
4298              $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
4299      }
4300  
4301      /**

4302      * register a service function with the server

4303      *

4304      * @param    string $name the name of the PHP function, class.method or class..method

4305      * @param    array $in assoc array of input values: key = param name, value = param type

4306      * @param    array $out assoc array of output values: key = param name, value = param type

4307      * @param    mixed $namespace the element namespace for the method or false

4308      * @param    mixed $soapaction the soapaction for the method or false

4309      * @param    mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically

4310      * @param    mixed $use optional (encoded|literal) or false

4311      * @param    string $documentation optional Description to include in WSDL

4312      * @param    string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)

4313      * @access   public

4314      */
4315  	function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
4316          global $HTTP_SERVER_VARS;
4317  
4318          if($this->externalWSDLURL){
4319              die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
4320          }
4321          if (! $name) {
4322              die('You must specify a name when you register an operation');
4323          }
4324          if (!is_array($in)) {
4325              die('You must provide an array for operation inputs');
4326          }
4327          if (!is_array($out)) {
4328              die('You must provide an array for operation outputs');
4329          }
4330          if(false == $namespace) {
4331          }
4332          if(false == $soapaction) {
4333              if (isset($_SERVER)) {
4334                  $SERVER_NAME = $_SERVER['SERVER_NAME'];
4335                  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4336                  $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4337              } elseif (isset($HTTP_SERVER_VARS)) {
4338                  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4339                  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4340                  $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4341              } else {
4342                  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4343              }
4344              if ($HTTPS == '1' || $HTTPS == 'on') {
4345                  $SCHEME = 'https';
4346              } else {
4347                  $SCHEME = 'http';
4348              }
4349              $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
4350          }
4351          if(false == $style) {
4352              $style = "rpc";
4353          }
4354          if(false == $use) {
4355              $use = "encoded";
4356          }
4357          if ($use == 'encoded' && $encodingStyle = '') {
4358              $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4359          }
4360  
4361          $this->operations[$name] = array(
4362          'name' => $name,
4363          'in' => $in,
4364          'out' => $out,
4365          'namespace' => $namespace,
4366          'soapaction' => $soapaction,
4367          'style' => $style);
4368          if($this->wsdl){
4369              $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
4370          }
4371          return true;
4372      }
4373  
4374      /**

4375      * Specify a fault to be returned to the client.

4376      * This also acts as a flag to the server that a fault has occured.

4377      *

4378      * @param    string $faultcode

4379      * @param    string $faultstring

4380      * @param    string $faultactor

4381      * @param    string $faultdetail

4382      * @access   public

4383      */
4384  	function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
4385          if ($faultdetail == '' && $this->debug_flag) {
4386              $faultdetail = $this->getDebug();
4387          }
4388          $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
4389          $this->fault->soap_defencoding = $this->soap_defencoding;
4390      }
4391  
4392      /**

4393      * Sets up wsdl object.

4394      * Acts as a flag to enable internal WSDL generation

4395      *

4396      * @param string $serviceName, name of the service

4397      * @param mixed $namespace optional 'tns' service namespace or false

4398      * @param mixed $endpoint optional URL of service endpoint or false

4399      * @param string $style optional (rpc|document) WSDL style (also specified by operation)

4400      * @param string $transport optional SOAP transport

4401      * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false

4402      */
4403      function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4404      {
4405          global $HTTP_SERVER_VARS;
4406  
4407          if (isset($_SERVER)) {
4408              $SERVER_NAME = $_SERVER['SERVER_NAME'];
4409              $SERVER_PORT = $_SERVER['SERVER_PORT'];
4410              $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4411              $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4412          } elseif (isset($HTTP_SERVER_VARS)) {
4413              $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4414              $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4415              $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4416              $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4417          } else {
4418              $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4419          }
4420          // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)

4421          $colon = strpos($SERVER_NAME,":");
4422          if ($colon) {
4423              $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4424          }
4425          if ($SERVER_PORT == 80) {
4426              $SERVER_PORT = '';
4427          } else {
4428              $SERVER_PORT = ':' . $SERVER_PORT;
4429          }
4430          if(false == $namespace) {
4431              $namespace = "http://$SERVER_NAME/soap/$serviceName";
4432          }
4433          
4434          if(false == $endpoint) {
4435              if ($HTTPS == '1' || $HTTPS == 'on') {
4436                  $SCHEME = 'https';
4437              } else {
4438                  $SCHEME = 'http';
4439              }
4440              $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4441          }
4442          
4443          if(false == $schemaTargetNamespace) {
4444              $schemaTargetNamespace = $namespace;
4445          }
4446          
4447          $this->wsdl = new wsdl;
4448          $this->wsdl->serviceName = $serviceName;
4449          $this->wsdl->endpoint = $endpoint;
4450          $this->wsdl->namespaces['tns'] = $namespace;
4451          $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4452          $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4453          if ($schemaTargetNamespace != $namespace) {
4454              $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4455          }
4456          $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4457          if ($style == 'document') {
4458              $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4459          }
4460          $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4461          $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4462          $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4463          $this->wsdl->bindings[$serviceName.'Binding'] = array(
4464              'name'=>$serviceName.'Binding',
4465              'style'=>$style,
4466              'transport'=>$transport,
4467              'portType'=>$serviceName.'PortType');
4468          $this->wsdl->ports[$serviceName.'Port'] = array(
4469              'binding'=>$serviceName.'Binding',
4470              'location'=>$endpoint,
4471              'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
4472      }
4473  }
4474  
4475  /**

4476   * Backward compatibility

4477   */
4478  class soap_server extends nusoap_server {
4479  }
4480  
4481  ?><?php
4482  
4483  
4484  
4485  /**

4486  * parses a WSDL file, allows access to it's data, other utility methods.

4487  * also builds WSDL structures programmatically.

4488  * 

4489  * @author   Dietrich Ayala <dietrich@ganx4.com>

4490  * @author   Scott Nichol <snichol@users.sourceforge.net>

4491  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

4492  * @access public 

4493  */
4494  class wsdl extends nusoap_base {
4495      // URL or filename of the root of this WSDL

4496      var $wsdl; 
4497      // define internal arrays of bindings, ports, operations, messages, etc.

4498      var $schemas = array();
4499      var $currentSchema;
4500      var $message = array();
4501      var $complexTypes = array();
4502      var $messages = array();
4503      var $currentMessage;
4504      var $currentOperation;
4505      var $portTypes = array();
4506      var $currentPortType;
4507      var $bindings = array();
4508      var $currentBinding;
4509      var $ports = array();
4510      var $currentPort;
4511      var $opData = array();
4512      var $status = '';
4513      var $documentation = false;
4514      var $endpoint = ''; 
4515      // array of wsdl docs to import

4516      var $import = array(); 
4517      // parser vars

4518      var $parser;
4519      var $position = 0;
4520      var $depth = 0;
4521      var $depth_array = array();
4522      // for getting wsdl

4523      var $proxyhost = '';
4524      var $proxyport = '';
4525      var $proxyusername = '';
4526      var $proxypassword = '';
4527      var $timeout = 0;
4528      var $response_timeout = 30;
4529      var $curl_options = array();    // User-specified cURL options

4530      var $use_curl = false;            // whether to always try to use cURL

4531      // for HTTP authentication

4532      var $username = '';                // Username for HTTP authentication

4533      var $password = '';                // Password for HTTP authentication

4534      var $authtype = '';                // Type of HTTP authentication

4535      var $certRequest = array();        // Certificate for HTTP SSL authentication

4536  
4537      /**

4538       * constructor

4539       * 

4540       * @param string $wsdl WSDL document URL

4541       * @param string $proxyhost

4542       * @param string $proxyport

4543       * @param string $proxyusername

4544       * @param string $proxypassword

4545       * @param integer $timeout set the connection timeout

4546       * @param integer $response_timeout set the response timeout

4547       * @param array $curl_options user-specified cURL options

4548       * @param boolean $use_curl try to use cURL

4549       * @access public 

4550       */
4551      function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
4552          parent::nusoap_base();
4553          $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4554          $this->proxyhost = $proxyhost;
4555          $this->proxyport = $proxyport;
4556          $this->proxyusername = $proxyusername;
4557          $this->proxypassword = $proxypassword;
4558          $this->timeout = $timeout;
4559          $this->response_timeout = $response_timeout;
4560          if (is_array($curl_options))
4561              $this->curl_options = $curl_options;
4562          $this->use_curl = $use_curl;
4563          $this->fetchWSDL($wsdl);
4564      }
4565  
4566      /**

4567       * fetches the WSDL document and parses it

4568       *

4569       * @access public

4570       */
4571  	function fetchWSDL($wsdl) {
4572          $this->debug("parse and process WSDL path=$wsdl");
4573          $this->wsdl = $wsdl;
4574          // parse wsdl file

4575          if ($this->wsdl != "") {
4576              $this->parseWSDL($this->wsdl);
4577          }
4578          // imports

4579          // TODO: handle imports more properly, grabbing them in-line and nesting them

4580          $imported_urls = array();
4581          $imported = 1;
4582          while ($imported > 0) {
4583              $imported = 0;
4584              // Schema imports

4585              foreach ($this->schemas as $ns => $list) {
4586                  foreach ($list as $xs) {
4587                      $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!

4588                      foreach ($xs->imports as $ns2 => $list2) {
4589                          for ($ii = 0; $ii < count($list2); $ii++) {
4590                              if (! $list2[$ii]['loaded']) {
4591                                  $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4592                                  $url = $list2[$ii]['location'];
4593                                  if ($url != '') {
4594                                      $urlparts = parse_url($url);
4595                                      if (!isset($urlparts['host'])) {
4596                                          $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
4597                                                  substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4598                                      }
4599                                      if (! in_array($url, $imported_urls)) {
4600                                          $this->parseWSDL($url);
4601                                          $imported++;
4602                                          $imported_urls[] = $url;
4603                                      }
4604                                  } else {
4605                                      $this->debug("Unexpected scenario: empty URL for unloaded import");
4606                                  }
4607                              }
4608                          }
4609                      } 
4610                  }
4611              }
4612              // WSDL imports

4613              $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!

4614              foreach ($this->import as $ns => $list) {
4615                  for ($ii = 0; $ii < count($list); $ii++) {
4616                      if (! $list[$ii]['loaded']) {
4617                          $this->import[$ns][$ii]['loaded'] = true;
4618                          $url = $list[$ii]['location'];
4619                          if ($url != '') {
4620                              $urlparts = parse_url($url);
4621                              if (!isset($urlparts['host'])) {
4622                                  $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4623                                          substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4624                              }
4625                              if (! in_array($url, $imported_urls)) {
4626                                  $this->parseWSDL($url);
4627                                  $imported++;
4628                                  $imported_urls[] = $url;
4629                              }
4630                          } else {
4631                              $this->debug("Unexpected scenario: empty URL for unloaded import");
4632                          }
4633                      }
4634                  }
4635              } 
4636          }
4637          // add new data to operation data

4638          foreach($this->bindings as $binding => $bindingData) {
4639              if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4640                  foreach($bindingData['operations'] as $operation => $data) {
4641                      $this->debug('post-parse data gathering for ' . $operation);
4642                      $this->bindings[$binding]['operations'][$operation]['input'] = 
4643                          isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
4644                          array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4645                          $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4646                      $this->bindings[$binding]['operations'][$operation]['output'] = 
4647                          isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4648                          array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4649                          $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4650                      if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
4651                          $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4652                      }
4653                      if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
4654                             $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4655                      }
4656                      // Set operation style if necessary, but do not override one already provided

4657                      if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
4658                          $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4659                      }
4660                      $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4661                      $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4662                      $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4663                  } 
4664              } 
4665          }
4666      }
4667  
4668      /**

4669       * parses the wsdl document

4670       * 

4671       * @param string $wsdl path or URL

4672       * @access private 

4673       */
4674      function parseWSDL($wsdl = '') {
4675          $this->debug("parse WSDL at path=$wsdl");
4676  
4677          if ($wsdl == '') {
4678              $this->debug('no wsdl passed to parseWSDL()!!');
4679              $this->setError('no wsdl passed to parseWSDL()!!');
4680              return false;
4681          }
4682          
4683          // parse $wsdl for url format

4684          $wsdl_props = parse_url($wsdl);
4685  
4686          if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4687              $this->debug('getting WSDL http(s) URL ' . $wsdl);
4688              // get wsdl

4689              $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
4690              $tr->request_method = 'GET';
4691              $tr->useSOAPAction = false;
4692              if($this->proxyhost && $this->proxyport){
4693                  $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
4694              }
4695              if ($this->authtype != '') {
4696                  $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
4697              }
4698              $tr->setEncoding('gzip, deflate');
4699              $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4700              //$this->debug("WSDL request\n" . $tr->outgoing_payload);

4701              //$this->debug("WSDL response\n" . $tr->incoming_payload);

4702              $this->appendDebug($tr->getDebug());
4703              // catch errors

4704              if($err = $tr->getError() ){
4705                  $errstr = 'HTTP ERROR: '.$err;
4706                  $this->debug($errstr);
4707                  $this->setError($errstr);
4708                  unset($tr);
4709                  return false;
4710              }
4711              unset($tr);
4712              $this->debug("got WSDL URL");
4713          } else {
4714              // $wsdl is not http(s), so treat it as a file URL or plain file path

4715              if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4716                  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4717              } else {
4718                  $path = $wsdl;
4719              }
4720              $this->debug('getting WSDL file ' . $path);
4721              if ($fp = @fopen($path, 'r')) {
4722                  $wsdl_string = '';
4723                  while ($data = fread($fp, 32768)) {
4724                      $wsdl_string .= $data;
4725                  } 
4726                  fclose($fp);
4727              } else {
4728                  $errstr = "Bad path to WSDL file $path";
4729                  $this->debug($errstr);
4730                  $this->setError($errstr);
4731                  return false;
4732              } 
4733          }
4734          $this->debug('Parse WSDL');
4735          // end new code added

4736          // Create an XML parser.

4737          $this->parser = xml_parser_create(); 
4738          // Set the options for parsing the XML data.

4739          // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);

4740          xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
4741          // Set the object for the parser.

4742          xml_set_object($this->parser, $this); 
4743          // Set the element handlers for the parser.

4744          xml_set_element_handler($this->parser, 'start_element', 'end_element');
4745          xml_set_character_data_handler($this->parser, 'character_data');
4746          // Parse the XML file.

4747          if (!xml_parse($this->parser, $wsdl_string, true)) {
4748              // Display an error message.

4749              $errstr = sprintf(
4750                  'XML error parsing WSDL from %s on line %d: %s',
4751                  $wsdl,
4752                  xml_get_current_line_number($this->parser),
4753                  xml_error_string(xml_get_error_code($this->parser))
4754                  );
4755              $this->debug($errstr);
4756              $this->debug("XML payload:\n" . $wsdl_string);
4757              $this->setError($errstr);
4758              return false;
4759          } 
4760          // free the parser

4761          xml_parser_free($this->parser);
4762          $this->debug('Parsing WSDL done');
4763          // catch wsdl parse errors

4764          if($this->getError()){
4765              return false;
4766          }
4767          return true;
4768      } 
4769  
4770      /**

4771       * start-element handler

4772       * 

4773       * @param string $parser XML parser object

4774       * @param string $name element name

4775       * @param string $attrs associative array of attributes

4776       * @access private 

4777       */
4778      function start_element($parser, $name, $attrs)
4779      {
4780          if ($this->status == 'schema') {
4781              $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4782              $this->appendDebug($this->currentSchema->getDebug());
4783              $this->currentSchema->clearDebug();
4784          } elseif (ereg('schema$', $name)) {
4785              $this->debug('Parsing WSDL schema');
4786              // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");

4787              $this->status = 'schema';
4788              $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
4789              $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4790              $this->appendDebug($this->currentSchema->getDebug());
4791              $this->currentSchema->clearDebug();
4792          } else {
4793              // position in the total number of elements, starting from 0

4794              $pos = $this->position++;
4795              $depth = $this->depth++; 
4796              // set self as current value for this depth

4797              $this->depth_array[$depth] = $pos;
4798              $this->message[$pos] = array('cdata' => ''); 
4799              // process attributes

4800              if (count($attrs) > 0) {
4801                  // register namespace declarations

4802                  foreach($attrs as $k => $v) {
4803                      if (ereg("^xmlns", $k)) {
4804                          if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4805                              $this->namespaces[$ns_prefix] = $v;
4806                          } else {
4807                              $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4808                          } 
4809                          if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4810                              $this->XMLSchemaVersion = $v;
4811                              $this->namespaces['xsi'] = $v . '-instance';
4812                          } 
4813                      }
4814                  }
4815                  // expand each attribute prefix to its namespace

4816                  foreach($attrs as $k => $v) {
4817                      $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4818                      if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4819                          $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4820                      } 
4821                      $eAttrs[$k] = $v;
4822                  } 
4823                  $attrs = $eAttrs;
4824              } else {
4825                  $attrs = array();
4826              } 
4827              // get element prefix, namespace and name

4828              if (ereg(':', $name)) {
4829                  // get ns prefix

4830                  $prefix = substr($name, 0, strpos($name, ':')); 
4831                  // get ns

4832                  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 
4833                  // get unqualified name

4834                  $name = substr(strstr($name, ':'), 1);
4835              } 
4836              // process attributes, expanding any prefixes to namespaces

4837              // find status, register data

4838              switch ($this->status) {
4839                  case 'message':
4840                      if ($name == 'part') {
4841                          if (isset($attrs['type'])) {
4842                              $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
4843                              $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4844                          } 
4845                          if (isset($attrs['element'])) {
4846                              $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
4847                              $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
4848                          } 
4849                      } 
4850                      break;
4851                  case 'portType':
4852                      switch ($name) {
4853                          case 'operation':
4854                              $this->currentPortOperation = $attrs['name'];
4855                              $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4856                              if (isset($attrs['parameterOrder'])) {
4857                                  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4858                              } 
4859                              break;
4860                          case 'documentation':
4861                              $this->documentation = true;
4862                              break; 
4863                          // merge input/output data

4864                          default:
4865                              $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4866                              $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4867                              break;
4868                      } 
4869                      break;
4870                  case 'binding':
4871                      switch ($name) {
4872                          case 'binding': 
4873                              // get ns prefix

4874                              if (isset($attrs['style'])) {
4875                              $this->bindings[$this->currentBinding]['prefix'] = $prefix;
4876                              } 
4877                              $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
4878                              break;
4879                          case 'header':
4880                              $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
4881                              break;
4882                          case 'operation':
4883                              if (isset($attrs['soapAction'])) {
4884                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
4885                              } 
4886                              if (isset($attrs['style'])) {
4887                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
4888                              } 
4889                              if (isset($attrs['name'])) {
4890                                  $this->currentOperation = $attrs['name'];
4891                                  $this->debug("current binding operation: $this->currentOperation");
4892                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
4893                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
4894                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
4895                              } 
4896                              break;
4897                          case 'input':
4898                              $this->opStatus = 'input';
4899                              break;
4900                          case 'output':
4901                              $this->opStatus = 'output';
4902                              break;
4903                          case 'body':
4904                              if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
4905                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
4906                              } else {
4907                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
4908                              } 
4909                              break;
4910                      } 
4911                      break;
4912                  case 'service':
4913                      switch ($name) {
4914                          case 'port':
4915                              $this->currentPort = $attrs['name'];
4916                              $this->debug('current port: ' . $this->currentPort);
4917                              $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
4918                      
4919                              break;
4920                          case 'address':
4921                              $this->ports[$this->currentPort]['location'] = $attrs['location'];
4922                              $this->ports[$this->currentPort]['bindingType'] = $namespace;
4923                              $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
4924                              $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
4925                              break;
4926                      } 
4927                      break;
4928              } 
4929          // set status

4930          switch ($name) {
4931              case 'import':
4932                  if (isset($attrs['location'])) {
4933                      $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
4934                      $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
4935                  } else {
4936                      $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
4937                      if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
4938                          $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
4939                      }
4940                      $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
4941                  }
4942                  break;
4943              //wait for schema

4944              //case 'types':

4945              //    $this->status = 'schema';

4946              //    break;

4947              case 'message':
4948                  $this->status = 'message';
4949                  $this->messages[$attrs['name']] = array();
4950                  $this->currentMessage = $attrs['name'];
4951                  break;
4952              case 'portType':
4953                  $this->status = 'portType';
4954                  $this->portTypes[$attrs['name']] = array();
4955                  $this->currentPortType = $attrs['name'];
4956                  break;
4957              case "binding":
4958                  if (isset($attrs['name'])) {
4959                  // get binding name

4960                      if (strpos($attrs['name'], ':')) {
4961                          $this->currentBinding = $this->getLocalPart($attrs['name']);
4962                      } else {
4963                          $this->currentBinding = $attrs['name'];
4964                      } 
4965                      $this->status = 'binding';
4966                      $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
4967                      $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
4968                  } 
4969                  break;
4970              case 'service':
4971                  $this->serviceName = $attrs['name'];
4972                  $this->status = 'service';
4973                  $this->debug('current service: ' . $this->serviceName);
4974                  break;
4975              case 'definitions':
4976                  foreach ($attrs as $name => $value) {
4977                      $this->wsdl_info[$name] = $value;
4978                  } 
4979                  break;
4980              } 
4981          } 
4982      } 
4983  
4984      /**

4985      * end-element handler

4986      * 

4987      * @param string $parser XML parser object

4988      * @param string $name element name

4989      * @access private 

4990      */
4991  	function end_element($parser, $name){ 
4992          // unset schema status

4993          if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
4994              $this->status = "";
4995              $this->appendDebug($this->currentSchema->getDebug());
4996              $this->currentSchema->clearDebug();
4997              $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
4998              $this->debug('Parsing WSDL schema done');
4999          } 
5000          if ($this->status == 'schema') {
5001              $this->currentSchema->schemaEndElement($parser, $name);
5002          } else {
5003              // bring depth down a notch

5004              $this->depth--;
5005          } 
5006          // end documentation

5007          if ($this->documentation) {
5008              //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.

5009              //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;

5010              $this->documentation = false;
5011          } 
5012      } 
5013  
5014      /**

5015       * element content handler

5016       * 

5017       * @param string $parser XML parser object

5018       * @param string $data element content

5019       * @access private 

5020       */
5021  	function character_data($parser, $data)
5022      {
5023          $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5024          if (isset($this->message[$pos]['cdata'])) {
5025              $this->message[$pos]['cdata'] .= $data;
5026          } 
5027          if ($this->documentation) {
5028              $this->documentation .= $data;
5029          } 
5030      } 
5031      
5032      /**

5033      * if authenticating, set user credentials here

5034      *

5035      * @param    string $username

5036      * @param    string $password

5037      * @param    string $authtype (basic|digest|certificate|ntlm)

5038      * @param    array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)

5039      * @access   public

5040      */
5041  	function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
5042          $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5043          $this->appendDebug($this->varDump($certRequest));
5044          $this->username = $username;
5045          $this->password = $password;
5046          $this->authtype = $authtype;
5047          $this->certRequest = $certRequest;
5048      }
5049      
5050  	function getBindingData($binding)
5051      {
5052          if (is_array($this->bindings[$binding])) {
5053              return $this->bindings[$binding];
5054          } 
5055      }
5056      
5057      /**

5058       * returns an assoc array of operation names => operation data

5059       * 

5060       * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)

5061       * @return array 

5062       * @access public 

5063       */
5064  	function getOperations($bindingType = 'soap') {
5065          $ops = array();
5066          if ($bindingType == 'soap') {
5067              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5068          } elseif ($bindingType == 'soap12') {
5069              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5070          }
5071          // loop thru ports

5072          foreach($this->ports as $port => $portData) {
5073              // binding type of port matches parameter

5074              if ($portData['bindingType'] == $bindingType) {
5075                  //$this->debug("getOperations for port $port");

5076                  //$this->debug("port data: " . $this->varDump($portData));

5077                  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));

5078                  // merge bindings

5079                  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
5080                      $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
5081                  }
5082              }
5083          } 
5084          return $ops;
5085      } 
5086      
5087      /**

5088       * returns an associative array of data necessary for calling an operation

5089       * 

5090       * @param string $operation name of operation

5091       * @param string $bindingType type of binding eg: soap, soap12

5092       * @return array 

5093       * @access public 

5094       */
5095  	function getOperationData($operation, $bindingType = 'soap')
5096      {
5097          if ($bindingType == 'soap') {
5098              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5099          } elseif ($bindingType == 'soap12') {
5100              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5101          }
5102          // loop thru ports

5103          foreach($this->ports as $port => $portData) {
5104              // binding type of port matches parameter

5105              if ($portData['bindingType'] == $bindingType) {
5106                  // get binding

5107                  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {

5108                  foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
5109                      // note that we could/should also check the namespace here

5110                      if ($operation == $bOperation) {
5111                          $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
5112                          return $opData;
5113                      } 
5114                  } 
5115              }
5116          } 
5117      }
5118      
5119      /**

5120       * returns an associative array of data necessary for calling an operation

5121       * 

5122       * @param string $soapAction soapAction for operation

5123       * @param string $bindingType type of binding eg: soap, soap12

5124       * @return array 

5125       * @access public 

5126       */
5127  	function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
5128          if ($bindingType == 'soap') {
5129              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5130          } elseif ($bindingType == 'soap12') {
5131              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5132          }
5133          // loop thru ports

5134          foreach($this->ports as $port => $portData) {
5135              // binding type of port matches parameter

5136              if ($portData['bindingType'] == $bindingType) {
5137                  // loop through operations for the binding

5138                  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
5139                      if ($opData['soapAction'] == $soapAction) {
5140                          return $opData;
5141                      } 
5142                  } 
5143              }
5144          } 
5145      }
5146      
5147      /**

5148      * returns an array of information about a given type

5149      * returns false if no type exists by the given name

5150      *

5151      *     typeDef = array(

5152      *     'elements' => array(), // refs to elements array

5153      *    'restrictionBase' => '',

5154      *    'phpType' => '',

5155      *    'order' => '(sequence|all)',

5156      *    'attrs' => array() // refs to attributes array

5157      *    )

5158      *

5159      * @param string $type the type

5160      * @param string $ns namespace (not prefix) of the type

5161      * @return mixed

5162      * @access public

5163      * @see nusoap_xmlschema

5164      */
5165  	function getTypeDef($type, $ns) {
5166          $this->debug("in getTypeDef: type=$type, ns=$ns");
5167          if ((! $ns) && isset($this->namespaces['tns'])) {
5168              $ns = $this->namespaces['tns'];
5169              $this->debug("in getTypeDef: type namespace forced to $ns");
5170          }
5171          if (!isset($this->schemas[$ns])) {
5172              foreach ($this->schemas as $ns0 => $schema0) {
5173                  if (strcasecmp($ns, $ns0) == 0) {
5174                      $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5175                      $ns = $ns0;
5176                      break;
5177                  }
5178              }
5179          }
5180          if (isset($this->schemas[$ns])) {
5181              $this->debug("in getTypeDef: have schema for namespace $ns");
5182              for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
5183                  $xs = &$this->schemas[$ns][$i];
5184                  $t = $xs->getTypeDef($type);
5185                  //$this->appendDebug($xs->getDebug());

5186                  //$xs->clearDebug();

5187                  if ($t) {
5188                      if (!isset($t['phpType'])) {
5189                          // get info for type to tack onto the element

5190                          $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5191                          $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
5192                          $etype = $this->getTypeDef($uqType, $ns);
5193                          if ($etype) {
5194                              $this->debug("found type for [element] $type:");
5195                              $this->debug($this->varDump($etype));
5196                              if (isset($etype['phpType'])) {
5197                                  $t['phpType'] = $etype['phpType'];
5198                              }
5199                              if (isset($etype['elements'])) {
5200                                  $t['elements'] = $etype['elements'];
5201                              }
5202                              if (isset($etype['attrs'])) {
5203                                  $t['attrs'] = $etype['attrs'];
5204                              }
5205                          }
5206                      }
5207                      return $t;
5208                  }
5209              }
5210          } else {
5211              $this->debug("in getTypeDef: do not have schema for namespace $ns");
5212          }
5213          return false;
5214      }
5215  
5216      /**

5217      * prints html description of services

5218      *

5219      * @access private

5220      */
5221      function webDescription(){
5222          global $HTTP_SERVER_VARS;
5223  
5224          if (isset($_SERVER)) {
5225              $PHP_SELF = $_SERVER['PHP_SELF'];
5226          } elseif (isset($HTTP_SERVER_VARS)) {
5227              $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5228          } else {
5229              $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5230          }
5231  
5232          $b = '
5233          <html><head><title>NuSOAP: '.$this->serviceName.'</title>
5234          <style type="text/css">
5235              body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
5236              p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
5237              pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5238              ul      { margin-top: 10px; margin-left: 20px; }
5239              li      { list-style-type: none; margin-top: 10px; color: #000000; }
5240              .content{
5241              margin-left: 0px; padding-bottom: 2em; }
5242              .nav {
5243              padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5244              margin-top: 10px; margin-left: 0px; color: #000000;
5245              background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5246              .title {
5247              font-family: arial; font-size: 26px; color: #ffffff;
5248              background-color: #999999; width: 105%; margin-left: 0px;
5249              padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
5250              .hidden {
5251              position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5252              font-family: arial; overflow: hidden; width: 600;
5253              padding: 20px; font-size: 10px; background-color: #999999;
5254              layer-background-color:#FFFFFF; }
5255              a,a:active  { color: charcoal; font-weight: bold; }
5256              a:visited   { color: #666666; font-weight: bold; }
5257              a:hover     { color: cc3300; font-weight: bold; }
5258          </style>
5259          <script language="JavaScript" type="text/javascript">
5260          <!--
5261          // POP-UP CAPTIONS...

5262  		function lib_bwcheck(){ //Browsercheck (needed)
5263              this.ver=navigator.appVersion
5264              this.agent=navigator.userAgent
5265              this.dom=document.getElementById?1:0
5266              this.opera5=this.agent.indexOf("Opera 5")>-1
5267              this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5268              this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5269              this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5270              this.ie=this.ie4||this.ie5||this.ie6
5271              this.mac=this.agent.indexOf("Mac")>-1
5272              this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5273              this.ns4=(document.layers && !this.dom)?1:0;
5274              this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5275              return this
5276          }
5277          var bw = new lib_bwcheck()
5278          //Makes crossbrowser object.

5279  		function makeObj(obj){
5280              this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5281              if(!this.evnt) return false
5282              this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5283              this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5284              this.writeIt=b_writeIt;
5285              return this
5286          }
5287          // A unit of measure that will be added when setting the position of a layer.

5288          //var px = bw.ns4||window.opera?"":"px";

5289  		function b_writeIt(text){
5290              if (bw.ns4){this.wref.write(text);this.wref.close()}
5291              else this.wref.innerHTML = text
5292          }
5293          //Shows the messages

5294          var oDesc;
5295  		function popup(divid){
5296              if(oDesc = new makeObj(divid)){
5297              oDesc.css.visibility = "visible"
5298              }
5299          }
5300  		function popout(){ // Hides message
5301              if(oDesc) oDesc.css.visibility = "hidden"
5302          }
5303          //-->

5304          </script>
5305          </head>
5306          <body>
5307          <div class=content>
5308              <br><br>
5309              <div class=title>'.$this->serviceName.'</div>
5310              <div class=nav>
5311                  <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
5312                  Click on an operation name to view it&apos;s details.</p>
5313                  <ul>';
5314                  foreach($this->getOperations() as $op => $data){
5315                      $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5316                      // create hidden div

5317                      $b .= "<div id='$op' class='hidden'>
5318                      <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
5319                      foreach($data as $donnie => $marie){ // loop through opdata
5320                          if($donnie == 'input' || $donnie == 'output'){ // show input/output data
5321                              $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
5322                              foreach($marie as $captain => $tenille){ // loop through data
5323                                  if($captain == 'parts'){ // loop thru parts
5324                                      $b .= "&nbsp;&nbsp;$captain:<br>";
5325                                      //if(is_array($tenille)){

5326                                          foreach($tenille as $joanie => $chachi){
5327                                              $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5328                                          }
5329                                      //}

5330                                  } else {
5331                                      $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5332                                  }
5333                              }
5334                          } else {
5335                              $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
5336                          }
5337                      }
5338                      $b .= '</div>';
5339                  }
5340                  $b .= '
5341                  <ul>
5342              </div>
5343          </div></body></html>';
5344          return $b;
5345      }
5346  
5347      /**

5348      * serialize the parsed wsdl

5349      *

5350      * @param mixed $debug whether to put debug=1 in endpoint URL

5351      * @return string serialization of WSDL

5352      * @access public 

5353      */
5354  	function serialize($debug = 0)
5355      {
5356          $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5357          $xml .= "\n<definitions";
5358          foreach($this->namespaces as $k => $v) {
5359              $xml .= " xmlns:$k=\"$v\"";
5360          } 
5361          // 10.9.02 - add poulter fix for wsdl and tns declarations

5362          if (isset($this->namespaces['wsdl'])) {
5363              $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5364          } 
5365          if (isset($this->namespaces['tns'])) {
5366              $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5367          } 
5368          $xml .= '>'; 
5369          // imports

5370          if (sizeof($this->import) > 0) {
5371              foreach($this->import as $ns => $list) {
5372                  foreach ($list as $ii) {
5373                      if ($ii['location'] != '') {
5374                          $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5375                      } else {
5376                          $xml .= '<import namespace="' . $ns . '" />';
5377                      }
5378                  }
5379              } 
5380          } 
5381          // types

5382          if (count($this->schemas)>=1) {
5383              $xml .= "\n<types>\n";
5384              foreach ($this->schemas as $ns => $list) {
5385                  foreach ($list as $xs) {
5386                      $xml .= $xs->serializeSchema();
5387                  }
5388              }
5389              $xml .= '</types>';
5390          } 
5391          // messages

5392          if (count($this->messages) >= 1) {
5393              foreach($this->messages as $msgName => $msgParts) {
5394                  $xml .= "\n<message name=\"" . $msgName . '">';
5395                  if(is_array($msgParts)){
5396                      foreach($msgParts as $partName => $partType) {
5397                          // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';

5398                          if (strpos($partType, ':')) {
5399                              $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
5400                          } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5401                              // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';

5402                              $typePrefix = 'xsd';
5403                          } else {
5404                              foreach($this->typemap as $ns => $types) {
5405                                  if (isset($types[$partType])) {
5406                                      $typePrefix = $this->getPrefixFromNamespace($ns);
5407                                  } 
5408                              } 
5409                              if (!isset($typePrefix)) {
5410                                  die("$partType has no namespace!");
5411                              } 
5412                          }
5413                          $ns = $this->getNamespaceFromPrefix($typePrefix);
5414                          $localPart = $this->getLocalPart($partType);
5415                          $typeDef = $this->getTypeDef($localPart, $ns);
5416                          if ($typeDef['typeClass'] == 'element') {
5417                              $elementortype = 'element';
5418                              if (substr($localPart, -1) == '^') {
5419                                  $localPart = substr($localPart, 0, -1);
5420                              }
5421                          } else {
5422                              $elementortype = 'type';
5423                          }
5424                          $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5425                      }
5426                  }
5427                  $xml .= '</message>';
5428              } 
5429          } 
5430          // bindings & porttypes

5431          if (count($this->bindings) >= 1) {
5432              $binding_xml = '';
5433              $portType_xml = '';
5434              foreach($this->bindings as $bindingName => $attrs) {
5435                  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5436                  $binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5437                  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5438                  foreach($attrs['operations'] as $opName => $opParts) {
5439                      $binding_xml .= "\n" . '  <operation name="' . $opName . '">';
5440                      $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
5441                      if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
5442                          $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5443                      } else {
5444                          $enc_style = '';
5445                      }
5446                      $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5447                      if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
5448                          $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5449                      } else {
5450                          $enc_style = '';
5451                      }
5452                      $binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5453                      $binding_xml .= "\n" . '  </operation>';
5454                      $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
5455                      if (isset($opParts['parameterOrder'])) {
5456                          $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5457                      } 
5458                      $portType_xml .= '>';
5459                      if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
5460                          $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5461                      }
5462                      $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';
5463                      $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';
5464                      $portType_xml .= "\n" . '  </operation>';
5465                  } 
5466                  $portType_xml .= "\n" . '</portType>';
5467                  $binding_xml .= "\n" . '</binding>';
5468              } 
5469              $xml .= $portType_xml . $binding_xml;
5470          } 
5471          // services

5472          $xml .= "\n<service name=\"" . $this->serviceName . '">';
5473          if (count($this->ports) >= 1) {
5474              foreach($this->ports as $pName => $attrs) {
5475                  $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5476                  $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5477                  $xml .= "\n" . '  </port>';
5478              } 
5479          } 
5480          $xml .= "\n" . '</service>';
5481          return $xml . "\n</definitions>";
5482      } 
5483  
5484      /**

5485       * determine whether a set of parameters are unwrapped

5486       * when they are expect to be wrapped, Microsoft-style.

5487       *

5488       * @param string $type the type (element name) of the wrapper

5489       * @param array $parameters the parameter values for the SOAP call

5490       * @return boolean whether they parameters are unwrapped (and should be wrapped)

5491       * @access private

5492       */
5493  	function parametersMatchWrapped($type, &$parameters) {
5494          $this->debug("in parametersMatchWrapped type=$type, parameters=");
5495          $this->appendDebug($this->varDump($parameters));
5496  
5497          // split type into namespace:unqualified-type

5498          if (strpos($type, ':')) {
5499              $uqType = substr($type, strrpos($type, ':') + 1);
5500              $ns = substr($type, 0, strrpos($type, ':'));
5501              $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5502              if ($this->getNamespaceFromPrefix($ns)) {
5503                  $ns = $this->getNamespaceFromPrefix($ns);
5504                  $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5505              }
5506          } else {
5507              // TODO: should the type be compared to types in XSD, and the namespace

5508              // set to XSD if the type matches?

5509              $this->debug("in parametersMatchWrapped: No namespace for type $type");
5510              $ns = '';
5511              $uqType = $type;
5512          }
5513  
5514          // get the type information

5515          if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5516              $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5517              return false;
5518          }
5519          $this->debug("in parametersMatchWrapped: found typeDef=");
5520          $this->appendDebug($this->varDump($typeDef));
5521          if (substr($uqType, -1) == '^') {
5522              $uqType = substr($uqType, 0, -1);
5523          }
5524          $phpType = $typeDef['phpType'];
5525          $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5526          $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5527          
5528          // we expect a complexType or element of complexType

5529          if ($phpType != 'struct') {
5530              $this->debug("in parametersMatchWrapped: not a struct");
5531              return false;
5532          }
5533  
5534          // see whether the parameter names match the elements

5535          if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5536              $elements = 0;
5537              $matches = 0;
5538              $change = false;
5539              if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
5540                  $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
5541                  $change = true;
5542              }
5543              foreach ($typeDef['elements'] as $name => $attrs) {
5544                  if ($change) {
5545                      $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
5546                      $parameters[$name] = $parameters[$elements];
5547                      unset($parameters[$elements]);
5548                      $matches++;
5549                  } elseif (isset($parameters[$name])) {
5550                      $this->debug("in parametersMatchWrapped: have parameter named $name");
5551                      $matches++;
5552                  } else {
5553                      $this->debug("in parametersMatchWrapped: do not have parameter named $name");
5554                  }
5555                  $elements++;
5556              }
5557  
5558              $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
5559              if ($matches == 0) {
5560                  return false;
5561              }
5562              return true;
5563          }
5564  
5565          // since there are no elements for the type, if the user passed no

5566          // parameters, the parameters match wrapped.

5567          $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
5568          return count($parameters) == 0;
5569      }
5570  
5571      /**

5572       * serialize PHP values according to a WSDL message definition

5573       * contrary to the method name, this is not limited to RPC

5574       *

5575       * TODO

5576       * - multi-ref serialization

5577       * - validate PHP values against type definitions, return errors if invalid

5578       * 

5579       * @param string $operation operation name

5580       * @param string $direction (input|output)

5581       * @param mixed $parameters parameter value(s)

5582       * @param string $bindingType (soap|soap12)

5583       * @return mixed parameters serialized as XML or false on error (e.g. operation not found)

5584       * @access public

5585       */
5586  	function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
5587          $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
5588          $this->appendDebug('parameters=' . $this->varDump($parameters));
5589          
5590          if ($direction != 'input' && $direction != 'output') {
5591              $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5592              $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5593              return false;
5594          } 
5595          if (!$opData = $this->getOperationData($operation, $bindingType)) {
5596              $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5597              $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
5598              return false;
5599          }
5600          $this->debug('in serializeRPCParameters: opData:');
5601          $this->appendDebug($this->varDump($opData));
5602  
5603          // Get encoding style for output and set to current

5604          $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5605          if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5606              $encodingStyle = $opData['output']['encodingStyle'];
5607              $enc_style = $encodingStyle;
5608          }
5609  
5610          // set input params

5611          $xml = '';
5612          if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5613              $parts = &$opData[$direction]['parts'];
5614              $part_count = sizeof($parts);
5615              $style = $opData['style'];
5616              $use = $opData[$direction]['use'];
5617              $this->debug("have $part_count part(s) to serialize using $style/$use");
5618              if (is_array($parameters)) {
5619                  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5620                  $parameter_count = count($parameters);
5621                  $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
5622                  // check for Microsoft-style wrapped parameters

5623                  if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
5624                      $this->debug('check whether the caller has wrapped the parameters');
5625                      if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
5626                          $this->debug('check whether caller\'s parameters match the wrapped ones');
5627                          if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
5628                              $this->debug('wrap the parameters for the caller');
5629                              $parameters = array('parameters' => $parameters);
5630                              $parameter_count = 1;
5631                          }
5632                      }
5633                  }
5634                  foreach ($parts as $name => $type) {
5635                      $this->debug("serializing part $name of type $type");
5636                      // Track encoding style

5637                      if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5638                          $encodingStyle = $opData[$direction]['encodingStyle'];            
5639                          $enc_style = $encodingStyle;
5640                      } else {
5641                          $enc_style = false;
5642                      }
5643                      // NOTE: add error handling here

5644                      // if serializeType returns false, then catch global error and fault

5645                      if ($parametersArrayType == 'arraySimple') {
5646                          $p = array_shift($parameters);
5647                          $this->debug('calling serializeType w/indexed param');
5648                          $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5649                      } elseif (isset($parameters[$name])) {
5650                          $this->debug('calling serializeType w/named param');
5651                          $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5652                      } else {
5653                          // TODO: only send nillable

5654                          $this->debug('calling serializeType w/null param');
5655                          $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5656                      }
5657                  }
5658              } else {
5659                  $this->debug('no parameters passed.');
5660              }
5661          }
5662          $this->debug("serializeRPCParameters returning: $xml");
5663          return $xml;
5664      } 
5665      
5666      /**

5667       * serialize a PHP value according to a WSDL message definition

5668       * 

5669       * TODO

5670       * - multi-ref serialization

5671       * - validate PHP values against type definitions, return errors if invalid

5672       * 

5673       * @param string $operation operation name

5674       * @param string $direction (input|output)

5675       * @param mixed $parameters parameter value(s)

5676       * @return mixed parameters serialized as XML or false on error (e.g. operation not found)

5677       * @access public

5678       * @deprecated

5679       */
5680  	function serializeParameters($operation, $direction, $parameters)
5681      {
5682          $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 
5683          $this->appendDebug('parameters=' . $this->varDump($parameters));
5684          
5685          if ($direction != 'input' && $direction != 'output') {
5686              $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5687              $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5688              return false;
5689          } 
5690          if (!$opData = $this->getOperationData($operation)) {
5691              $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5692              $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5693              return false;
5694          }
5695          $this->debug('opData:');
5696          $this->appendDebug($this->varDump($opData));
5697          
5698          // Get encoding style for output and set to current

5699          $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5700          if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5701              $encodingStyle = $opData['output']['encodingStyle'];
5702              $enc_style = $encodingStyle;
5703          }
5704          
5705          // set input params

5706          $xml = '';
5707          if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5708              
5709              $use = $opData[$direction]['use'];
5710              $this->debug("use=$use");
5711              $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5712              if (is_array($parameters)) {
5713                  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5714                  $this->debug('have ' . $parametersArrayType . ' parameters');
5715                  foreach($opData[$direction]['parts'] as $name => $type) {
5716                      $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5717                      // Track encoding style

5718                      if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5719                          $encodingStyle = $opData[$direction]['encodingStyle'];            
5720                          $enc_style = $encodingStyle;
5721                      } else {
5722                          $enc_style = false;
5723                      }
5724                      // NOTE: add error handling here

5725                      // if serializeType returns false, then catch global error and fault

5726                      if ($parametersArrayType == 'arraySimple') {
5727                          $p = array_shift($parameters);
5728                          $this->debug('calling serializeType w/indexed param');
5729                          $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5730                      } elseif (isset($parameters[$name])) {
5731                          $this->debug('calling serializeType w/named param');
5732                          $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5733                      } else {
5734                          // TODO: only send nillable

5735                          $this->debug('calling serializeType w/null param');
5736                          $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5737                      }
5738                  }
5739              } else {
5740                  $this->debug('no parameters passed.');
5741              }
5742          }
5743          $this->debug("serializeParameters returning: $xml");
5744          return $xml;
5745      } 
5746      
5747      /**

5748       * serializes a PHP value according a given type definition

5749       * 

5750       * @param string $name name of value (part or element)

5751       * @param string $type XML schema type of value (type or element)

5752       * @param mixed $value a native PHP value (parameter value)

5753       * @param string $use use for part (encoded|literal)

5754       * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)

5755       * @param boolean $unqualified a kludge for what should be XML namespace form handling

5756       * @return string value serialized as an XML string

5757       * @access private

5758       */
5759  	function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
5760      {
5761          $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5762          $this->appendDebug("value=" . $this->varDump($value));
5763          if($use == 'encoded' && $encodingStyle) {
5764              $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5765          }
5766  
5767          // if a soapval has been supplied, let its type override the WSDL

5768          if (is_object($value) && get_class($value) == 'soapval') {
5769              if ($value->type_ns) {
5770                  $type = $value->type_ns . ':' . $value->type;
5771                  $forceType = true;
5772                  $this->debug("in serializeType: soapval overrides type to $type");
5773              } elseif ($value->type) {
5774                  $type = $value->type;
5775                  $forceType = true;
5776                  $this->debug("in serializeType: soapval overrides type to $type");
5777              } else {
5778                  $forceType = false;
5779                  $this->debug("in serializeType: soapval does not override type");
5780              }
5781              $attrs = $value->attributes;
5782              $value = $value->value;
5783              $this->debug("in serializeType: soapval overrides value to $value");
5784              if ($attrs) {
5785                  if (!is_array($value)) {
5786                      $value['!'] = $value;
5787                  }
5788                  foreach ($attrs as $n => $v) {
5789                      $value['!' . $n] = $v;
5790                  }
5791                  $this->debug("in serializeType: soapval provides attributes");
5792              }
5793          } else {
5794              $forceType = false;
5795          }
5796  
5797          $xml = '';
5798          if (strpos($type, ':')) {
5799              $uqType = substr($type, strrpos($type, ':') + 1);
5800              $ns = substr($type, 0, strrpos($type, ':'));
5801              $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5802              if ($this->getNamespaceFromPrefix($ns)) {
5803                  $ns = $this->getNamespaceFromPrefix($ns);
5804                  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5805              }
5806  
5807              if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
5808                  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5809                  if ($unqualified && $use == 'literal') {
5810                      $elementNS = " xmlns=\"\"";
5811                  } else {
5812                      $elementNS = '';
5813                  }
5814                  if (is_null($value)) {
5815                      if ($use == 'literal') {
5816                          // TODO: depends on minOccurs

5817                          $xml = "<$name$elementNS/>";
5818                      } else {
5819                          // TODO: depends on nillable, which should be checked before calling this method

5820                          $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5821                      }
5822                      $this->debug("in serializeType: returning: $xml");
5823                      return $xml;
5824                  }
5825                  if ($uqType == 'Array') {
5826                      // JBoss/Axis does this sometimes

5827                      return $this->serialize_val($value, $name, false, false, false, false, $use);
5828                  }
5829                  if ($uqType == 'boolean') {
5830                      if ((is_string($value) && $value == 'false') || (! $value)) {
5831                          $value = 'false';
5832                      } else {
5833                          $value = 'true';
5834                      }
5835                  } 
5836                  if ($uqType == 'string' && gettype($value) == 'string') {
5837                      $value = $this->expandEntities($value);
5838                  }
5839                  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5840                      $value = sprintf("%.0lf", $value);
5841                  }
5842                  // it's a scalar

5843                  // TODO: what about null/nil values?

5844                  // check type isn't a custom type extending xmlschema namespace

5845                  if (!$this->getTypeDef($uqType, $ns)) {
5846                      if ($use == 'literal') {
5847                          if ($forceType) {
5848                              $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5849                          } else {
5850                              $xml = "<$name$elementNS>$value</$name>";
5851                          }
5852                      } else {
5853                          $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5854                      }
5855                      $this->debug("in serializeType: returning: $xml");
5856                      return $xml;
5857                  }
5858                  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
5859              } else if ($ns == 'http://xml.apache.org/xml-soap') {
5860                  $this->debug('in serializeType: appears to be Apache SOAP type');
5861                  if ($uqType == 'Map') {
5862                      $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5863                      if (! $tt_prefix) {
5864                          $this->debug('in serializeType: Add namespace for Apache SOAP type');
5865                          $tt_prefix = 'ns' . rand(1000, 9999);
5866                          $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
5867                          // force this to be added to usedNamespaces

5868                          $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5869                      }
5870                      $contents = '';
5871                      foreach($value as $k => $v) {
5872                          $this->debug("serializing map element: key $k, value $v");
5873                          $contents .= '<item>';
5874                          $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
5875                          $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
5876                          $contents .= '</item>';
5877                      }
5878                      if ($use == 'literal') {
5879                          if ($forceType) {
5880                              $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
5881                          } else {
5882                              $xml = "<$name>$contents</$name>";
5883                          }
5884                      } else {
5885                          $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
5886                      }
5887                      $this->debug("in serializeType: returning: $xml");
5888                      return $xml;
5889                  }
5890                  $this->debug('in serializeType: Apache SOAP type, but only support Map');
5891              }
5892          } else {
5893              // TODO: should the type be compared to types in XSD, and the namespace

5894              // set to XSD if the type matches?

5895              $this->debug("in serializeType: No namespace for type $type");
5896              $ns = '';
5897              $uqType = $type;
5898          }
5899          if(!$typeDef = $this->getTypeDef($uqType, $ns)){
5900              $this->setError("$type ($uqType) is not a supported type.");
5901              $this->debug("in serializeType: $type ($uqType) is not a supported type.");
5902              return false;
5903          } else {
5904              $this->debug("in serializeType: found typeDef");
5905              $this->appendDebug('typeDef=' . $this->varDump($typeDef));
5906              if (substr($uqType, -1) == '^') {
5907                  $uqType = substr($uqType, 0, -1);
5908              }
5909          }
5910          $phpType = $typeDef['phpType'];
5911          $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 
5912          // if php type == struct, map value to the <all> element names

5913          if ($phpType == 'struct') {
5914              if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
5915                  $elementName = $uqType;
5916                  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5917                      $elementNS = " xmlns=\"$ns\"";
5918                  } else {
5919                      $elementNS = " xmlns=\"\"";
5920                  }
5921              } else {
5922                  $elementName = $name;
5923                  if ($unqualified) {
5924                      $elementNS = " xmlns=\"\"";
5925                  } else {
5926                      $elementNS = '';
5927                  }
5928              }
5929              if (is_null($value)) {
5930                  if ($use == 'literal') {
5931                      // TODO: depends on minOccurs

5932                      $xml = "<$elementName$elementNS/>";
5933                  } else {
5934                      $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5935                  }
5936                  $this->debug("in serializeType: returning: $xml");
5937                  return $xml;
5938              }
5939              if (is_object($value)) {
5940                  $value = get_object_vars($value);
5941              }
5942              if (is_array($value)) {
5943                  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
5944                  if ($use == 'literal') {
5945                      if ($forceType) {
5946                          $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
5947                      } else {
5948                          $xml = "<$elementName$elementNS$elementAttrs>";
5949                      }
5950                  } else {
5951                      $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
5952                  }
5953      
5954                  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
5955                  $xml .= "</$elementName>";
5956              } else {
5957                  $this->debug("in serializeType: phpType is struct, but value is not an array");
5958                  $this->setError("phpType is struct, but value is not an array: see debug output for details");
5959                  $xml = '';
5960              }
5961          } elseif ($phpType == 'array') {
5962              if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5963                  $elementNS = " xmlns=\"$ns\"";
5964              } else {
5965                  if ($unqualified) {
5966                      $elementNS = " xmlns=\"\"";
5967                  } else {
5968                      $elementNS = '';
5969                  }
5970              }
5971              if (is_null($value)) {
5972                  if ($use == 'literal') {
5973                      // TODO: depends on minOccurs

5974                      $xml = "<$name$elementNS/>";
5975                  } else {
5976                      $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
5977                          $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5978                          ":Array\" " .
5979                          $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5980                          ':arrayType="' .
5981                          $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
5982                          ':' .
5983                          $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
5984                  }
5985                  $this->debug("in serializeType: returning: $xml");
5986                  return $xml;
5987              }
5988              if (isset($typeDef['multidimensional'])) {
5989                  $nv = array();
5990                  foreach($value as $v) {
5991                      $cols = ',' . sizeof($v);
5992                      $nv = array_merge($nv, $v);
5993                  } 
5994                  $value = $nv;
5995              } else {
5996                  $cols = '';
5997              } 
5998              if (is_array($value) && sizeof($value) >= 1) {
5999                  $rows = sizeof($value);
6000                  $contents = '';
6001                  foreach($value as $k => $v) {
6002                      $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6003                      //if (strpos($typeDef['arrayType'], ':') ) {

6004                      if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6005                          $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6006                      } else {
6007                          $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6008                      } 
6009                  }
6010              } else {
6011                  $rows = 0;
6012                  $contents = null;
6013              }
6014              // TODO: for now, an empty value will be serialized as a zero element

6015              // array.  Revisit this when coding the handling of null/nil values.

6016              if ($use == 'literal') {
6017                  $xml = "<$name$elementNS>"
6018                      .$contents
6019                      ."</$name>";
6020              } else {
6021                  $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
6022                      $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6023                      .':arrayType="'
6024                      .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
6025                      .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
6026                      .$contents
6027                      ."</$name>";
6028              }
6029          } elseif ($phpType == 'scalar') {
6030              if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
6031                  $elementNS = " xmlns=\"$ns\"";
6032              } else {
6033                  if ($unqualified) {
6034                      $elementNS = " xmlns=\"\"";
6035                  } else {
6036                      $elementNS = '';
6037                  }
6038              }
6039              if ($use == 'literal') {
6040                  if ($forceType) {
6041                      $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6042                  } else {
6043                      $xml = "<$name$elementNS>$value</$name>";
6044                  }
6045              } else {
6046                  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6047              }
6048          }
6049          $this->debug("in serializeType: returning: $xml");
6050          return $xml;
6051      }
6052      
6053      /**

6054       * serializes the attributes for a complexType

6055       *

6056       * @param array $typeDef our internal representation of an XML schema type (or element)

6057       * @param mixed $value a native PHP value (parameter value)

6058       * @param string $ns the namespace of the type

6059       * @param string $uqType the local part of the type

6060       * @return string value serialized as an XML string

6061       * @access private

6062       */
6063  	function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
6064          $xml = '';
6065          if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6066              $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6067              if (is_array($value)) {
6068                  $xvalue = $value;
6069              } elseif (is_object($value)) {
6070                  $xvalue = get_object_vars($value);
6071              } else {
6072                  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6073                  $xvalue = array();
6074              }
6075              foreach ($typeDef['attrs'] as $aName => $attrs) {
6076                  if (isset($xvalue['!' . $aName])) {
6077                      $xname = '!' . $aName;
6078                      $this->debug("value provided for attribute $aName with key $xname");
6079                  } elseif (isset($xvalue[$aName])) {
6080                      $xname = $aName;
6081                      $this->debug("value provided for attribute $aName with key $xname");
6082                  } elseif (isset($attrs['default'])) {
6083                      $xname = '!' . $aName;
6084                      $xvalue[$xname] = $attrs['default'];
6085                      $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6086                  } else {
6087                      $xname = '';
6088                      $this->debug("no value provided for attribute $aName");
6089                  }
6090                  if ($xname) {
6091                      $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6092                  }
6093              } 
6094          } else {
6095              $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6096          }
6097          if (isset($typeDef['extensionBase'])) {
6098              $ns = $this->getPrefix($typeDef['extensionBase']);
6099              $uqType = $this->getLocalPart($typeDef['extensionBase']);
6100              if ($this->getNamespaceFromPrefix($ns)) {
6101                  $ns = $this->getNamespaceFromPrefix($ns);
6102              }
6103              if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6104                  $this->debug("serialize attributes for extension base $ns:$uqType");
6105                  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6106              } else {
6107                  $this->debug("extension base $ns:$uqType is not a supported type");
6108              }
6109          }
6110          return $xml;
6111      }
6112  
6113      /**

6114       * serializes the elements for a complexType

6115       *

6116       * @param array $typeDef our internal representation of an XML schema type (or element)

6117       * @param mixed $value a native PHP value (parameter value)

6118       * @param string $ns the namespace of the type

6119       * @param string $uqType the local part of the type

6120       * @param string $use use for part (encoded|literal)

6121       * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)

6122       * @return string value serialized as an XML string

6123       * @access private

6124       */
6125  	function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
6126          $xml = '';
6127          if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6128              $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6129              if (is_array($value)) {
6130                  $xvalue = $value;
6131              } elseif (is_object($value)) {
6132                  $xvalue = get_object_vars($value);
6133              } else {
6134                  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6135                  $xvalue = array();
6136              }
6137              // toggle whether all elements are present - ideally should validate against schema

6138              if (count($typeDef['elements']) != count($xvalue)){
6139                  $optionals = true;
6140              }
6141              foreach ($typeDef['elements'] as $eName => $attrs) {
6142                  if (!isset($xvalue[$eName])) {
6143                      if (isset($attrs['default'])) {
6144                          $xvalue[$eName] = $attrs['default'];
6145                          $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6146                      }
6147                  }
6148                  // if user took advantage of a minOccurs=0, then only serialize named parameters

6149                  if (isset($optionals)
6150                      && (!isset($xvalue[$eName])) 
6151                      && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
6152                      ){
6153                      if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6154                          $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6155                      }
6156                      // do nothing

6157                      $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6158                  } else {
6159                      // get value

6160                      if (isset($xvalue[$eName])) {
6161                          $v = $xvalue[$eName];
6162                      } else {
6163                          $v = null;
6164                      }
6165                      if (isset($attrs['form'])) {
6166                          $unqualified = ($attrs['form'] == 'unqualified');
6167                      } else {
6168                          $unqualified = false;
6169                      }
6170                      if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
6171                          $vv = $v;
6172                          foreach ($vv as $k => $v) {
6173                              if (isset($attrs['type']) || isset($attrs['ref'])) {
6174                                  // serialize schema-defined type

6175                                  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6176                              } else {
6177                                  // serialize generic type (can this ever really happen?)

6178                                  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6179                                  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6180                              }
6181                          }
6182                      } else {
6183                          if (isset($attrs['type']) || isset($attrs['ref'])) {
6184                              // serialize schema-defined type

6185                              $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6186                          } else {
6187                              // serialize generic type (can this ever really happen?)

6188                              $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6189                              $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6190                          }
6191                      }
6192                  }
6193              } 
6194          } else {
6195              $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6196          }
6197          if (isset($typeDef['extensionBase'])) {
6198              $ns = $this->getPrefix($typeDef['extensionBase']);
6199              $uqType = $this->getLocalPart($typeDef['extensionBase']);
6200              if ($this->getNamespaceFromPrefix($ns)) {
6201                  $ns = $this->getNamespaceFromPrefix($ns);
6202              }
6203              if ($typeDef = $this->getTypeDef($uqType, $ns)) {
6204                  $this->debug("serialize elements for extension base $ns:$uqType");
6205                  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6206              } else {
6207                  $this->debug("extension base $ns:$uqType is not a supported type");
6208              }
6209          }
6210          return $xml;
6211      }
6212  
6213      /**

6214      * adds an XML Schema complex type to the WSDL types

6215      *

6216      * @param string    $name

6217      * @param string $typeClass (complexType|simpleType|attribute)

6218      * @param string $phpType currently supported are array and struct (php assoc array)

6219      * @param string $compositor (all|sequence|choice)

6220      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)

6221      * @param array $elements e.g. array ( name => array(name=>'',type=>'') )

6222      * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))

6223      * @param string $arrayType as namespace:name (xsd:string)

6224      * @see nusoap_xmlschema

6225      * @access public

6226      */
6227  	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
6228          if (count($elements) > 0) {
6229              $eElements = array();
6230              foreach($elements as $n => $e){
6231                  // expand each element

6232                  $ee = array();
6233                  foreach ($e as $k => $v) {
6234                      $k = strpos($k,':') ? $this->expandQname($k) : $k;
6235                      $v = strpos($v,':') ? $this->expandQname($v) : $v;
6236                      $ee[$k] = $v;
6237                  }
6238                  $eElements[$n] = $ee;
6239              }
6240              $elements = $eElements;
6241          }
6242          
6243          if (count($attrs) > 0) {
6244              foreach($attrs as $n => $a){
6245                  // expand each attribute

6246                  foreach ($a as $k => $v) {
6247                      $k = strpos($k,':') ? $this->expandQname($k) : $k;
6248                      $v = strpos($v,':') ? $this->expandQname($v) : $v;
6249                      $aa[$k] = $v;
6250                  }
6251                  $eAttrs[$n] = $aa;
6252              }
6253              $attrs = $eAttrs;
6254          }
6255  
6256          $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6257          $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
6258  
6259          $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6260          $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
6261      }
6262  
6263      /**

6264      * adds an XML Schema simple type to the WSDL types

6265      *

6266      * @param string $name

6267      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)

6268      * @param string $typeClass (should always be simpleType)

6269      * @param string $phpType (should always be scalar)

6270      * @param array $enumeration array of values

6271      * @see nusoap_xmlschema

6272      * @access public

6273      */
6274  	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
6275          $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6276  
6277          $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6278          $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6279      }
6280  
6281      /**

6282      * adds an element to the WSDL types

6283      *

6284      * @param array $attrs attributes that must include name and type

6285      * @see nusoap_xmlschema

6286      * @access public

6287      */
6288  	function addElement($attrs) {
6289          $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6290          $this->schemas[$typens][0]->addElement($attrs);
6291      }
6292  
6293      /**

6294      * register an operation with the server

6295      * 

6296      * @param string $name operation (method) name

6297      * @param array $in assoc array of input values: key = param name, value = param type

6298      * @param array $out assoc array of output values: key = param name, value = param type

6299      * @param string $namespace optional The namespace for the operation

6300      * @param string $soapaction optional The soapaction for the operation

6301      * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically

6302      * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)

6303      * @param string $documentation optional The description to include in the WSDL

6304      * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)

6305      * @access public 

6306      */
6307  	function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
6308          if ($use == 'encoded' && $encodingStyle == '') {
6309              $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6310          }
6311  
6312          if ($style == 'document') {
6313              $elements = array();
6314              foreach ($in as $n => $t) {
6315                  $elements[$n] = array('name' => $n, 'type' => $t);
6316              }
6317              $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6318              $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6319              $in = array('parameters' => 'tns:' . $name . '^');
6320  
6321              $elements = array();
6322              foreach ($out as $n => $t) {
6323                  $elements[$n] = array('name' => $n, 'type' => $t);
6324              }
6325              $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6326              $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
6327              $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6328          }
6329  
6330          // get binding

6331          $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
6332          array(
6333          'name' => $name,
6334          'binding' => $this->serviceName . 'Binding',
6335          'endpoint' => $this->endpoint,
6336          'soapAction' => $soapaction,
6337          'style' => $style,
6338          'input' => array(
6339              'use' => $use,
6340              'namespace' => $namespace,
6341              'encodingStyle' => $encodingStyle,
6342              'message' => $name . 'Request',
6343              'parts' => $in),
6344          'output' => array(
6345              'use' => $use,
6346              'namespace' => $namespace,
6347              'encodingStyle' => $encodingStyle,
6348              'message' => $name . 'Response',
6349              'parts' => $out),
6350          'namespace' => $namespace,
6351          'transport' => 'http://schemas.xmlsoap.org/soap/http',
6352          'documentation' => $documentation); 
6353          // add portTypes

6354          // add messages

6355          if($in)
6356          {
6357              foreach($in as $pName => $pType)
6358              {
6359                  if(strpos($pType,':')) {
6360                      $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6361                  }
6362                  $this->messages[$name.'Request'][$pName] = $pType;
6363              }
6364          } else {
6365              $this->messages[$name.'Request']= '0';
6366          }
6367          if($out)
6368          {
6369              foreach($out as $pName => $pType)
6370              {
6371                  if(strpos($pType,':')) {
6372                      $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
6373                  }
6374                  $this->messages[$name.'Response'][$pName] = $pType;
6375              }
6376          } else {
6377              $this->messages[$name.'Response']= '0';
6378          }
6379          return true;
6380      } 
6381  }
6382  ?><?php
6383  
6384  
6385  
6386  /**

6387  *

6388  * nusoap_parser class parses SOAP XML messages into native PHP values

6389  *

6390  * @author   Dietrich Ayala <dietrich@ganx4.com>

6391  * @author   Scott Nichol <snichol@users.sourceforge.net>

6392  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

6393  * @access   public

6394  */
6395  class nusoap_parser extends nusoap_base {
6396  
6397      var $xml = '';
6398      var $xml_encoding = '';
6399      var $method = '';
6400      var $root_struct = '';
6401      var $root_struct_name = '';
6402      var $root_struct_namespace = '';
6403      var $root_header = '';
6404      var $document = '';            // incoming SOAP body (text)

6405      // determines where in the message we are (envelope,header,body,method)

6406      var $status = '';
6407      var $position = 0;
6408      var $depth = 0;
6409      var $default_namespace = '';
6410      var $namespaces = array();
6411      var $message = array();
6412      var $parent = '';
6413      var $fault = false;
6414      var $fault_code = '';
6415      var $fault_str = '';
6416      var $fault_detail = '';
6417      var $depth_array = array();
6418      var $debug_flag = true;
6419      var $soapresponse = NULL;    // parsed SOAP Body

6420      var $soapheader = NULL;        // parsed SOAP Header

6421      var $responseHeaders = '';    // incoming SOAP headers (text)

6422      var $body_position = 0;
6423      // for multiref parsing:

6424      // array of id => pos

6425      var $ids = array();
6426      // array of id => hrefs => pos

6427      var $multirefs = array();
6428      // toggle for auto-decoding element content

6429      var $decode_utf8 = true;
6430  
6431      /**

6432      * constructor that actually does the parsing

6433      *

6434      * @param    string $xml SOAP message

6435      * @param    string $encoding character encoding scheme of message

6436      * @param    string $method method for which XML is parsed (unused?)

6437      * @param    string $decode_utf8 whether to decode UTF-8 to ISO-8859-1

6438      * @access   public

6439      */
6440  	function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
6441          parent::nusoap_base();
6442          $this->xml = $xml;
6443          $this->xml_encoding = $encoding;
6444          $this->method = $method;
6445          $this->decode_utf8 = $decode_utf8;
6446  
6447          // Check whether content has been read.

6448          if(!empty($xml)){
6449              // Check XML encoding

6450              $pos_xml = strpos($xml, '<?xml');
6451              if ($pos_xml !== FALSE) {
6452                  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
6453                  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
6454                      $xml_encoding = $res[1];
6455                      if (strtoupper($xml_encoding) != $encoding) {
6456                          $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
6457                          $this->debug($err);
6458                          if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
6459                              $this->setError($err);
6460                              return;
6461                          }
6462                          // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed

6463                      } else {
6464                          $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
6465                      }
6466                  } else {
6467                      $this->debug('No encoding specified in XML declaration');
6468                  }
6469              } else {
6470                  $this->debug('No XML declaration');
6471              }
6472              $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
6473              // Create an XML parser - why not xml_parser_create_ns?

6474              $this->parser = xml_parser_create($this->xml_encoding);
6475              // Set the options for parsing the XML data.

6476              //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);

6477              xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6478              xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
6479              // Set the object for the parser.

6480              xml_set_object($this->parser, $this);
6481              // Set the element handlers for the parser.

6482              xml_set_element_handler($this->parser, 'start_element','end_element');
6483              xml_set_character_data_handler($this->parser,'character_data');
6484  
6485              // Parse the XML file.

6486              if(!xml_parse($this->parser,$xml,true)){
6487                  // Display an error message.

6488                  $err = sprintf('XML error parsing SOAP payload on line %d: %s',
6489                  xml_get_current_line_number($this->parser),
6490                  xml_error_string(xml_get_error_code($this->parser)));
6491                  $this->debug($err);
6492                  $this->debug("XML payload:\n" . $xml);
6493                  $this->setError($err);
6494              } else {
6495                  $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
6496                  // get final value

6497                  $this->soapresponse = $this->message[$this->root_struct]['result'];
6498                  // get header value

6499                  if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
6500                      $this->soapheader = $this->message[$this->root_header]['result'];
6501                  }
6502                  // resolve hrefs/ids

6503                  if(sizeof($this->multirefs) > 0){
6504                      foreach($this->multirefs as $id => $hrefs){
6505                          $this->debug('resolving multirefs for id: '.$id);
6506                          $idVal = $this->buildVal($this->ids[$id]);
6507                          if (is_array($idVal) && isset($idVal['!id'])) {
6508                              unset($idVal['!id']);
6509                          }
6510                          foreach($hrefs as $refPos => $ref){
6511                              $this->debug('resolving href at pos '.$refPos);
6512                              $this->multirefs[$id][$refPos] = $idVal;
6513                          }
6514                      }
6515                  }
6516              }
6517              xml_parser_free($this->parser);
6518          } else {
6519              $this->debug('xml was empty, didn\'t parse!');
6520              $this->setError('xml was empty, didn\'t parse!');
6521          }
6522      }
6523  
6524      /**

6525      * start-element handler

6526      *

6527      * @param    resource $parser XML parser object

6528      * @param    string $name element name

6529      * @param    array $attrs associative array of attributes

6530      * @access   private

6531      */
6532  	function start_element($parser, $name, $attrs) {
6533          // position in a total number of elements, starting from 0

6534          // update class level pos

6535          $pos = $this->position++;
6536          // and set mine

6537          $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
6538          // depth = how many levels removed from root?

6539          // set mine as current global depth and increment global depth value

6540          $this->message[$pos]['depth'] = $this->depth++;
6541  
6542          // else add self as child to whoever the current parent is

6543          if($pos != 0){
6544              $this->message[$this->parent]['children'] .= '|'.$pos;
6545          }
6546          // set my parent

6547          $this->message[$pos]['parent'] = $this->parent;
6548          // set self as current parent

6549          $this->parent = $pos;
6550          // set self as current value for this depth

6551          $this->depth_array[$this->depth] = $pos;
6552          // get element prefix

6553          if(strpos($name,':')){
6554              // get ns prefix

6555              $prefix = substr($name,0,strpos($name,':'));
6556              // get unqualified name

6557              $name = substr(strstr($name,':'),1);
6558          }
6559          // set status

6560          if($name == 'Envelope'){
6561              $this->status = 'envelope';
6562          } elseif($name == 'Header' && $this->status = 'envelope'){
6563              $this->root_header = $pos;
6564              $this->status = 'header';
6565          } elseif($name == 'Body' && $this->status = 'envelope'){
6566              $this->status = 'body';
6567              $this->body_position = $pos;
6568          // set method

6569          } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
6570              $this->status = 'method';
6571              $this->root_struct_name = $name;
6572              $this->root_struct = $pos;
6573              $this->message[$pos]['type'] = 'struct';
6574              $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
6575          }
6576          // set my status

6577          $this->message[$pos]['status'] = $this->status;
6578          // set name

6579          $this->message[$pos]['name'] = htmlspecialchars($name);
6580          // set attrs

6581          $this->message[$pos]['attrs'] = $attrs;
6582  
6583          // loop through atts, logging ns and type declarations

6584          $attstr = '';
6585          foreach($attrs as $key => $value){
6586              $key_prefix = $this->getPrefix($key);
6587              $key_localpart = $this->getLocalPart($key);
6588              // if ns declarations, add to class level array of valid namespaces

6589              if($key_prefix == 'xmlns'){
6590                  if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
6591                      $this->XMLSchemaVersion = $value;
6592                      $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6593                      $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
6594                  }
6595                  $this->namespaces[$key_localpart] = $value;
6596                  // set method namespace

6597                  if($name == $this->root_struct_name){
6598                      $this->methodNamespace = $value;
6599                  }
6600              // if it's a type declaration, set type

6601          } elseif($key_localpart == 'type'){
6602                  if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
6603                      // do nothing: already processed arrayType

6604                  } else {
6605                      $value_prefix = $this->getPrefix($value);
6606                      $value_localpart = $this->getLocalPart($value);
6607                      $this->message[$pos]['type'] = $value_localpart;
6608                      $this->message[$pos]['typePrefix'] = $value_prefix;
6609                      if(isset($this->namespaces[$value_prefix])){
6610                          $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6611                      } else if(isset($attrs['xmlns:'.$value_prefix])) {
6612                          $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
6613                      }
6614                      // should do something here with the namespace of specified type?

6615                  }
6616              } elseif($key_localpart == 'arrayType'){
6617                  $this->message[$pos]['type'] = 'array';
6618                  /* do arrayType ereg here

6619                  [1]    arrayTypeValue    ::=    atype asize

6620                  [2]    atype    ::=    QName rank*

6621                  [3]    rank    ::=    '[' (',')* ']'

6622                  [4]    asize    ::=    '[' length~ ']'

6623                  [5]    length    ::=    nextDimension* Digit+

6624                  [6]    nextDimension    ::=    Digit+ ','

6625                  */
6626                  $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
6627                  if(ereg($expr,$value,$regs)){
6628                      $this->message[$pos]['typePrefix'] = $regs[1];
6629                      $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6630                      if (isset($this->namespaces[$regs[1]])) {
6631                          $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6632                      } else if (isset($attrs['xmlns:'.$regs[1]])) {
6633                          $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
6634                      }
6635                      $this->message[$pos]['arrayType'] = $regs[2];
6636                      $this->message[$pos]['arraySize'] = $regs[3];
6637                      $this->message[$pos]['arrayCols'] = $regs[4];
6638                  }
6639              // specifies nil value (or not)

6640              } elseif ($key_localpart == 'nil'){
6641                  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6642              // some other attribute

6643              } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6644                  $this->message[$pos]['xattrs']['!' . $key] = $value;
6645              }
6646  
6647              if ($key == 'xmlns') {
6648                  $this->default_namespace = $value;
6649              }
6650              // log id

6651              if($key == 'id'){
6652                  $this->ids[$value] = $pos;
6653              }
6654              // root

6655              if($key_localpart == 'root' && $value == 1){
6656                  $this->status = 'method';
6657                  $this->root_struct_name = $name;
6658                  $this->root_struct = $pos;
6659                  $this->debug("found root struct $this->root_struct_name, pos $pos");
6660              }
6661              // for doclit

6662              $attstr .= " $key=\"$value\"";
6663          }
6664          // get namespace - must be done after namespace atts are processed

6665          if(isset($prefix)){
6666              $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6667              $this->default_namespace = $this->namespaces[$prefix];
6668          } else {
6669              $this->message[$pos]['namespace'] = $this->default_namespace;
6670          }
6671          if($this->status == 'header'){
6672              if ($this->root_header != $pos) {
6673                  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6674              }
6675          } elseif($this->root_struct_name != ''){
6676              $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6677          }
6678      }
6679  
6680      /**

6681      * end-element handler

6682      *

6683      * @param    resource $parser XML parser object

6684      * @param    string $name element name

6685      * @access   private

6686      */
6687  	function end_element($parser, $name) {
6688          // position of current element is equal to the last value left in depth_array for my depth

6689          $pos = $this->depth_array[$this->depth--];
6690  
6691          // get element prefix

6692          if(strpos($name,':')){
6693              // get ns prefix

6694              $prefix = substr($name,0,strpos($name,':'));
6695              // get unqualified name

6696              $name = substr(strstr($name,':'),1);
6697          }
6698          
6699          // build to native type

6700          if(isset($this->body_position) && $pos > $this->body_position){
6701              // deal w/ multirefs

6702              if(isset($this->message[$pos]['attrs']['href'])){
6703                  // get id

6704                  $id = substr($this->message[$pos]['attrs']['href'],1);
6705                  // add placeholder to href array

6706                  $this->multirefs[$id][$pos] = 'placeholder';
6707                  // add set a reference to it as the result value

6708                  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6709              // build complexType values

6710              } elseif($this->message[$pos]['children'] != ''){
6711                  // if result has already been generated (struct/array)

6712                  if(!isset($this->message[$pos]['result'])){
6713                      $this->message[$pos]['result'] = $this->buildVal($pos);
6714                  }
6715              // build complexType values of attributes and possibly simpleContent

6716              } elseif (isset($this->message[$pos]['xattrs'])) {
6717                  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6718                      $this->message[$pos]['xattrs']['!'] = null;
6719                  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6720                      if (isset($this->message[$pos]['type'])) {
6721                          $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'] : '');
6722                      } else {
6723                          $parent = $this->message[$pos]['parent'];
6724                          if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6725                              $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6726                          } else {
6727                              $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6728                          }
6729                      }
6730                  }
6731                  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6732              // set value of simpleType (or nil complexType)

6733              } else {
6734                  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);

6735                  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6736                      $this->message[$pos]['xattrs']['!'] = null;
6737                  } elseif (isset($this->message[$pos]['type'])) {
6738                      $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'] : '');
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]['result'] = $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]['result'] = $this->message[$pos]['cdata'];
6745                      }
6746                  }
6747  
6748                  /* add value to parent's result, if parent is struct/array

6749                  $parent = $this->message[$pos]['parent'];

6750                  if($this->message[$parent]['type'] != 'map'){

6751                      if(strtolower($this->message[$parent]['type']) == 'array'){

6752                          $this->message[$parent]['result'][] = $this->message[$pos]['result'];

6753                      } else {

6754                          $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];

6755                      }

6756                  }

6757                  */
6758              }
6759          }
6760          
6761          // for doclit

6762          if($this->status == 'header'){
6763              if ($this->root_header != $pos) {
6764                  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6765              }
6766          } elseif($pos >= $this->root_struct){
6767              $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6768          }
6769          // switch status

6770          if($pos == $this->root_struct){
6771              $this->status = 'body';
6772              $this->root_struct_namespace = $this->message[$pos]['namespace'];
6773          } elseif($name == 'Body'){
6774              $this->status = 'envelope';
6775           } elseif($name == 'Header'){
6776              $this->status = 'envelope';
6777          } elseif($name == 'Envelope'){
6778              //

6779          }
6780          // set parent back to my parent

6781          $this->parent = $this->message[$pos]['parent'];
6782      }
6783  
6784      /**

6785      * element content handler

6786      *

6787      * @param    resource $parser XML parser object

6788      * @param    string $data element content

6789      * @access   private

6790      */
6791  	function character_data($parser, $data){
6792          $pos = $this->depth_array[$this->depth];
6793          if ($this->xml_encoding=='UTF-8'){
6794              // TODO: add an option to disable this for folks who want

6795              // raw UTF-8 that, e.g., might not map to iso-8859-1

6796              // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");

6797              if($this->decode_utf8){
6798                  $data = utf8_decode($data);
6799              }
6800          }
6801          $this->message[$pos]['cdata'] .= $data;
6802          // for doclit

6803          if($this->status == 'header'){
6804              $this->responseHeaders .= $data;
6805          } else {
6806              $this->document .= $data;
6807          }
6808      }
6809  
6810      /**

6811      * get the parsed message (SOAP Body)

6812      *

6813      * @return    mixed

6814      * @access   public

6815      * @deprecated    use get_soapbody instead

6816      */
6817  	function get_response(){
6818          return $this->soapresponse;
6819      }
6820  
6821      /**

6822      * get the parsed SOAP Body (NULL if there was none)

6823      *

6824      * @return    mixed

6825      * @access   public

6826      */
6827  	function get_soapbody(){
6828          return $this->soapresponse;
6829      }
6830  
6831      /**

6832      * get the parsed SOAP Header (NULL if there was none)

6833      *

6834      * @return    mixed

6835      * @access   public

6836      */
6837  	function get_soapheader(){
6838          return $this->soapheader;
6839      }
6840  
6841      /**

6842      * get the unparsed SOAP Header

6843      *

6844      * @return    string XML or empty if no Header

6845      * @access   public

6846      */
6847  	function getHeaders(){
6848          return $this->responseHeaders;
6849      }
6850  
6851      /**

6852      * decodes simple types into PHP variables

6853      *

6854      * @param    string $value value to decode

6855      * @param    string $type XML type to decode

6856      * @param    string $typens XML type namespace to decode

6857      * @return    mixed PHP value

6858      * @access   private

6859      */
6860  	function decodeSimple($value, $type, $typens) {
6861          // TODO: use the namespace!

6862          if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
6863              return (string) $value;
6864          }
6865          if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
6866              return (int) $value;
6867          }
6868          if ($type == 'float' || $type == 'double' || $type == 'decimal') {
6869              return (double) $value;
6870          }
6871          if ($type == 'boolean') {
6872              if (strtolower($value) == 'false' || strtolower($value) == 'f') {
6873                  return false;
6874              }
6875              return (boolean) $value;
6876          }
6877          if ($type == 'base64' || $type == 'base64Binary') {
6878              $this->debug('Decode base64 value');
6879              return base64_decode($value);
6880          }
6881          // obscure numeric types

6882          if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
6883              || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
6884              || $type == 'unsignedInt'
6885              || $type == 'unsignedShort' || $type == 'unsignedByte') {
6886              return (int) $value;
6887          }
6888          // bogus: parser treats array with no elements as a simple type

6889          if ($type == 'array') {
6890              return array();
6891          }
6892          // everything else

6893          return (string) $value;
6894      }
6895  
6896      /**

6897      * builds response structures for compound values (arrays/structs)

6898      * and scalars

6899      *

6900      * @param    integer $pos position in node tree

6901      * @return    mixed    PHP value

6902      * @access   private

6903      */
6904  	function buildVal($pos){
6905          if(!isset($this->message[$pos]['type'])){
6906              $this->message[$pos]['type'] = '';
6907          }
6908          $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
6909          // if there are children...

6910          if($this->message[$pos]['children'] != ''){
6911              $this->debug('in buildVal, there are children');
6912              $children = explode('|',$this->message[$pos]['children']);
6913              array_shift($children); // knock off empty

6914              // md array

6915              if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
6916                  $r=0; // rowcount

6917                  $c=0; // colcount

6918                  foreach($children as $child_pos){
6919                      $this->debug("in buildVal, got an MD array element: $r, $c");
6920                      $params[$r][] = $this->message[$child_pos]['result'];
6921                      $c++;
6922                      if($c == $this->message[$pos]['arrayCols']){
6923                          $c = 0;
6924                          $r++;
6925                      }
6926                  }
6927              // array

6928              } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
6929                  $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
6930                  foreach($children as $child_pos){
6931                      $params[] = &$this->message[$child_pos]['result'];
6932                  }
6933              // apache Map type: java hashtable

6934              } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
6935                  $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
6936                  foreach($children as $child_pos){
6937                      $kv = explode("|",$this->message[$child_pos]['children']);
6938                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
6939                  }
6940              // generic compound type

6941              //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {

6942              } else {
6943                  // Apache Vector type: treat as an array

6944                  $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
6945                  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
6946                      $notstruct = 1;
6947                  } else {
6948                      $notstruct = 0;
6949                  }
6950                  //

6951                  foreach($children as $child_pos){
6952                      if($notstruct){
6953                          $params[] = &$this->message[$child_pos]['result'];
6954                      } else {
6955                          if (isset($params[$this->message[$child_pos]['name']])) {
6956                              // de-serialize repeated element name into an array

6957                              if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
6958                                  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
6959                              }
6960                              $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
6961                          } else {
6962                              $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
6963                          }
6964                      }
6965                  }
6966              }
6967              if (isset($this->message[$pos]['xattrs'])) {
6968                  $this->debug('in buildVal, handling attributes');
6969                  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
6970                      $params[$n] = $v;
6971                  }
6972              }
6973              // handle simpleContent

6974              if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6975                  $this->debug('in buildVal, handling simpleContent');
6976                  if (isset($this->message[$pos]['type'])) {
6977                      $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6978                  } else {
6979                      $parent = $this->message[$pos]['parent'];
6980                      if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6981                          $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6982                      } else {
6983                          $params['!'] = $this->message[$pos]['cdata'];
6984                      }
6985                  }
6986              }
6987              $ret = is_array($params) ? $params : array();
6988              $this->debug('in buildVal, return:');
6989              $this->appendDebug($this->varDump($ret));
6990              return $ret;
6991          } else {
6992              $this->debug('in buildVal, no children, building scalar');
6993              $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
6994              if (isset($this->message[$pos]['type'])) {
6995                  $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6996                  $this->debug("in buildVal, return: $ret");
6997                  return $ret;
6998              }
6999              $parent = $this->message[$pos]['parent'];
7000              if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
7001                  $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7002                  $this->debug("in buildVal, return: $ret");
7003                  return $ret;
7004              }
7005                 $ret = $this->message[$pos]['cdata'];
7006              $this->debug("in buildVal, return: $ret");
7007                 return $ret;
7008          }
7009      }
7010  }
7011  
7012  /**

7013   * Backward compatibility

7014   */
7015  class soap_parser extends nusoap_parser {
7016  }
7017  
7018  ?><?php
7019  
7020  
7021  
7022  /**

7023  *

7024  * [nu]soapclient higher level class for easy usage.

7025  *

7026  * usage:

7027  *

7028  * // instantiate client with server info

7029  * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );

7030  *

7031  * // call method, get results

7032  * echo $soapclient->call( string methodname [ ,array parameters] );

7033  *

7034  * // bye bye client

7035  * unset($soapclient);

7036  *

7037  * @author   Dietrich Ayala <dietrich@ganx4.com>

7038  * @author   Scott Nichol <snichol@users.sourceforge.net>

7039  * @version  $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 snichol Exp $

7040  * @access   public

7041  */
7042  class nusoap_client extends nusoap_base  {
7043  
7044      var $username = '';                // Username for HTTP authentication

7045      var $password = '';                // Password for HTTP authentication

7046      var $authtype = '';                // Type of HTTP authentication

7047      var $certRequest = array();        // Certificate for HTTP SSL authentication

7048      var $requestHeaders = false;    // SOAP headers in request (text)

7049      var $responseHeaders = '';        // SOAP headers from response (incomplete namespace resolution) (text)

7050      var $responseHeader = NULL;        // SOAP Header from response (parsed)

7051      var $document = '';                // SOAP body response portion (incomplete namespace resolution) (text)

7052      var $endpoint;
7053      var $forceEndpoint = '';        // overrides WSDL endpoint

7054      var $proxyhost = '';
7055      var $proxyport = '';
7056      var $proxyusername = '';
7057      var $proxypassword = '';
7058      var $xml_encoding = '';            // character set encoding of incoming (response) messages

7059      var $http_encoding = false;
7060      var $timeout = 0;                // HTTP connection timeout

7061      var $response_timeout = 30;        // HTTP response timeout

7062      var $endpointType = '';            // soap|wsdl, empty for WSDL initialization error

7063      var $persistentConnection = false;
7064      var $defaultRpcParams = false;    // This is no longer used

7065      var $request = '';                // HTTP request

7066      var $response = '';                // HTTP response

7067      var $responseData = '';            // SOAP payload of response

7068      var $cookies = array();            // Cookies from response or for request

7069      var $decode_utf8 = true;        // toggles whether the parser decodes element content w/ utf8_decode()

7070      var $operations = array();        // WSDL operations, empty for WSDL initialization error

7071      var $curl_options = array();    // User-specified cURL options

7072      var $bindingType = '';            // WSDL operation binding type

7073      var $use_curl = false;            // whether to always try to use cURL

7074  
7075      /*

7076       * fault related variables

7077       */
7078      /**

7079       * @var      fault

7080       * @access   public

7081       */
7082      var $fault;
7083      /**

7084       * @var      faultcode

7085       * @access   public

7086       */
7087      var $faultcode;
7088      /**

7089       * @var      faultstring

7090       * @access   public

7091       */
7092      var $faultstring;
7093      /**

7094       * @var      faultdetail

7095       * @access   public

7096       */
7097      var $faultdetail;
7098  
7099      /**

7100      * constructor

7101      *

7102      * @param    mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)

7103      * @param    bool $wsdl optional, set to true if using WSDL

7104      * @param    int $portName optional portName in WSDL document

7105      * @param    string $proxyhost

7106      * @param    string $proxyport

7107      * @param    string $proxyusername

7108      * @param    string $proxypassword

7109      * @param    integer $timeout set the connection timeout

7110      * @param    integer $response_timeout set the response timeout

7111      * @access   public

7112      */
7113  	function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
7114          parent::nusoap_base();
7115          $this->endpoint = $endpoint;
7116          $this->proxyhost = $proxyhost;
7117          $this->proxyport = $proxyport;
7118          $this->proxyusername = $proxyusername;
7119          $this->proxypassword = $proxypassword;
7120          $this->timeout = $timeout;
7121          $this->response_timeout = $response_timeout;
7122  
7123          $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7124          $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7125  
7126          // make values

7127          if($wsdl){
7128              if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
7129                  $this->wsdl = $endpoint;
7130                  $this->endpoint = $this->wsdl->wsdl;
7131                  $this->wsdlFile = $this->endpoint;
7132                  $this->debug('existing wsdl instance created from ' . $this->endpoint);
7133                  $this->checkWSDL();
7134              } else {
7135                  $this->wsdlFile = $this->endpoint;
7136                  $this->wsdl = null;
7137                  $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7138              }
7139              $this->endpointType = 'wsdl';
7140          } else {
7141              $this->debug("instantiate SOAP with endpoint at $endpoint");
7142              $this->endpointType = 'soap';
7143          }
7144      }
7145  
7146      /**

7147      * calls method, returns PHP native type

7148      *

7149      * @param    string $operation SOAP server URL or path

7150      * @param    mixed $params An array, associative or simple, of the parameters

7151      *                          for the method call, or a string that is the XML

7152      *                          for the call.  For rpc style, this call will

7153      *                          wrap the XML in a tag named after the method, as

7154      *                          well as the SOAP Envelope and Body.  For document

7155      *                          style, this will only wrap with the Envelope and Body.

7156      *                          IMPORTANT: when using an array with document style,

7157      *                          in which case there

7158      *                         is really one parameter, the root of the fragment

7159      *                         used in the call, which encloses what programmers

7160      *                         normally think of parameters.  A parameter array

7161      *                         *must* include the wrapper.

7162      * @param    string $namespace optional method namespace (WSDL can override)

7163      * @param    string $soapAction optional SOAPAction value (WSDL can override)

7164      * @param    mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array

7165      * @param    boolean $rpcParams optional (no longer used)

7166      * @param    string    $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)

7167      * @param    string    $use optional (encoded|literal) the use when serializing parameters (WSDL can override)

7168      * @return    mixed    response from SOAP call

7169      * @access   public

7170      */
7171  	function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
7172          $this->operation = $operation;
7173          $this->fault = false;
7174          $this->setError('');
7175          $this->request = '';
7176          $this->response = '';
7177          $this->responseData = '';
7178          $this->faultstring = '';
7179          $this->faultcode = '';
7180          $this->opData = array();
7181          
7182          $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7183          $this->appendDebug('params=' . $this->varDump($params));
7184          $this->appendDebug('headers=' . $this->varDump($headers));
7185          if ($headers) {
7186              $this->requestHeaders = $headers;
7187          }
7188          if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7189              $this->loadWSDL();
7190              if ($this->getError())
7191                  return false;
7192          }
7193          // serialize parameters

7194          if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
7195              // use WSDL for operation

7196              $this->opData = $opData;
7197              $this->debug("found operation");
7198              $this->appendDebug('opData=' . $this->varDump($opData));
7199              if (isset($opData['soapAction'])) {
7200                  $soapAction = $opData['soapAction'];
7201              }
7202              if (! $this->forceEndpoint) {
7203                  $this->endpoint = $opData['endpoint'];
7204              } else {
7205                  $this->endpoint = $this->forceEndpoint;
7206              }
7207              $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :    $namespace;
7208              $style = $opData['style'];
7209              $use = $opData['input']['use'];
7210              // add ns to ns array

7211              if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
7212                  $nsPrefix = 'ns' . rand(1000, 9999);
7213                  $this->wsdl->namespaces[$nsPrefix] = $namespace;
7214              }
7215              $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7216              // serialize payload

7217              if (is_string($params)) {
7218                  $this->debug("serializing param string for WSDL operation $operation");
7219                  $payload = $params;
7220              } elseif (is_array($params)) {
7221                  $this->debug("serializing param array for WSDL operation $operation");
7222                  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
7223              } else {
7224                  $this->debug('params must be array or string');
7225                  $this->setError('params must be array or string');
7226                  return false;
7227              }
7228              $usedNamespaces = $this->wsdl->usedNamespaces;
7229              if (isset($opData['input']['encodingStyle'])) {
7230                  $encodingStyle = $opData['input']['encodingStyle'];
7231              } else {
7232                  $encodingStyle = '';
7233              }
7234              $this->appendDebug($this->wsdl->getDebug());
7235              $this->wsdl->clearDebug();
7236              if ($errstr = $this->wsdl->getError()) {
7237                  $this->debug('got wsdl error: '.$errstr);
7238                  $this->setError('wsdl error: '.$errstr);
7239                  return false;
7240              }
7241          } elseif($this->endpointType == 'wsdl') {
7242              // operation not in WSDL

7243              $this->appendDebug($this->wsdl->getDebug());
7244              $this->wsdl->clearDebug();
7245              $this->setError( 'operation '.$operation.' not present.');
7246              $this->debug("operation '$operation' not present.");
7247              return false;
7248          } else {
7249              // no WSDL

7250              //$this->namespaces['ns1'] = $namespace;

7251              $nsPrefix = 'ns' . rand(1000, 9999);
7252              // serialize 

7253              $payload = '';
7254              if (is_string($params)) {
7255                  $this->debug("serializing param string for operation $operation");
7256                  $payload = $params;
7257              } elseif (is_array($params)) {
7258                  $this->debug("serializing param array for operation $operation");
7259                  foreach($params as $k => $v){
7260                      $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
7261                  }
7262              } else {
7263                  $this->debug('params must be array or string');
7264                  $this->setError('params must be array or string');
7265                  return false;
7266              }
7267              $usedNamespaces = array();
7268              if ($use == 'encoded') {
7269                  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7270              } else {
7271                  $encodingStyle = '';
7272              }
7273          }
7274          // wrap RPC calls with method element

7275          if ($style == 'rpc') {
7276              if ($use == 'literal') {
7277                  $this->debug("wrapping RPC request with literal method element");
7278                  if ($namespace) {
7279                      // 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

7280                      $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7281                                  $payload .
7282                                  "</$nsPrefix:$operation>";
7283                  } else {
7284                      $payload = "<$operation>" . $payload . "</$operation>";
7285                  }
7286              } else {
7287                  $this->debug("wrapping RPC request with encoded method element");
7288                  if ($namespace) {
7289                      $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
7290                                  $payload .
7291                                  "</$nsPrefix:$operation>";
7292                  } else {
7293                      $payload = "<$operation>" .
7294                                  $payload .
7295                                  "</$operation>";
7296                  }
7297              }
7298          }
7299          // serialize envelope

7300          $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
7301          $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7302          $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7303          // send

7304          $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
7305          if($errstr = $this->getError()){
7306              $this->debug('Error: '.$errstr);
7307              return false;
7308          } else {
7309              $this->return = $return;
7310              $this->debug('sent message successfully and got a(n) '.gettype($return));
7311                 $this->appendDebug('return=' . $this->varDump($return));
7312              
7313              // fault?

7314              if(is_array($return) && isset($return['faultcode'])){
7315                  $this->debug('got fault');
7316                  $this->setError($return['faultcode'].': '.$return['faultstring']);
7317                  $this->fault = true;
7318                  foreach($return as $k => $v){
7319                      $this->$k = $v;
7320                      $this->debug("$k = $v<br>");
7321                  }
7322                  return $return;
7323              } elseif ($style == 'document') {
7324                  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),

7325                  // we are only going to return the first part here...sorry about that

7326                  return $return;
7327              } else {
7328                  // array of return values

7329                  if(is_array($return)){
7330                      // multiple 'out' parameters, which we return wrapped up

7331                      // in the array

7332                      if(sizeof($return) > 1){
7333                          return $return;
7334                      }
7335                      // single 'out' parameter (normally the return value)

7336                      $return = array_shift($return);
7337                      $this->debug('return shifted value: ');
7338                      $this->appendDebug($this->varDump($return));
7339                         return $return;
7340                  // nothing returned (ie, echoVoid)

7341                  } else {
7342                      return "";
7343                  }
7344              }
7345          }
7346      }
7347  
7348      /**

7349      * check WSDL passed as an instance or pulled from an endpoint

7350      *

7351      * @access   private

7352      */
7353  	function checkWSDL() {
7354          $this->appendDebug($this->wsdl->getDebug());
7355          $this->wsdl->clearDebug();
7356          $this->debug('checkWSDL');
7357          // catch errors

7358          if ($errstr = $this->wsdl->getError()) {
7359              $this->debug('got wsdl error: '.$errstr);
7360              $this->setError('wsdl error: '.$errstr);
7361          } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
7362              $this->bindingType = 'soap';
7363              $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7364          } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
7365              $this->bindingType = 'soap12';
7366              $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
7367              $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7368          } else {
7369              $this->debug('getOperations returned false');
7370              $this->setError('no operations defined in the WSDL document!');
7371          }
7372      }
7373  
7374      /**

7375       * instantiate wsdl object and parse wsdl file

7376       *

7377       * @access    public

7378       */
7379  	function loadWSDL() {
7380          $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
7381          $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
7382          $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
7383          $this->wsdl->fetchWSDL($this->wsdlFile);
7384          $this->checkWSDL();
7385      }
7386  
7387      /**

7388      * get available data pertaining to an operation

7389      *

7390      * @param    string $operation operation name

7391      * @return    array array of data pertaining to the operation

7392      * @access   public

7393      */
7394  	function getOperationData($operation){
7395          if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7396              $this->loadWSDL();
7397              if ($this->getError())
7398                  return false;
7399          }
7400          if(isset($this->operations[$operation])){
7401              return $this->operations[$operation];
7402          }
7403          $this->debug("No data for operation: $operation");
7404      }
7405  
7406      /**

7407      * send the SOAP message

7408      *

7409      * Note: if the operation has multiple return values

7410      * the return value of this method will be an array

7411      * of those values.

7412      *

7413      * @param    string $msg a SOAPx4 soapmsg object

7414      * @param    string $soapaction SOAPAction value

7415      * @param    integer $timeout set connection timeout in seconds

7416      * @param    integer $response_timeout set response timeout in seconds

7417      * @return    mixed native PHP types.

7418      * @access   private

7419      */
7420  	function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
7421          $this->checkCookies();
7422          // detect transport

7423          switch(true){
7424              // http(s)

7425              case ereg('^http',$this->endpoint):
7426                  $this->debug('transporting via HTTP');
7427                  if($this->persistentConnection == true && is_object($this->persistentConnection)){
7428                      $http =& $this->persistentConnection;
7429                  } else {
7430                      $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
7431                      if ($this->persistentConnection) {
7432                          $http->usePersistentConnection();
7433                      }
7434                  }
7435                  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
7436                  $http->setSOAPAction($soapaction);
7437                  if($this->proxyhost && $this->proxyport){
7438                      $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
7439                  }
7440                  if($this->authtype != '') {
7441                      $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
7442                  }
7443                  if($this->http_encoding != ''){
7444                      $http->setEncoding($this->http_encoding);
7445                  }
7446                  $this->debug('sending message, length='.strlen($msg));
7447                  if(ereg('^http:',$this->endpoint)){
7448                  //if(strpos($this->endpoint,'http:')){

7449                      $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
7450                  } elseif(ereg('^https',$this->endpoint)){
7451                  //} elseif(strpos($this->endpoint,'https:')){

7452                      //if(phpversion() == '4.3.0-dev'){

7453                          //$response = $http->send($msg,$timeout,$response_timeout);

7454                             //$this->request = $http->outgoing_payload;

7455                          //$this->response = $http->incoming_payload;

7456                      //} else

7457                      $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
7458                  } else {
7459                      $this->setError('no http/s in endpoint url');
7460                  }
7461                  $this->request = $http->outgoing_payload;
7462                  $this->response = $http->incoming_payload;
7463                  $this->appendDebug($http->getDebug());
7464                  $this->UpdateCookies($http->incoming_cookies);
7465  
7466                  // save transport object if using persistent connections

7467                  if ($this->persistentConnection) {
7468                      $http->clearDebug();
7469                      if (!is_object($this->persistentConnection)) {
7470                          $this->persistentConnection = $http;
7471                      }
7472                  }
7473                  
7474                  if($err = $http->getError()){
7475                      $this->setError('HTTP Error: '.$err);
7476                      return false;
7477                  } elseif($this->getError()){
7478                      return false;
7479                  } else {
7480                      $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
7481                      return $this->parseResponse($http->incoming_headers, $this->responseData);
7482                  }
7483              break;
7484              default:
7485                  $this->setError('no transport found, or selected transport is not yet supported!');
7486              return false;
7487              break;
7488          }
7489      }
7490  
7491      /**

7492      * processes SOAP message returned from server

7493      *

7494      * @param    array    $headers    The HTTP headers

7495      * @param    string    $data        unprocessed response data from server

7496      * @return    mixed    value of the message, decoded into a PHP type

7497      * @access   private

7498      */
7499      function parseResponse($headers, $data) {
7500          $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
7501          $this->appendDebug($this->varDump($headers));
7502          if (!strstr($headers['content-type'], 'text/xml')) {
7503              $this->setError('Response not of type text/xml: ' . $headers['content-type']);
7504              return false;
7505          }
7506          if (strpos($headers['content-type'], '=')) {
7507              $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
7508              $this->debug('Got response encoding: ' . $enc);
7509              if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
7510                  $this->xml_encoding = strtoupper($enc);
7511              } else {
7512                  $this->xml_encoding = 'US-ASCII';
7513              }
7514          } else {
7515              // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1

7516              $this->xml_encoding = 'ISO-8859-1';
7517          }
7518          $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
7519          $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
7520          // add parser debug data to our debug

7521          $this->appendDebug($parser->getDebug());
7522          // if parse errors

7523          if($errstr = $parser->getError()){
7524              $this->setError( $errstr);
7525              // destroy the parser object

7526              unset($parser);
7527              return false;
7528          } else {
7529              // get SOAP headers

7530              $this->responseHeaders = $parser->getHeaders();
7531              // get SOAP headers

7532              $this->responseHeader = $parser->get_soapheader();
7533              // get decoded message

7534              $return = $parser->get_soapbody();
7535              // add document for doclit support

7536              $this->document = $parser->document;
7537              // destroy the parser object

7538              unset($parser);
7539              // return decode message

7540              return $return;
7541          }
7542       }
7543  
7544      /**

7545      * sets user-specified cURL options

7546      *

7547      * @param    mixed $option The cURL option (always integer?)

7548      * @param    mixed $value The cURL option value

7549      * @access   public

7550      */
7551  	function setCurlOption($option, $value) {
7552          $this->debug("setCurlOption option=$option, value=");
7553          $this->appendDebug($this->varDump($value));
7554          $this->curl_options[$option] = $value;
7555      }
7556  
7557      /**

7558      * sets the SOAP endpoint, which can override WSDL

7559      *

7560      * @param    string $endpoint The endpoint URL to use, or empty string or false to prevent override

7561      * @access   public

7562      */
7563  	function setEndpoint($endpoint) {
7564          $this->debug("setEndpoint(\"$endpoint\")");
7565          $this->forceEndpoint = $endpoint;
7566      }
7567  
7568      /**

7569      * set the SOAP headers

7570      *

7571      * @param    mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers

7572      * @access   public

7573      */
7574  	function setHeaders($headers){
7575          $this->debug("setHeaders headers=");
7576          $this->appendDebug($this->varDump($headers));
7577          $this->requestHeaders = $headers;
7578      }
7579  
7580      /**

7581      * get the SOAP response headers (namespace resolution incomplete)

7582      *

7583      * @return    string

7584      * @access   public

7585      */
7586  	function getHeaders(){
7587          return $this->responseHeaders;
7588      }
7589  
7590      /**

7591      * get the SOAP response Header (parsed)

7592      *

7593      * @return    mixed

7594      * @access   public

7595      */
7596  	function getHeader(){
7597          return $this->responseHeader;
7598      }
7599  
7600      /**

7601      * set proxy info here

7602      *

7603      * @param    string $proxyhost

7604      * @param    string $proxyport

7605      * @param    string $proxyusername

7606      * @param    string $proxypassword

7607      * @access   public

7608      */
7609  	function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
7610          $this->proxyhost = $proxyhost;
7611          $this->proxyport = $proxyport;
7612          $this->proxyusername = $proxyusername;
7613          $this->proxypassword = $proxypassword;
7614      }
7615  
7616      /**

7617      * if authenticating, set user credentials here

7618      *

7619      * @param    string $username

7620      * @param    string $password

7621      * @param    string $authtype (basic|digest|certificate|ntlm)

7622      * @param    array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)

7623      * @access   public

7624      */
7625  	function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
7626          $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
7627          $this->appendDebug($this->varDump($certRequest));
7628          $this->username = $username;
7629          $this->password = $password;
7630          $this->authtype = $authtype;
7631          $this->certRequest = $certRequest;
7632      }
7633      
7634      /**

7635      * use HTTP encoding

7636      *

7637      * @param    string $enc HTTP encoding

7638      * @access   public

7639      */
7640  	function setHTTPEncoding($enc='gzip, deflate'){
7641          $this->debug("setHTTPEncoding(\"$enc\")");
7642          $this->http_encoding = $enc;
7643      }
7644      
7645      /**

7646      * Set whether to try to use cURL connections if possible

7647      *

7648      * @param    boolean $use Whether to try to use cURL

7649      * @access   public

7650      */
7651  	function setUseCURL($use) {
7652          $this->debug("setUseCURL($use)");
7653          $this->use_curl = $use;
7654      }
7655  
7656      /**

7657      * use HTTP persistent connections if possible

7658      *

7659      * @access   public

7660      */
7661  	function useHTTPPersistentConnection(){
7662          $this->debug("useHTTPPersistentConnection");
7663          $this->persistentConnection = true;
7664      }
7665      
7666      /**

7667      * gets the default RPC parameter setting.

7668      * If true, default is that call params are like RPC even for document style.

7669      * Each call() can override this value.

7670      *

7671      * This is no longer used.

7672      *

7673      * @return boolean

7674      * @access public

7675      * @deprecated

7676      */
7677  	function getDefaultRpcParams() {
7678          return $this->defaultRpcParams;
7679      }
7680  
7681      /**

7682      * sets the default RPC parameter setting.

7683      * If true, default is that call params are like RPC even for document style

7684      * Each call() can override this value.

7685      *

7686      * This is no longer used.

7687      *

7688      * @param    boolean $rpcParams

7689      * @access public

7690      * @deprecated

7691      */
7692  	function setDefaultRpcParams($rpcParams) {
7693          $this->defaultRpcParams = $rpcParams;
7694      }
7695      
7696      /**

7697      * dynamically creates an instance of a proxy class,

7698      * allowing user to directly call methods from wsdl

7699      *

7700      * @return   object soap_proxy object

7701      * @access   public

7702      */
7703  	function getProxy() {
7704          $r = rand();
7705          $evalStr = $this->_getProxyClassCode($r);
7706          //$this->debug("proxy class: $evalStr");

7707          if ($this->getError()) {
7708              $this->debug("Error from _getProxyClassCode, so return NULL");
7709              return null;
7710          }
7711          // eval the class

7712          eval($evalStr);
7713          // instantiate proxy object

7714          eval("\$proxy = new nusoap_proxy_$r('');");
7715          // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice

7716          $proxy->endpointType = 'wsdl';
7717          $proxy->wsdlFile = $this->wsdlFile;
7718          $proxy->wsdl = $this->wsdl;
7719          $proxy->operations = $this->operations;
7720          $proxy->defaultRpcParams = $this->defaultRpcParams;
7721          // transfer other state

7722          $proxy->soap_defencoding = $this->soap_defencoding;
7723          $proxy->username = $this->username;
7724          $proxy->password = $this->password;
7725          $proxy->authtype = $this->authtype;
7726          $proxy->certRequest = $this->certRequest;
7727          $proxy->requestHeaders = $this->requestHeaders;
7728          $proxy->endpoint = $this->endpoint;
7729          $proxy->forceEndpoint = $this->forceEndpoint;
7730          $proxy->proxyhost = $this->proxyhost;
7731          $proxy->proxyport = $this->proxyport;
7732          $proxy->proxyusername = $this->proxyusername;
7733          $proxy->proxypassword = $this->proxypassword;
7734          $proxy->http_encoding = $this->http_encoding;
7735          $proxy->timeout = $this->timeout;
7736          $proxy->response_timeout = $this->response_timeout;
7737          $proxy->persistentConnection = &$this->persistentConnection;
7738          $proxy->decode_utf8 = $this->decode_utf8;
7739          $proxy->curl_options = $this->curl_options;
7740          $proxy->bindingType = $this->bindingType;
7741          $proxy->use_curl = $this->use_curl;
7742          return $proxy;
7743      }
7744  
7745      /**

7746      * dynamically creates proxy class code

7747      *

7748      * @return   string PHP/NuSOAP code for the proxy class

7749      * @access   private

7750      */
7751  	function _getProxyClassCode($r) {
7752          $this->debug("in getProxy endpointType=$this->endpointType");
7753          $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
7754          if ($this->endpointType != 'wsdl') {
7755              $evalStr = 'A proxy can only be created for a WSDL client';
7756              $this->setError($evalStr);
7757              $evalStr = "echo \"$evalStr\";";
7758              return $evalStr;
7759          }
7760          if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
7761              $this->loadWSDL();
7762              if ($this->getError()) {
7763                  return "echo \"" . $this->getError() . "\";";
7764              }
7765          }
7766          $evalStr = '';
7767          foreach ($this->operations as $operation => $opData) {
7768              if ($operation != '') {
7769                  // create param string and param comment string

7770                  if (sizeof($opData['input']['parts']) > 0) {
7771                      $paramStr = '';
7772                      $paramArrayStr = '';
7773                      $paramCommentStr = '';
7774                      foreach ($opData['input']['parts'] as $name => $type) {
7775                          $paramStr .= "\$$name, ";
7776                          $paramArrayStr .= "'$name' => \$$name, ";
7777                          $paramCommentStr .= "$type \$$name, ";
7778                      }
7779                      $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
7780                      $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
7781                      $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
7782                  } else {
7783                      $paramStr = '';
7784                      $paramArrayStr = '';
7785                      $paramCommentStr = 'void';
7786                  }
7787                  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7788                  $evalStr .= "// $paramCommentStr
7789      function " . str_replace('.', '__', $operation) . "($paramStr) {
7790          \$params = array($paramArrayStr);
7791          return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
7792      }
7793      ";
7794                  unset($paramStr);
7795                  unset($paramCommentStr);
7796              }
7797          }
7798          $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
7799      '.$evalStr.'
7800  }';
7801          return $evalStr;
7802      }
7803  
7804      /**

7805      * dynamically creates proxy class code

7806      *

7807      * @return   string PHP/NuSOAP code for the proxy class

7808      * @access   public

7809      */
7810  	function getProxyClassCode() {
7811          $r = rand();
7812          return $this->_getProxyClassCode($r);
7813      }
7814  
7815      /**

7816      * gets the HTTP body for the current request.

7817      *

7818      * @param string $soapmsg The SOAP payload

7819      * @return string The HTTP body, which includes the SOAP payload

7820      * @access private

7821      */
7822  	function getHTTPBody($soapmsg) {
7823          return $soapmsg;
7824      }
7825      
7826      /**

7827      * gets the HTTP content type for the current request.

7828      *

7829      * Note: getHTTPBody must be called before this.

7830      *

7831      * @return string the HTTP content type for the current request.

7832      * @access private

7833      */
7834  	function getHTTPContentType() {
7835          return 'text/xml';
7836      }
7837      
7838      /**

7839      * gets the HTTP content type charset for the current request.

7840      * returns false for non-text content types.

7841      *

7842      * Note: getHTTPBody must be called before this.

7843      *

7844      * @return string the HTTP content type charset for the current request.

7845      * @access private

7846      */
7847  	function getHTTPContentTypeCharset() {
7848          return $this->soap_defencoding;
7849      }
7850  
7851      /*

7852      * whether or not parser should decode utf8 element content

7853      *

7854      * @return   always returns true

7855      * @access   public

7856      */
7857      function decodeUTF8($bool){
7858          $this->decode_utf8 = $bool;
7859          return true;
7860      }
7861  
7862      /**

7863       * adds a new Cookie into $this->cookies array

7864       *

7865       * @param    string $name Cookie Name

7866       * @param    string $value Cookie Value

7867       * @return    boolean if cookie-set was successful returns true, else false

7868       * @access    public

7869       */
7870  	function setCookie($name, $value) {
7871          if (strlen($name) == 0) {
7872              return false;
7873          }
7874          $this->cookies[] = array('name' => $name, 'value' => $value);
7875          return true;
7876      }
7877  
7878      /**

7879       * gets all Cookies

7880       *

7881       * @return   array with all internal cookies

7882       * @access   public

7883       */
7884  	function getCookies() {
7885          return $this->cookies;
7886      }
7887  
7888      /**

7889       * checks all Cookies and delete those which are expired

7890       *

7891       * @return   boolean always return true

7892       * @access   private

7893       */
7894  	function checkCookies() {
7895          if (sizeof($this->cookies) == 0) {
7896              return true;
7897          }
7898          $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
7899          $curr_cookies = $this->cookies;
7900          $this->cookies = array();
7901          foreach ($curr_cookies as $cookie) {
7902              if (! is_array($cookie)) {
7903                  $this->debug('Remove cookie that is not an array');
7904                  continue;
7905              }
7906              if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
7907                  if (strtotime($cookie['expires']) > time()) {
7908                      $this->cookies[] = $cookie;
7909                  } else {
7910                      $this->debug('Remove expired cookie ' . $cookie['name']);
7911                  }
7912              } else {
7913                  $this->cookies[] = $cookie;
7914              }
7915          }
7916          $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
7917          return true;
7918      }
7919  
7920      /**

7921       * updates the current cookies with a new set

7922       *

7923       * @param    array $cookies new cookies with which to update current ones

7924       * @return    boolean always return true

7925       * @access    private

7926       */
7927  	function UpdateCookies($cookies) {
7928          if (sizeof($this->cookies) == 0) {
7929              // no existing cookies: take whatever is new

7930              if (sizeof($cookies) > 0) {
7931                  $this->debug('Setting new cookie(s)');
7932                  $this->cookies = $cookies;
7933              }
7934              return true;
7935          }
7936          if (sizeof($cookies) == 0) {
7937              // no new cookies: keep what we've got

7938              return true;
7939          }
7940          // merge

7941          foreach ($cookies as $newCookie) {
7942              if (!is_array($newCookie)) {
7943                  continue;
7944              }
7945              if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
7946                  continue;
7947              }
7948              $newName = $newCookie['name'];
7949  
7950              $found = false;
7951              for ($i = 0; $i < count($this->cookies); $i++) {
7952                  $cookie = $this->cookies[$i];
7953                  if (!is_array($cookie)) {
7954                      continue;
7955                  }
7956                  if (!isset($cookie['name'])) {
7957                      continue;
7958                  }
7959                  if ($newName != $cookie['name']) {
7960                      continue;
7961                  }
7962                  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
7963                  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
7964                  if ($newDomain != $domain) {
7965                      continue;
7966                  }
7967                  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
7968                  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
7969                  if ($newPath != $path) {
7970                      continue;
7971                  }
7972                  $this->cookies[$i] = $newCookie;
7973                  $found = true;
7974                  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
7975                  break;
7976              }
7977              if (! $found) {
7978                  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
7979                  $this->cookies[] = $newCookie;
7980              }
7981          }
7982          return true;
7983      }
7984  }
7985  
7986  if (!extension_loaded('soap')) {
7987      /**

7988       *    For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.

7989       */
7990      class soapclient extends nusoap_client {
7991      }
7992  }
7993  ?>


Généré le : Thu Nov 29 09:42:17 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics