[ PHPXref.com ] [ Generated: Sun Jul 20 21:02:40 2008 ] [ Web Form Factory 0.1.2 ]
[ Index ]     [ Variables ]     [ Functions ]     [ Classes ]     [ Constants ]     [ Statistics ]

title

Body

[close]

/services/ -> nusoap.php (source)

   1  <?php
   2  
   3  /*
   4  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 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  If you have any questions or comments, please email:
  25  
  26  Dietrich Ayala
  27  dietrich@ganx4.com
  28  http://dietrich.ganx4.com/nusoap
  29  
  30  NuSphere Corporation
  31  http://www.nusphere.com
  32  
  33  */
  34  
  35  /* load classes
  36  
  37  // necessary classes
  38  require_once('class.soapclient.php');
  39  require_once('class.soap_val.php');
  40  require_once('class.soap_parser.php');
  41  require_once('class.soap_fault.php');
  42  
  43  // transport classes
  44  require_once('class.soap_transport_http.php');
  45  
  46  // optional add-on classes
  47  require_once('class.xmlschema.php');
  48  require_once('class.wsdl.php');
  49  
  50  // server class
  51  require_once('class.soap_server.php');*/
  52  
  53  // class variable emulation
  54  // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
  55  $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
  56  
  57  /**
  58  *
  59  * nusoap_base
  60  *
  61  * @author   Dietrich Ayala <dietrich@ganx4.com>
  62  * @version  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 snichol Exp $
  63  * @access   public
  64  */
  65  class nusoap_base {
  66      /**
  67       * Identification for HTTP headers.
  68       *
  69       * @var string
  70       * @access private
  71       */
  72      var $title = 'NuSOAP';
  73      /**
  74       * Version for HTTP headers.
  75       *
  76       * @var string
  77       * @access private
  78       */
  79      var $version = '0.7.2';
  80      /**
  81       * CVS revision for HTTP headers.
  82       *
  83       * @var string
  84       * @access private
  85       */
  86      var $revision = '$Revision: 1.95 $';
  87      /**
  88       * Current error string (manipulated by getError/setError)
  89       *
  90       * @var string
  91       * @access private
  92       */
  93      var $error_str = '';
  94      /**
  95       * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
  96       *
  97       * @var string
  98       * @access private
  99       */
 100      var $debug_str = '';
 101      /**
 102       * toggles automatic encoding of special characters as entities
 103       * (should always be true, I think)
 104       *
 105       * @var boolean
 106       * @access private
 107       */
 108      var $charencoding = true;
 109      /**
 110       * the debug level for this instance
 111       *
 112       * @var    integer
 113       * @access private
 114       */
 115      var $debugLevel;
 116  
 117      /**
 118      * set schema version
 119      *
 120      * @var      string
 121      * @access   public
 122      */
 123      var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
 124  
 125      /**
 126      * charset encoding for outgoing messages
 127      *
 128      * @var      string
 129      * @access   public
 130      */
 131      var $soap_defencoding = 'ISO-8859-1';
 132      //var $soap_defencoding = 'UTF-8';
 133  
 134      /**
 135      * namespaces in an array of prefix => uri
 136      *
 137      * this is "seeded" by a set of constants, but it may be altered by code
 138      *
 139      * @var      array
 140      * @access   public
 141      */
 142      var $namespaces = array(
 143          'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
 144          'xsd' => 'http://www.w3.org/2001/XMLSchema',
 145          'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
 146          'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
 147          );
 148  
 149      /**
 150      * namespaces used in the current context, e.g. during serialization
 151      *
 152      * @var      array
 153      * @access   private
 154      */
 155      var $usedNamespaces = array();
 156  
 157      /**
 158      * XML Schema types in an array of uri => (array of xml type => php type)
 159      * is this legacy yet?
 160      * no, this is used by the xmlschema class to verify type => namespace mappings.
 161      * @var      array
 162      * @access   public
 163      */
 164      var $typemap = array(
 165      'http://www.w3.org/2001/XMLSchema' => array(
 166          'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
 167          'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
 168          'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
 169          // abstract "any" types
 170          'anyType'=>'string','anySimpleType'=>'string',
 171          // derived datatypes
 172          'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
 173          'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
 174          'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
 175          'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
 176      'http://www.w3.org/2000/10/XMLSchema' => array(
 177          'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
 178          'float'=>'double','dateTime'=>'string',
 179          'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
 180      'http://www.w3.org/1999/XMLSchema' => array(
 181          'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
 182          'float'=>'double','dateTime'=>'string',
 183          'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
 184      'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
 185      'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
 186      'http://xml.apache.org/xml-soap' => array('Map')
 187      );
 188  
 189      /**
 190      * XML entities to convert
 191      *
 192      * @var      array
 193      * @access   public
 194      * @deprecated
 195      * @see    expandEntities
 196      */
 197      var $xmlEntities = array('quot' => '"','amp' => '&',
 198          'lt' => '<','gt' => '>','apos' => "'");
 199  
 200      /**
 201      * constructor
 202      *
 203      * @access    public
 204      */
 205  	function nusoap_base() {
 206          $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
 207      }
 208  
 209      /**
 210      * gets the global debug level, which applies to future instances
 211      *
 212      * @return    integer    Debug level 0-9, where 0 turns off
 213      * @access    public
 214      */
 215  	function getGlobalDebugLevel() {
 216          return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
 217      }
 218  
 219      /**
 220      * sets the global debug level, which applies to future instances
 221      *
 222      * @param    int    $level    Debug level 0-9, where 0 turns off
 223      * @access    public
 224      */
 225  	function setGlobalDebugLevel($level) {
 226          $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
 227      }
 228  
 229      /**
 230      * gets the debug level for this instance
 231      *
 232      * @return    int    Debug level 0-9, where 0 turns off
 233      * @access    public
 234      */
 235  	function getDebugLevel() {
 236          return $this->debugLevel;
 237      }
 238  
 239      /**
 240      * sets the debug level for this instance
 241      *
 242      * @param    int    $level    Debug level 0-9, where 0 turns off
 243      * @access    public
 244      */
 245  	function setDebugLevel($level) {
 246          $this->debugLevel = $level;
 247      }
 248  
 249      /**
 250      * adds debug data to the instance debug string with formatting
 251      *
 252      * @param    string $string debug data
 253      * @access   private
 254      */
 255  	function debug($string){
 256          if ($this->debugLevel > 0) {
 257              $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
 258          }
 259      }
 260  
 261      /**
 262      * adds debug data to the instance debug string without formatting
 263      *
 264      * @param    string $string debug data
 265      * @access   public
 266      */
 267  	function appendDebug($string){
 268          if ($this->debugLevel > 0) {
 269              // it would be nice to use a memory stream here to use
 270              // memory more efficiently
 271              $this->debug_str .= $string;
 272          }
 273      }
 274  
 275      /**
 276      * clears the current debug data for this instance
 277      *
 278      * @access   public
 279      */
 280  	function clearDebug() {
 281          // it would be nice to use a memory stream here to use
 282          // memory more efficiently
 283          $this->debug_str = '';
 284      }
 285  
 286      /**
 287      * gets the current debug data for this instance
 288      *
 289      * @return   debug data
 290      * @access   public
 291      */
 292      function &getDebug() {
 293          // it would be nice to use a memory stream here to use
 294          // memory more efficiently
 295          return $this->debug_str;
 296      }
 297  
 298      /**
 299      * gets the current debug data for this instance as an XML comment
 300      * this may change the contents of the debug data
 301      *
 302      * @return   debug data as an XML comment
 303      * @access   public
 304      */
 305      function &getDebugAsXMLComment() {
 306          // it would be nice to use a memory stream here to use
 307          // memory more efficiently
 308          while (strpos($this->debug_str, '--')) {
 309              $this->debug_str = str_replace('--', '- -', $this->debug_str);
 310          }
 311          return "<!--\n" . $this->debug_str . "\n-->";
 312      }
 313  
 314      /**
 315      * expands entities, e.g. changes '<' to '&lt;'.
 316      *
 317      * @param    string    $val    The string in which to expand entities.
 318      * @access    private
 319      */
 320  	function expandEntities($val) {
 321          if ($this->charencoding) {
 322              $val = str_replace('&', '&amp;', $val);
 323              $val = str_replace("'", '&apos;', $val);
 324              $val = str_replace('"', '&quot;', $val);
 325              $val = str_replace('<', '&lt;', $val);
 326              $val = str_replace('>', '&gt;', $val);
 327          }
 328          return $val;
 329      }
 330  
 331      /**
 332      * returns error string if present
 333      *
 334      * @return   mixed error string or false
 335      * @access   public
 336      */
 337  	function getError(){
 338          if($this->error_str != ''){
 339              return $this->error_str;
 340          }
 341          return false;
 342      }
 343  
 344      /**
 345      * sets error string
 346      *
 347      * @return   boolean $string error string
 348      * @access   private
 349      */
 350  	function setError($str){
 351          $this->error_str = $str;
 352      }
 353  
 354      /**
 355      * detect if array is a simple array or a struct (associative array)
 356      *
 357      * @param    mixed    $val    The PHP array
 358      * @return    string    (arraySimple|arrayStruct)
 359      * @access    private
 360      */
 361  	function isArraySimpleOrStruct($val) {
 362          $keyList = array_keys($val);
 363          foreach ($keyList as $keyListValue) {
 364              if (!is_int($keyListValue)) {
 365                  return 'arrayStruct';
 366              }
 367          }
 368          return 'arraySimple';
 369      }
 370  
 371      /**
 372      * serializes PHP values in accordance w/ section 5. Type information is
 373      * not serialized if $use == 'literal'.
 374      *
 375      * @param    mixed    $val    The value to serialize
 376      * @param    string    $name    The name (local part) of the XML element
 377      * @param    string    $type    The XML schema type (local part) for the element
 378      * @param    string    $name_ns    The namespace for the name of the XML element
 379      * @param    string    $type_ns    The namespace for the type of the element
 380      * @param    array    $attributes    The attributes to serialize as name=>value pairs
 381      * @param    string    $use    The WSDL "use" (encoded|literal)
 382      * @return    string    The serialized element, possibly with child elements
 383      * @access    public
 384      */
 385  	function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
 386          $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
 387          $this->appendDebug('value=' . $this->varDump($val));
 388          $this->appendDebug('attributes=' . $this->varDump($attributes));
 389  
 390          if(is_object($val) && get_class($val) == 'soapval'){
 391              return $val->serialize($use);
 392          }
 393          // force valid name if necessary
 394          if (is_numeric($name)) {
 395              $name = '__numeric_' . $name;
 396          } elseif (! $name) {
 397              $name = 'noname';
 398          }
 399          // if name has ns, add ns prefix to name
 400          $xmlns = '';
 401          if($name_ns){
 402              $prefix = 'nu'.rand(1000,9999);
 403              $name = $prefix.':'.$name;
 404              $xmlns .= " xmlns:$prefix=\"$name_ns\"";
 405          }
 406          // if type is prefixed, create type prefix
 407          if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
 408              // need to fix this. shouldn't default to xsd if no ns specified
 409              // w/o checking against typemap
 410              $type_prefix = 'xsd';
 411          } elseif($type_ns){
 412              $type_prefix = 'ns'.rand(1000,9999);
 413              $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
 414          }
 415          // serialize attributes if present
 416          $atts = '';
 417          if($attributes){
 418              foreach($attributes as $k => $v){
 419                  $atts .= " $k=\"".$this->expandEntities($v).'"';
 420              }
 421          }
 422          // serialize null value
 423          if (is_null($val)) {
 424              if ($use == 'literal') {
 425                  // TODO: depends on minOccurs
 426                  return "<$name$xmlns $atts/>";
 427              } else {
 428                  if (isset($type) && isset($type_prefix)) {
 429                      $type_str = " xsi:type=\"$type_prefix:$type\"";
 430                  } else {
 431                      $type_str = '';
 432                  }
 433                  return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
 434              }
 435          }
 436          // serialize if an xsd built-in primitive type
 437          if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
 438              if (is_bool($val)) {
 439                  if ($type == 'boolean') {
 440                      $val = $val ? 'true' : 'false';
 441                  } elseif (! $val) {
 442                      $val = 0;
 443                  }
 444              } else if (is_string($val)) {
 445                  $val = $this->expandEntities($val);
 446              }
 447              if ($use == 'literal') {
 448                  return "<$name$xmlns $atts>$val</$name>";
 449              } else {
 450                  return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>";
 451              }
 452          }
 453          // detect type and serialize
 454          $xml = '';
 455          switch(true) {
 456              case (is_bool($val) || $type == 'boolean'):
 457                  if ($type == 'boolean') {
 458                      $val = $val ? 'true' : 'false';
 459                  } elseif (! $val) {
 460                      $val = 0;
 461                  }
 462                  if ($use == 'literal') {
 463                      $xml .= "<$name$xmlns $atts>$val</$name>";
 464                  } else {
 465                      $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
 466                  }
 467                  break;
 468              case (is_int($val) || is_long($val) || $type == 'int'):
 469                  if ($use == 'literal') {
 470                      $xml .= "<$name$xmlns $atts>$val</$name>";
 471                  } else {
 472                      $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
 473                  }
 474                  break;
 475              case (is_float($val)|| is_double($val) || $type == 'float'):
 476                  if ($use == 'literal') {
 477                      $xml .= "<$name$xmlns $atts>$val</$name>";
 478                  } else {
 479                      $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
 480                  }
 481                  break;
 482              case (is_string($val) || $type == 'string'):
 483                  $val = $this->expandEntities($val);
 484                  if ($use == 'literal') {
 485                      $xml .= "<$name$xmlns $atts>$val</$name>";
 486                  } else {
 487                      $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
 488                  }
 489                  break;
 490              case is_object($val):
 491                  if (! $name) {
 492                      $name = get_class($val);
 493                      $this->debug("In serialize_val, used class name $name as element name");
 494                  } else {
 495                      $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
 496                  }
 497                  foreach(get_object_vars($val) as $k => $v){
 498                      $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
 499                  }
 500                  $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
 501                  break;
 502              break;
 503              case (is_array($val) || $type):
 504                  // detect if struct or array
 505                  $valueType = $this->isArraySimpleOrStruct($val);
 506                  if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
 507                      $i = 0;
 508                      if(is_array($val) && count($val)> 0){
 509                          foreach($val as $v){
 510                              if(is_object($v) && get_class($v) ==  'soapval'){
 511                                  $tt_ns = $v->type_ns;
 512                                  $tt = $v->type;
 513                              } elseif (is_array($v)) {
 514                                  $tt = $this->isArraySimpleOrStruct($v);
 515                              } else {
 516                                  $tt = gettype($v);
 517                              }
 518                              $array_types[$tt] = 1;
 519                              // TODO: for literal, the name should be $name
 520                              $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
 521                              ++$i;
 522                          }
 523                          if(count($array_types) > 1){
 524                              $array_typename = 'xsd:anyType';
 525                          } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
 526                              if ($tt == 'integer') {
 527                                  $tt = 'int';
 528                              }
 529                              $array_typename = 'xsd:'.$tt;
 530                          } elseif(isset($tt) && $tt == 'arraySimple'){
 531                              $array_typename = 'SOAP-ENC:Array';
 532                          } elseif(isset($tt) && $tt == 'arrayStruct'){
 533                              $array_typename = 'unnamed_struct_use_soapval';
 534                          } else {
 535                              // if type is prefixed, create type prefix
 536                              if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
 537                                   $array_typename = 'xsd:' . $tt;
 538                              } elseif ($tt_ns) {
 539                                  $tt_prefix = 'ns' . rand(1000, 9999);
 540                                  $array_typename = "$tt_prefix:$tt";
 541                                  $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
 542                              } else {
 543                                  $array_typename = $tt;
 544                              }
 545                          }
 546                          $array_type = $i;
 547                          if ($use == 'literal') {
 548                              $type_str = '';
 549                          } else if (isset($type) && isset($type_prefix)) {
 550                              $type_str = " xsi:type=\"$type_prefix:$type\"";
 551                          } else {
 552                              $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
 553                          }
 554                      // empty array
 555                      } else {
 556                          if ($use == 'literal') {
 557                              $type_str = '';
 558                          } else if (isset($type) && isset($type_prefix)) {
 559                              $type_str = " xsi:type=\"$type_prefix:$type\"";
 560                          } else {
 561                              $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
 562                          }
 563                      }
 564                      // TODO: for array in literal, there is no wrapper here
 565                      $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
 566                  } else {
 567                      // got a struct
 568                      if(isset($type) && isset($type_prefix)){
 569                          $type_str = " xsi:type=\"$type_prefix:$type\"";
 570                      } else {
 571                          $type_str = '';
 572                      }
 573                      if ($use == 'literal') {
 574                          $xml .= "<$name$xmlns $atts>";
 575                      } else {
 576                          $xml .= "<$name$xmlns$type_str$atts>";
 577                      }
 578                      foreach($val as $k => $v){
 579                          // Apache Map
 580                          if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
 581                              $xml .= '<item>';
 582                              $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
 583                              $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
 584                              $xml .= '</item>';
 585                          } else {
 586                              $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
 587                          }
 588                      }
 589                      $xml .= "</$name>";
 590                  }
 591                  break;
 592              default:
 593                  $xml .= 'not detected, got '.gettype($val).' for '.$val;
 594                  break;
 595          }
 596          return $xml;
 597      }
 598  
 599      /**
 600      * serializes a message
 601      *
 602      * @param string $body the XML of the SOAP body
 603      * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers
 604      * @param array $namespaces optional the namespaces used in generating the body and headers
 605      * @param string $style optional (rpc|document)
 606      * @param string $use optional (encoded|literal)
 607      * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
 608      * @return string the message
 609      * @access public
 610      */
 611      function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
 612      // TODO: add an option to automatically run utf8_encode on $body and $headers
 613      // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
 614      // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
 615  
 616      $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
 617      $this->debug("headers:");
 618      $this->appendDebug($this->varDump($headers));
 619      $this->debug("namespaces:");
 620      $this->appendDebug($this->varDump($namespaces));
 621  
 622      // serialize namespaces
 623      $ns_string = '';
 624      foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
 625          $ns_string .= " xmlns:$k=\"$v\"";
 626      }
 627      if($encodingStyle) {
 628          $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
 629      }
 630  
 631      // serialize headers
 632      if($headers){
 633          if (is_array($headers)) {
 634              $xml = '';
 635              foreach ($headers as $header) {
 636                  $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
 637              }
 638              $headers = $xml;
 639              $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
 640          }
 641          $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
 642      }
 643      // serialize envelope
 644      return
 645      '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
 646      '<SOAP-ENV:Envelope'.$ns_string.">".
 647      $headers.
 648      "<SOAP-ENV:Body>".
 649          $body.
 650      "</SOAP-ENV:Body>".
 651      "</SOAP-ENV:Envelope>";
 652      }
 653  
 654      /**
 655       * formats a string to be inserted into an HTML stream
 656       *
 657       * @param string $str The string to format
 658       * @return string The formatted string
 659       * @access public
 660       * @deprecated
 661       */
 662      function formatDump($str){
 663          $str = htmlspecialchars($str);
 664          return nl2br($str);
 665      }
 666  
 667      /**
 668      * contracts (changes namespace to prefix) a qualified name
 669      *
 670      * @param    string $qname qname
 671      * @return    string contracted qname
 672      * @access   private
 673      */
 674  	function contractQname($qname){
 675          // get element namespace
 676          //$this->xdebug("Contract $qname");
 677          if (strrpos($qname, ':')) {
 678              // get unqualified name
 679              $name = substr($qname, strrpos($qname, ':') + 1);
 680              // get ns
 681              $ns = substr($qname, 0, strrpos($qname, ':'));
 682              $p = $this->getPrefixFromNamespace($ns);
 683              if ($p) {
 684                  return $p . ':' . $name;
 685              }
 686              return $qname;
 687          } else {
 688              return $qname;
 689          }
 690      }
 691  
 692      /**
 693      * expands (changes prefix to namespace) a qualified name
 694      *
 695      * @param    string $string qname
 696      * @return    string expanded qname
 697      * @access   private
 698      */
 699  	function expandQname($qname){
 700          // get element prefix
 701          if(strpos($qname,':') && !ereg('^http://',$qname)){
 702              // get unqualified name
 703              $name = substr(strstr($qname,':'),1);
 704              // get ns prefix
 705              $prefix = substr($qname,0,strpos($qname,':'));
 706              if(isset($this->namespaces[$prefix])){
 707                  return $this->namespaces[$prefix].':'.$name;
 708              } else {
 709                  return $qname;
 710              }
 711          } else {
 712              return $qname;
 713          }
 714      }
 715  
 716      /**
 717      * returns the local part of a prefixed string
 718      * returns the original string, if not prefixed
 719      *
 720      * @param string $str The prefixed string
 721      * @return string The local part
 722      * @access public
 723      */
 724  	function getLocalPart($str){
 725          if($sstr = strrchr($str,':')){
 726              // get unqualified name
 727              return substr( $sstr, 1 );
 728          } else {
 729              return $str;
 730          }
 731      }
 732  
 733      /**
 734      * returns the prefix part of a prefixed string
 735      * returns false, if not prefixed
 736      *
 737      * @param string $str The prefixed string
 738      * @return mixed The prefix or false if there is no prefix
 739      * @access public
 740      */
 741  	function getPrefix($str){
 742          if($pos = strrpos($str,':')){
 743              // get prefix
 744              return substr($str,0,$pos);
 745          }
 746          return false;
 747      }
 748  
 749      /**
 750      * pass it a prefix, it returns a namespace
 751      *
 752      * @param string $prefix The prefix
 753      * @return mixed The namespace, false if no namespace has the specified prefix
 754      * @access public
 755      */
 756  	function getNamespaceFromPrefix($prefix){
 757          if (isset($this->namespaces[$prefix])) {
 758              return $this->namespaces[$prefix];
 759          }
 760          //$this->setError("No namespace registered for prefix '$prefix'");
 761          return false;
 762      }
 763  
 764      /**
 765      * returns the prefix for a given namespace (or prefix)
 766      * or false if no prefixes registered for the given namespace
 767      *
 768      * @param string $ns The namespace
 769      * @return mixed The prefix, false if the namespace has no prefixes
 770      * @access public
 771      */
 772  	function getPrefixFromNamespace($ns) {
 773          foreach ($this->namespaces as $p => $n) {
 774              if ($ns == $n || $ns == $p) {
 775                  $this->usedNamespaces[$p] = $n;
 776                  return $p;
 777              }
 778          }
 779          return false;
 780      }
 781  
 782      /**
 783      * returns the time in ODBC canonical form with microseconds
 784      *
 785      * @return string The time in ODBC canonical form with microseconds
 786      * @access public
 787      */
 788  	function getmicrotime() {
 789          if (function_exists('gettimeofday')) {
 790              $tod = gettimeofday();
 791              $sec = $tod['sec'];
 792              $usec = $tod['usec'];
 793          } else {
 794              $sec = time();
 795              $usec = 0;
 796          }
 797          return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
 798      }
 799  
 800      /**
 801       * Returns a string with the output of var_dump
 802       *
 803       * @param mixed $data The variable to var_dump
 804       * @return string The output of var_dump
 805       * @access public
 806       */
 807      function varDump($data) {
 808          ob_start();
 809          var_dump($data);
 810          $ret_val = ob_get_contents();
 811          ob_end_clean();
 812          return $ret_val;
 813      }
 814  }
 815  
 816  // XML Schema Datatype Helper Functions
 817  
 818  //xsd:dateTime helpers
 819  
 820  /**
 821  * convert unix timestamp to ISO 8601 compliant date string
 822  *
 823  * @param    string $timestamp Unix time stamp
 824  * @access   public
 825  */
 826  function timestamp_to_iso8601($timestamp,$utc=true){
 827      $datestr = date('Y-m-d\TH:i:sO',$timestamp);
 828      if($utc){
 829          $eregStr =
 830          '([0-9]{4})-'.    // centuries & years CCYY-
 831          '([0-9]{2})-'.    // months MM-
 832          '([0-9]{2})'.    // days DD
 833          'T'.            // separator T
 834          '([0-9]{2}):'.    // hours hh:
 835          '([0-9]{2}):'.    // minutes mm:
 836          '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
 837          '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
 838  
 839          if(ereg($eregStr,$datestr,$regs)){
 840              return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
 841          }
 842          return false;
 843      } else {
 844          return $datestr;
 845      }
 846  }
 847  
 848  /**
 849  * convert ISO 8601 compliant date string to unix timestamp
 850  *
 851  * @param    string $datestr ISO 8601 compliant date string
 852  * @access   public
 853  */
 854  function iso8601_to_timestamp($datestr){
 855      $eregStr =
 856      '([0-9]{4})-'.    // centuries & years CCYY-
 857      '([0-9]{2})-'.    // months MM-
 858      '([0-9]{2})'.    // days DD
 859      'T'.            // separator T
 860      '([0-9]{2}):'.    // hours hh:
 861      '([0-9]{2}):'.    // minutes mm:
 862      '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
 863      '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
 864      if(ereg($eregStr,$datestr,$regs)){
 865          // not utc
 866          if($regs[8] != 'Z'){
 867              $op = substr($regs[8],0,1);
 868              $h = substr($regs[8],1,2);
 869              $m = substr($regs[8],strlen($regs[8])-2,2);
 870              if($op == '-'){
 871                  $regs[4] = $regs[4] + $h;
 872                  $regs[5] = $regs[5] + $m;
 873              } elseif($op == '+'){
 874                  $regs[4] = $regs[4] - $h;
 875                  $regs[5] = $regs[5] - $m;
 876              }
 877          }
 878          return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
 879      } else {
 880          return false;
 881      }
 882  }
 883  
 884  /**
 885  * sleeps some number of microseconds
 886  *
 887  * @param    string $usec the number of microseconds to sleep
 888  * @access   public
 889  * @deprecated
 890  */
 891  function usleepWindows($usec)
 892  {
 893      $start = gettimeofday();
 894  
 895      do
 896      {
 897          $stop = gettimeofday();
 898          $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
 899          + $stop['usec'] - $start['usec'];
 900      }
 901      while ($timePassed < $usec);
 902  }
 903  
 904  ?><?php
 905  
 906  
 907  
 908  /**
 909  * Contains information for a SOAP fault.
 910  * Mainly used for returning faults from deployed functions
 911  * in a server instance.
 912  * @author   Dietrich Ayala <dietrich@ganx4.com>
 913  * @version  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 snichol Exp $
 914  * @access public
 915  */
 916  class soap_fault extends nusoap_base {
 917      /**
 918       * The fault code (client|server)
 919       * @var string
 920       * @access private
 921       */
 922      var $faultcode;
 923      /**
 924       * The fault actor
 925       * @var string
 926       * @access private
 927       */
 928      var $faultactor;
 929      /**
 930       * The fault string, a description of the fault
 931       * @var string
 932       * @access private
 933       */
 934      var $faultstring;
 935      /**
 936       * The fault detail, typically a string or array of string
 937       * @var mixed
 938       * @access private
 939       */
 940      var $faultdetail;
 941  
 942      /**
 943      * constructor
 944      *
 945      * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
 946      * @param string $faultactor only used when msg routed between multiple actors
 947      * @param string $faultstring human readable error message
 948      * @param mixed $faultdetail detail, typically a string or array of string
 949      */
 950  	function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
 951          parent::nusoap_base();
 952          $this->faultcode = $faultcode;
 953          $this->faultactor = $faultactor;
 954          $this->faultstring = $faultstring;
 955          $this->faultdetail = $faultdetail;
 956      }
 957  
 958      /**
 959      * serialize a fault
 960      *
 961      * @return    string    The serialization of the fault instance.
 962      * @access   public
 963      */
 964  	function serialize(){
 965          $ns_string = '';
 966          foreach($this->namespaces as $k => $v){
 967              $ns_string .= "\n  xmlns:$k=\"$v\"";
 968          }
 969          $return_msg =
 970              '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
 971              '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
 972                  '<SOAP-ENV:Body>'.
 973                  '<SOAP-ENV:Fault>'.
 974                      $this->serialize_val($this->faultcode, 'faultcode').
 975                      $this->serialize_val($this->faultactor, 'faultactor').
 976                      $this->serialize_val($this->faultstring, 'faultstring').
 977                      $this->serialize_val($this->faultdetail, 'detail').
 978                  '</SOAP-ENV:Fault>'.
 979                  '</SOAP-ENV:Body>'.
 980              '</SOAP-ENV:Envelope>';
 981          return $return_msg;
 982      }
 983  }
 984  
 985  
 986  
 987  ?><?php
 988  
 989  
 990  
 991  /**
 992  * parses an XML Schema, allows access to it's data, other utility methods
 993  * no validation... yet.
 994  * very experimental and limited. As is discussed on XML-DEV, I'm one of the people
 995  * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
 996  * tutorials I refer to :)
 997  *
 998  * @author   Dietrich Ayala <dietrich@ganx4.com>
 999  * @version  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 snichol Exp $
1000  * @access   public
1001  */
1002  class XMLSchema extends nusoap_base  {
1003  
1004      // files
1005      var $schema = '';
1006      var $xml = '';
1007      // namespaces
1008      var $enclosingNamespaces;
1009      // schema info
1010      var $schemaInfo = array();
1011      var $schemaTargetNamespace = '';
1012      // types, elements, attributes defined by the schema
1013      var $attributes = array();
1014      var $complexTypes = array();
1015      var $complexTypeStack = array();
1016      var $currentComplexType = null;
1017      var $elements = array();
1018      var $elementStack = array();
1019      var $currentElement = null;
1020      var $simpleTypes = array();
1021      var $simpleTypeStack = array();
1022      var $currentSimpleType = null;
1023      // imports
1024      var $imports = array();
1025      // parser vars
1026      var $parser;
1027      var $position = 0;
1028      var $depth = 0;
1029      var $depth_array = array();
1030      var $message = array();
1031      var $defaultNamespace = array();
1032  
1033      /**
1034      * constructor
1035      *
1036      * @param    string $schema schema document URI
1037      * @param    string $xml xml document URI
1038      * @param    string $namespaces namespaces defined in enclosing XML
1039      * @access   public
1040      */
1041  	function XMLSchema($schema='',$xml='',$namespaces=array()){
1042          parent::nusoap_base();
1043          $this->debug('xmlschema class instantiated, inside constructor');
1044          // files
1045          $this->schema = $schema;
1046          $this->xml = $xml;
1047  
1048          // namespaces
1049          $this->enclosingNamespaces = $namespaces;
1050          $this->namespaces = array_merge($this->namespaces, $namespaces);
1051  
1052          // parse schema file
1053          if($schema != ''){
1054              $this->debug('initial schema file: '.$schema);
1055              $this->parseFile($schema, 'schema');
1056          }
1057  
1058          // parse xml file
1059          if($xml != ''){
1060              $this->debug('initial xml file: '.$xml);
1061              $this->parseFile($xml, 'xml');
1062          }
1063  
1064      }
1065  
1066      /**
1067      * parse an XML file
1068      *
1069      * @param string $xml, path/URL to XML file
1070      * @param string $type, (schema | xml)
1071      * @return boolean
1072      * @access public
1073      */
1074  	function parseFile($xml,$type){
1075          // parse xml file
1076          if($xml != ""){
1077              $xmlStr = @join("",@file($xml));
1078              if($xmlStr == ""){
1079                  $msg = 'Error reading XML from '.$xml;
1080                  $this->setError($msg);
1081                  $this->debug($msg);
1082              return false;
1083              } else {
1084                  $this->debug("parsing $xml");
1085                  $this->parseString($xmlStr,$type);
1086                  $this->debug("done parsing $xml");
1087              return true;
1088              }
1089          }
1090          return false;
1091      }
1092  
1093      /**
1094      * parse an XML string
1095      *
1096      * @param    string $xml path or URL
1097      * @param string $type, (schema|xml)
1098      * @access   private
1099      */
1100  	function parseString($xml,$type){
1101          // parse xml string
1102          if($xml != ""){
1103  
1104              // Create an XML parser.
1105              $this->parser = xml_parser_create();
1106              // Set the options for parsing the XML data.
1107              xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1108  
1109              // Set the object for the parser.
1110              xml_set_object($this->parser, $this);
1111  
1112              // Set the element handlers for the parser.
1113              if($type == "schema"){
1114                  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1115                  xml_set_character_data_handler($this->parser,'schemaCharacterData');
1116              } elseif($type == "xml"){
1117                  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1118                  xml_set_character_data_handler($this->parser,'xmlCharacterData');
1119              }
1120  
1121              // Parse the XML file.
1122              if(!xml_parse($this->parser,$xml,true)){
1123              // Display an error message.
1124                  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1125                  xml_get_current_line_number($this->parser),
1126                  xml_error_string(xml_get_error_code($this->parser))
1127                  );
1128                  $this->debug($errstr);
1129                  $this->debug("XML payload:\n" . $xml);
1130                  $this->setError($errstr);
1131              }
1132  
1133              xml_parser_free($this->parser);
1134          } else{
1135              $this->debug('no xml passed to parseString()!!');
1136              $this->setError('no xml passed to parseString()!!');
1137          }
1138      }
1139  
1140      /**
1141      * start-element handler
1142      *
1143      * @param    string $parser XML parser object
1144      * @param    string $name element name
1145      * @param    string $attrs associative array of attributes
1146      * @access   private
1147      */
1148  	function schemaStartElement($parser, $name, $attrs) {
1149  
1150          // position in the total number of elements, starting from 0
1151          $pos = $this->position++;
1152          $depth = $this->depth++;
1153          // set self as current value for this depth
1154          $this->depth_array[$depth] = $pos;
1155          $this->message[$pos] = array('cdata' => '');
1156          if ($depth > 0) {
1157              $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1158          } else {
1159              $this->defaultNamespace[$pos] = false;
1160          }
1161  
1162          // get element prefix
1163          if($prefix = $this->getPrefix($name)){
1164              // get unqualified name
1165              $name = $this->getLocalPart($name);
1166          } else {
1167              $prefix = '';
1168          }
1169  
1170          // loop thru attributes, expanding, and registering namespace declarations
1171          if(count($attrs) > 0){
1172              foreach($attrs as $k => $v){
1173                  // if ns declarations, add to class level array of valid namespaces
1174                  if(ereg("^xmlns",$k)){
1175                      //$this->xdebug("$k: $v");
1176                      //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1177                      if($ns_prefix = substr(strrchr($k,':'),1)){
1178                          //$this->xdebug("Add namespace[$ns_prefix] = $v");
1179                          $this->namespaces[$ns_prefix] = $v;
1180                      } else {
1181                          $this->defaultNamespace[$pos] = $v;
1182                          if (! $this->getPrefixFromNamespace($v)) {
1183                              $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1184                          }
1185                      }
1186                      if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1187                          $this->XMLSchemaVersion = $v;
1188                          $this->namespaces['xsi'] = $v.'-instance';
1189                      }
1190                  }
1191              }
1192              foreach($attrs as $k => $v){
1193                  // expand each attribute
1194                  $k = strpos($k,':') ? $this->expandQname($k) : $k;
1195                  $v = strpos($v,':') ? $this->expandQname($v) : $v;
1196                  $eAttrs[$k] = $v;
1197              }
1198              $attrs = $eAttrs;
1199          } else {
1200              $attrs = array();
1201          }
1202          // find status, register data
1203          switch($name){
1204              case 'all':            // (optional) compositor content for a complexType
1205              case 'choice':
1206              case 'group':
1207              case 'sequence':
1208                  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1209                  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1210                  //if($name == 'all' || $name == 'sequence'){
1211                  //    $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1212                  //}
1213              break;
1214              case 'attribute':    // complexType attribute
1215                  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1216                  $this->xdebug("parsing attribute:");
1217                  $this->appendDebug($this->varDump($attrs));
1218                  if (!isset($attrs['form'])) {
1219                      $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1220                  }
1221                  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1222                      $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1223                      if (!strpos($v, ':')) {
1224                          // no namespace in arrayType attribute value...
1225                          if ($this->defaultNamespace[$pos]) {
1226                              // ...so use the default
1227                              $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1228                          }
1229                      }
1230                  }
1231                  if(isset($attrs['name'])){
1232                      $this->attributes[$attrs['name']] = $attrs;
1233                      $aname = $attrs['name'];
1234                  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1235                      if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1236                          $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1237                      } else {
1238                          $aname = '';
1239                      }
1240                  } elseif(isset($attrs['ref'])){
1241                      $aname = $attrs['ref'];
1242                      $this->attributes[$attrs['ref']] = $attrs;
1243                  }
1244  
1245                  if($this->currentComplexType){    // This should *always* be
1246                      $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1247                  }
1248                  // arrayType attribute
1249                  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1250                      $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1251                      $prefix = $this->getPrefix($aname);
1252                      if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1253                          $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1254                      } else {
1255                          $v = '';
1256                      }
1257                      if(strpos($v,'[,]')){
1258                          $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1259                      }
1260                      $v = substr($v,0,strpos($v,'[')); // clip the []
1261                      if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1262                          $v = $this->XMLSchemaVersion.':'.$v;
1263                      }
1264                      $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1265                  }
1266              break;
1267              case 'complexContent':    // (optional) content for a complexType
1268              break;
1269              case 'complexType':
1270                  array_push($this->complexTypeStack, $this->currentComplexType);
1271                  if(isset($attrs['name'])){
1272                      $this->xdebug('processing named complexType '.$attrs['name']);
1273                      //$this->currentElement = false;
1274                      $this->currentComplexType = $attrs['name'];
1275                      $this->complexTypes[$this->currentComplexType] = $attrs;
1276                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1277                      // This is for constructs like
1278                      //           <complexType name="ListOfString" base="soap:Array">
1279                      //                <sequence>
1280                      //                    <element name="string" type="xsd:string"
1281                      //                        minOccurs="0" maxOccurs="unbounded" />
1282                      //                </sequence>
1283                      //            </complexType>
1284                      if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1285                          $this->xdebug('complexType is unusual array');
1286                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1287                      } else {
1288                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1289                      }
1290                  }else{
1291                      $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
1292                      $this->currentComplexType = $this->currentElement . '_ContainedType';
1293                      //$this->currentElement = false;
1294                      $this->complexTypes[$this->currentComplexType] = $attrs;
1295                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1296                      // This is for constructs like
1297                      //           <complexType name="ListOfString" base="soap:Array">
1298                      //                <sequence>
1299                      //                    <element name="string" type="xsd:string"
1300                      //                        minOccurs="0" maxOccurs="unbounded" />
1301                      //                </sequence>
1302                      //            </complexType>
1303                      if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1304                          $this->xdebug('complexType is unusual array');
1305                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1306                      } else {
1307                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1308                      }
1309                  }
1310              break;
1311              case 'element':
1312                  array_push($this->elementStack, $this->currentElement);
1313                  // elements defined as part of a complex type should
1314                  // not really be added to $this->elements, but for some
1315                  // reason, they are
1316                  if (!isset($attrs['form'])) {
1317                      $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1318                  }
1319                  if(isset($attrs['type'])){
1320                      $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1321                      if (! $this->getPrefix($attrs['type'])) {
1322                          if ($this->defaultNamespace[$pos]) {
1323                              $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1324                              $this->xdebug('used default namespace to make type ' . $attrs['type']);
1325                          }
1326                      }
1327                      // This is for constructs like
1328                      //           <complexType name="ListOfString" base="soap:Array">
1329                      //                <sequence>
1330                      //                    <element name="string" type="xsd:string"
1331                      //                        minOccurs="0" maxOccurs="unbounded" />
1332                      //                </sequence>
1333                      //            </complexType>
1334                      if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1335                          $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1336                          $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1337                      }
1338                      $this->currentElement = $attrs['name'];
1339                      $this->elements[ $attrs['name'] ] = $attrs;
1340                      $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1341                      $ename = $attrs['name'];
1342                  } elseif(isset($attrs['ref'])){
1343                      $this->xdebug("processing element as ref to ".$attrs['ref']);
1344                      $this->currentElement = "ref to ".$attrs['ref'];
1345                      $ename = $this->getLocalPart($attrs['ref']);
1346                  } else {
1347                      $this->xdebug("processing untyped element ".$attrs['name']);
1348                      $this->currentElement = $attrs['name'];
1349                      $this->elements[ $attrs['name'] ] = $attrs;
1350                      $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1351                      $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
1352                      $this->elements[ $attrs['name'] ]['type'] = $attrs['type'];
1353                      $ename = $attrs['name'];
1354                  }
1355                  if(isset($ename) && $this->currentComplexType){
1356                      $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1357                  }
1358              break;
1359              case 'enumeration':    //    restriction value list member
1360                  $this->xdebug('enumeration ' . $attrs['value']);
1361                  if ($this->currentSimpleType) {
1362                      $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1363                  } elseif ($this->currentComplexType) {
1364                      $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1365                  }
1366              break;
1367              case 'extension':    // simpleContent or complexContent type extension
1368                  $this->xdebug('extension ' . $attrs['base']);
1369                  if ($this->currentComplexType) {
1370                      $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1371                  }
1372              break;
1373              case 'import':
1374                  if (isset($attrs['schemaLocation'])) {
1375                      //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1376                      $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1377                  } else {
1378                      //$this->xdebug('import namespace ' . $attrs['namespace']);
1379                      $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1380                      if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1381                          $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1382                      }
1383                  }
1384              break;
1385              case 'list':    // simpleType value list
1386              break;
1387              case 'restriction':    // simpleType, simpleContent or complexContent value restriction
1388                  $this->xdebug('restriction ' . $attrs['base']);
1389                  if($this->currentSimpleType){
1390                      $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1391                  } elseif($this->currentComplexType){
1392                      $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1393                      if(strstr($attrs['base'],':') == ':Array'){
1394                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1395                      }
1396                  }
1397              break;
1398              case 'schema':
1399                  $this->schemaInfo = $attrs;
1400                  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1401                  if (isset($attrs['targetNamespace'])) {
1402                      $this->schemaTargetNamespace = $attrs['targetNamespace'];
1403                  }
1404                  if (!isset($attrs['elementFormDefault'])) {
1405                      $this->schemaInfo['elementFormDefault'] = 'unqualified';
1406                  }
1407                  if (!isset($attrs['attributeFormDefault'])) {
1408                      $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1409                  }
1410              break;
1411              case 'simpleContent':    // (optional) content for a complexType
1412              break;
1413              case 'simpleType':
1414                  array_push($this->simpleTypeStack, $this->currentSimpleType);
1415                  if(isset($attrs['name'])){
1416                      $this->xdebug("processing simpleType for name " . $attrs['name']);
1417                      $this->currentSimpleType = $attrs['name'];
1418                      $this->simpleTypes[ $attrs['name'] ] = $attrs;
1419                      $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1420                      $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1421                  } else {
1422                      $this->xdebug('processing unnamed simpleType for element '.$this->currentElement);
1423                      $this->currentSimpleType = $this->currentElement . '_ContainedType';
1424                      //$this->currentElement = false;
1425                      $this->simpleTypes[$this->currentSimpleType] = $attrs;
1426                      $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1427                  }
1428              break;
1429              case 'union':    // simpleType type list
1430              break;
1431              default:
1432                  //$this->xdebug("do not have anything to do for element $name");
1433          }
1434      }
1435  
1436      /**
1437      * end-element handler
1438      *
1439      * @param    string $parser XML parser object
1440      * @param    string $name element name
1441      * @access   private
1442      */
1443  	function schemaEndElement($parser, $name) {
1444          // bring depth down a notch
1445          $this->depth--;
1446          // position of current element is equal to the last value left in depth_array for my depth
1447          if(isset($this->depth_array[$this->depth])){
1448              $pos = $this->depth_array[$this->depth];
1449          }
1450          // get element prefix
1451          if ($prefix = $this->getPrefix($name)){
1452              // get unqualified name
1453              $name = $this->getLocalPart($name);
1454          } else {
1455              $prefix = '';
1456          }
1457          // move on...
1458          if($name == 'complexType'){
1459              $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1460              $this->currentComplexType = array_pop($this->complexTypeStack);
1461              //$this->currentElement = false;
1462          }
1463          if($name == 'element'){
1464              $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1465              $this->currentElement = array_pop($this->elementStack);
1466          }
1467          if($name == 'simpleType'){
1468              $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1469              $this->currentSimpleType = array_pop($this->simpleTypeStack);
1470          }
1471      }
1472  
1473      /**
1474      * element content handler
1475      *
1476      * @param    string $parser XML parser object
1477      * @param    string $data element content
1478      * @access   private
1479      */
1480  	function schemaCharacterData($parser, $data){
1481          $pos = $this->depth_array[$this->depth - 1];
1482          $this->message[$pos]['cdata'] .= $data;
1483      }
1484  
1485      /**
1486      * serialize the schema
1487      *
1488      * @access   public
1489      */
1490  	function serializeSchema(){
1491  
1492          $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1493          $xml = '';
1494          // imports
1495          if (sizeof($this->imports) > 0) {
1496              foreach($this->imports as $ns => $list) {
1497                  foreach ($list as $ii) {
1498                      if ($ii['location'] != '') {
1499                          $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1500                      } else {
1501                          $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1502                      }
1503                  }
1504              }
1505          }
1506          // complex types
1507          foreach($this->complexTypes as $typeName => $attrs){
1508              $contentStr = '';
1509              // serialize child elements
1510              if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1511                  foreach($attrs['elements'] as $element => $eParts){
1512                      if(isset($eParts['ref'])){
1513                          $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
1514                      } else {
1515                          $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1516                          foreach ($eParts as $aName => $aValue) {
1517                              // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1518                              if ($aName != 'name' && $aName != 'type') {
1519                                  $contentStr .= " $aName=\"$aValue\"";
1520                              }
1521                          }
1522                          $contentStr .= "/>\n";
1523                      }
1524                  }
1525                  // compositor wraps elements
1526                  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1527                      $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
1528                  }
1529              }
1530              // attributes
1531              if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1532                  foreach($attrs['attrs'] as $attr => $aParts){
1533                      $contentStr .= "    <$schemaPrefix:attribute";
1534                      foreach ($aParts as $a => $v) {
1535                          if ($a == 'ref' || $a == 'type') {
1536                              $contentStr .= " $a=\"".$this->contractQName($v).'"';
1537                          } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1538                              $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1539                              $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1540                          } else {
1541                              $contentStr .= " $a=\"$v\"";
1542                          }
1543                      }
1544                      $contentStr .= "/>\n";
1545                  }
1546              }
1547              // if restriction
1548              if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1549                  $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
1550                  // complex or simple content
1551                  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1552                      $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
1553                  }
1554              }
1555              // finalize complex type
1556              if($contentStr != ''){
1557                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1558              } else {
1559                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1560              }
1561              $xml .= $contentStr;
1562          }
1563          // simple types
1564          if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1565              foreach($this->simpleTypes as $typeName => $eParts){
1566                  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n";
1567                  if (isset($eParts['enumeration'])) {
1568                      foreach ($eParts['enumeration'] as $e) {
1569                          $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
1570                      }
1571                  }
1572                  $xml .= " </$schemaPrefix:simpleType>";
1573              }
1574          }
1575          // elements
1576          if(isset($this->elements) && count($this->elements) > 0){
1577              foreach($this->elements as $element => $eParts){
1578                  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1579              }
1580          }
1581          // attributes
1582          if(isset($this->attributes) && count($this->attributes) > 0){
1583              foreach($this->attributes as $attr => $aParts){
1584                  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1585              }
1586          }
1587          // finish 'er up
1588          $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
1589          foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1590              $el .= " xmlns:$nsp=\"$ns\"";
1591          }
1592          $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1593          return $xml;
1594      }
1595  
1596      /**
1597      * adds debug data to the clas level debug string
1598      *
1599      * @param    string $string debug data
1600      * @access   private
1601      */
1602  	function xdebug($string){
1603          $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1604      }
1605  
1606      /**
1607      * get the PHP type of a user defined type in the schema
1608      * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1609      * returns false if no type exists, or not w/ the given namespace
1610      * else returns a string that is either a native php type, or 'struct'
1611      *
1612      * @param string $type, name of defined type
1613      * @param string $ns, namespace of type
1614      * @return mixed
1615      * @access public
1616      * @deprecated
1617      */
1618  	function getPHPType($type,$ns){
1619          if(isset($this->typemap[$ns][$type])){
1620              //print "found type '$type' and ns $ns in typemap<br>";
1621              return $this->typemap[$ns][$type];
1622          } elseif(isset($this->complexTypes[$type])){
1623              //print "getting type '$type' and ns $ns from complexTypes array<br>";
1624              return $this->complexTypes[$type]['phpType'];
1625          }
1626          return false;
1627      }
1628  
1629      /**
1630      * returns an associative array of information about a given type
1631      * returns false if no type exists by the given name
1632      *
1633      *    For a complexType typeDef = array(
1634      *    'restrictionBase' => '',
1635      *    'phpType' => '',
1636      *    'compositor' => '(sequence|all)',
1637      *    'elements' => array(), // refs to elements array
1638      *    'attrs' => array() // refs to attributes array
1639      *    ... and so on (see addComplexType)
1640      *    )
1641      *
1642      *   For simpleType or element, the array has different keys.
1643      *
1644      * @param string
1645      * @return mixed
1646      * @access public
1647      * @see addComplexType
1648      * @see addSimpleType
1649      * @see addElement
1650      */
1651  	function getTypeDef($type){
1652          //$this->debug("in getTypeDef for type $type");
1653          if(isset($this->complexTypes[$type])){
1654              $this->xdebug("in getTypeDef, found complexType $type");
1655              return $this->complexTypes[$type];
1656          } elseif(isset($this->simpleTypes[$type])){
1657              $this->xdebug("in getTypeDef, found simpleType $type");
1658              if (!isset($this->simpleTypes[$type]['phpType'])) {
1659                  // get info for type to tack onto the simple type
1660                  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1661                  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1662                  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1663                  $etype = $this->getTypeDef($uqType);
1664                  if ($etype) {
1665                      $this->xdebug("in getTypeDef, found type for simpleType $type:");
1666                      $this->xdebug($this->varDump($etype));
1667                      if (isset($etype['phpType'])) {
1668                          $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1669                      }
1670                      if (isset($etype['elements'])) {
1671                          $this->simpleTypes[$type]['elements'] = $etype['elements'];
1672                      }
1673                  }
1674              }
1675              return $this->simpleTypes[$type];
1676          } elseif(isset($this->elements[$type])){
1677              $this->xdebug("in getTypeDef, found element $type");
1678              if (!isset($this->elements[$type]['phpType'])) {
1679                  // get info for type to tack onto the element
1680                  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1681                  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1682                  $etype = $this->getTypeDef($uqType);
1683                  if ($etype) {
1684                      $this->xdebug("in getTypeDef, found type for element $type:");
1685                      $this->xdebug($this->varDump($etype));
1686                      if (isset($etype['phpType'])) {
1687                          $this->elements[$type]['phpType'] = $etype['phpType'];
1688                      }
1689                      if (isset($etype['elements'])) {
1690                          $this->elements[$type]['elements'] = $etype['elements'];
1691                      }
1692                  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1693                      $this->xdebug("in getTypeDef, element $type is an XSD type");
1694                      $this->elements[$type]['phpType'] = 'scalar';
1695                  }
1696              }
1697              return $this->elements[$type];
1698          } elseif(isset($this->attributes[$type])){
1699              $this->xdebug("in getTypeDef, found attribute $type");
1700              return $this->attributes[$type];
1701          } elseif (ereg('_ContainedType$', $type)) {
1702              $this->xdebug("in getTypeDef, have an untyped element $type");
1703              $typeDef['typeClass'] = 'simpleType';
1704              $typeDef['phpType'] = 'scalar';
1705              $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1706              return $typeDef;
1707          }
1708          $this->xdebug("in getTypeDef, did not find $type");
1709          return false;
1710      }
1711  
1712      /**
1713      * returns a sample serialization of a given type, or false if no type by the given name
1714      *
1715      * @param string $type, name of type
1716      * @return mixed
1717      * @access public
1718      * @deprecated
1719      */
1720      function serializeTypeDef($type){
1721          //print "in sTD() for type $type<br>";
1722      if($typeDef = $this->getTypeDef($type)){
1723          $str .= '<'.$type;
1724          if(is_array($typeDef['attrs'])){
1725          foreach($attrs as $attName => $data){
1726              $str .= " $attName=\"{type = ".$data['type']."}\"";
1727          }
1728          }
1729          $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1730          if(count($typeDef['elements']) > 0){
1731          $str .= ">";
1732          foreach($typeDef['elements'] as $element => $eData){
1733              $str .= $this->serializeTypeDef($element);
1734          }
1735          $str .= "</$type>";
1736          } elseif($typeDef['typeClass'] == 'element') {
1737          $str .= "></$type>";
1738          } else {
1739          $str .= "/>";
1740          }
1741              return $str;
1742      }
1743          return false;
1744      }
1745  
1746      /**
1747      * returns HTML form elements that allow a user
1748      * to enter values for creating an instance of the given type.
1749      *
1750      * @param string $name, name for type instance
1751      * @param string $type, name of type
1752      * @return string
1753      * @access public
1754      * @deprecated
1755      */
1756  	function typeToForm($name,$type){
1757          // get typedef
1758          if($typeDef = $this->getTypeDef($type)){
1759              // if struct
1760              if($typeDef['phpType'] == 'struct'){
1761                  $buffer .= '<table>';
1762                  foreach($typeDef['elements'] as $child => $childDef){
1763                      $buffer .= "
1764                      <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1765                      <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1766                  }
1767                  $buffer .= '</table>';
1768              // if array
1769              } elseif($typeDef['phpType'] == 'array'){
1770                  $buffer .= '<table>';
1771                  for($i=0;$i < 3; $i++){
1772                      $buffer .= "
1773                      <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1774                      <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1775                  }
1776                  $buffer .= '</table>';
1777              // if scalar
1778              } else {
1779                  $buffer .= "<input type='text' name='parameters[$name]'>";
1780              }
1781          } else {
1782              $buffer .= "<input type='text' name='parameters[$name]'>";
1783          }
1784          return $buffer;
1785      }
1786  
1787      /**
1788      * adds a complex type to the schema
1789      *
1790      * example: array
1791      *
1792      * addType(
1793      *     'ArrayOfstring',
1794      *     'complexType',
1795      *     'array',
1796      *     '',
1797      *     'SOAP-ENC:Array',
1798      *     array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
1799      *     'xsd:string'
1800      * );
1801      *
1802      * example: PHP associative array ( SOAP Struct )
1803      *
1804      * addType(
1805      *     'SOAPStruct',
1806      *     'complexType',
1807      *     'struct',
1808      *     'all',
1809      *     array('myVar'=> array('name'=>'myVar','type'=>'string')
1810      * );
1811      *
1812      * @param name
1813      * @param typeClass (complexType|simpleType|attribute)
1814      * @param phpType: currently supported are array and struct (php assoc array)
1815      * @param compositor (all|sequence|choice)
1816      * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1817      * @param elements = array ( name = array(name=>'',type=>'') )
1818      * @param attrs = array(
1819      *     array(
1820      *        'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
1821      *        "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
1822      *     )
1823      * )
1824      * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
1825      * @access public
1826      * @see getTypeDef
1827      */
1828  	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1829          $this->complexTypes[$name] = array(
1830          'name'        => $name,
1831          'typeClass'    => $typeClass,
1832          'phpType'    => $phpType,
1833          'compositor'=> $compositor,
1834          'restrictionBase' => $restrictionBase,
1835          'elements'    => $elements,
1836          'attrs'        => $attrs,
1837          'arrayType'    => $arrayType
1838          );
1839  
1840          $this->xdebug("addComplexType $name:");
1841          $this->appendDebug($this->varDump($this->complexTypes[$name]));
1842      }
1843  
1844      /**
1845      * adds a simple type to the schema
1846      *
1847      * @param string $name
1848      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1849      * @param string $typeClass (should always be simpleType)
1850      * @param string $phpType (should always be scalar)
1851      * @param array $enumeration array of values
1852      * @access public
1853      * @see xmlschema
1854      * @see getTypeDef
1855      */
1856  	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1857          $this->simpleTypes[$name] = array(
1858          'name'            => $name,
1859          'typeClass'        => $typeClass,
1860          'phpType'        => $phpType,
1861          'type'            => $restrictionBase,
1862          'enumeration'    => $enumeration
1863          );
1864  
1865          $this->xdebug("addSimpleType $name:");
1866          $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1867      }
1868  
1869      /**
1870      * adds an element to the schema
1871      *
1872      * @param array $attrs attributes that must include name and type
1873      * @see xmlschema
1874      * @access public
1875      */
1876  	function addElement($attrs) {
1877          if (! $this->getPrefix($attrs['type'])) {
1878              $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
1879          }
1880          $this->elements[ $attrs['name'] ] = $attrs;
1881          $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1882  
1883          $this->xdebug("addElement " . $attrs['name']);
1884          $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
1885      }
1886  }
1887  
1888  
1889  
1890  ?><?php
1891  
1892  
1893  
1894  /**
1895  * For creating serializable abstractions of native PHP types.  This class
1896  * allows element name/namespace, XSD type, and XML attributes to be
1897  * associated with a value.  This is extremely useful when WSDL is not
1898  * used, but is also useful when WSDL is used with polymorphic types, including
1899  * xsd:anyType and user-defined types.
1900  *
1901  * @author   Dietrich Ayala <dietrich@ganx4.com>
1902  * @version  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 snichol Exp $
1903  * @access   public
1904  */
1905  class soapval extends nusoap_base {
1906      /**
1907       * The XML element name
1908       *
1909       * @var string
1910       * @access private
1911       */
1912      var $name;
1913      /**
1914       * The XML type name (string or false)
1915       *
1916       * @var mixed
1917       * @access private
1918       */
1919      var $type;
1920      /**
1921       * The PHP value
1922       *
1923       * @var mixed
1924       * @access private
1925       */
1926      var $value;
1927      /**
1928       * The XML element namespace (string or false)
1929       *
1930       * @var mixed
1931       * @access private
1932       */
1933      var $element_ns;
1934      /**
1935       * The XML type namespace (string or false)
1936       *
1937       * @var mixed
1938       * @access private
1939       */
1940      var $type_ns;
1941      /**
1942       * The XML element attributes (array or false)
1943       *
1944       * @var mixed
1945       * @access private
1946       */
1947      var $attributes;
1948  
1949      /**
1950      * constructor
1951      *
1952      * @param    string $name optional name
1953      * @param    mixed $type optional type name
1954      * @param    mixed $value optional value
1955      * @param    mixed $element_ns optional namespace of value
1956      * @param    mixed $type_ns optional namespace of type
1957      * @param    mixed $attributes associative array of attributes to add to element serialization
1958      * @access   public
1959      */
1960    	function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
1961          parent::nusoap_base();
1962          $this->name = $name;
1963          $this->type = $type;
1964          $this->value = $value;
1965          $this->element_ns = $element_ns;
1966          $this->type_ns = $type_ns;
1967          $this->attributes = $attributes;
1968      }
1969  
1970      /**
1971      * return serialized value
1972      *
1973      * @param    string $use The WSDL use value (encoded|literal)
1974      * @return    string XML data
1975      * @access   public
1976      */
1977  	function serialize($use='encoded') {
1978          return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
1979      }
1980  
1981      /**
1982      * decodes a soapval object into a PHP native type
1983      *
1984      * @return    mixed
1985      * @access   public
1986      */
1987  	function decode(){
1988          return $this->value;
1989      }
1990  }
1991  
1992  
1993  
1994  ?><?php
1995  
1996  
1997  
1998  /**
1999  * transport class for sending/receiving data via HTTP and HTTPS
2000  * NOTE: PHP must be compiled with the CURL extension for HTTPS support
2001  *
2002  * @author   Dietrich Ayala <dietrich@ganx4.com>
2003  * @version  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 snichol Exp $
2004  * @access public
2005  */
2006  class soap_transport_http extends nusoap_base {
2007  
2008      var $url = '';
2009      var $uri = '';
2010      var $digest_uri = '';
2011      var $scheme = '';
2012      var $host = '';
2013      var $port = '';
2014      var $path = '';
2015      var $request_method = 'POST';
2016      var $protocol_version = '1.0';
2017      var $encoding = '';
2018      var $outgoing_headers = array();
2019      var $incoming_headers = array();
2020      var $incoming_cookies = array();
2021      var $outgoing_payload = '';
2022      var $incoming_payload = '';
2023      var $useSOAPAction = true;
2024      var $persistentConnection = false;
2025      var $ch = false;    // cURL handle
2026      var $username = '';
2027      var $password = '';
2028      var $authtype = '';
2029      var $digestRequest = array();
2030      var $certRequest = array();    // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional)
2031                                  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2032                                  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2033                                  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2034                                  // passphrase: SSL key password/passphrase
2035                                  // verifypeer: default is 1
2036                                  // verifyhost: default is 1
2037  
2038      /**
2039      * constructor
2040      */
2041  	function soap_transport_http($url){
2042          parent::nusoap_base();
2043          $this->setURL($url);
2044          ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
2045          $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
2046          $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']);
2047      }
2048  
2049  	function setURL($url) {
2050          $this->url = $url;
2051  
2052          $u = parse_url($url);
2053          foreach($u as $k => $v){
2054              $this->debug("$k = $v");
2055              $this->$k = $v;
2056          }
2057  
2058          // add any GET params to path
2059          if(isset($u['query']) && $u['query'] != ''){
2060              $this->path .= '?' . $u['query'];
2061          }
2062  
2063          // set default port
2064          if(!isset($u['port'])){
2065              if($u['scheme'] == 'https'){
2066                  $this->port = 443;
2067              } else {
2068                  $this->port = 80;
2069              }
2070          }
2071  
2072          $this->uri = $this->path;
2073          $this->digest_uri = $this->uri;
2074  
2075          // build headers
2076          if (!isset($u['port'])) {
2077              $this->outgoing_headers['Host'] = $this->host;
2078          } else {
2079              $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
2080          }
2081          $this->debug('set Host: ' . $this->outgoing_headers['Host']);
2082  
2083          if (isset($u['user']) && $u['user'] != '') {
2084              $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2085          }
2086      }
2087  
2088  	function connect($connection_timeout=0,$response_timeout=30){
2089            // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2090            // "regular" socket.
2091            // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2092            //       loaded), and until PHP5 stream_get_wrappers is not available.
2093  //          if ($this->scheme == 'https') {
2094  //              if (version_compare(phpversion(), '4.3.0') >= 0) {
2095  //                  if (extension_loaded('openssl')) {
2096  //                      $this->scheme = 'ssl';
2097  //                      $this->debug('Using SSL over OpenSSL');
2098  //                  }
2099  //              }
2100  //        }
2101          $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2102        if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2103          // use persistent connection
2104          if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
2105              if (!feof($this->fp)) {
2106                  $this->debug('Re-use persistent connection');
2107                  return true;
2108              }
2109              fclose($this->fp);
2110              $this->debug('Closed persistent connection at EOF');
2111          }
2112  
2113          // munge host if using OpenSSL
2114          if ($this->scheme == 'ssl') {
2115              $host = 'ssl://' . $this->host;
2116          } else {
2117              $host = $this->host;
2118          }
2119          $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2120  
2121          // open socket
2122          if($connection_timeout > 0){
2123              $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2124          } else {
2125              $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
2126          }
2127  
2128          // test pointer
2129          if(!$this->fp) {
2130              $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2131              if ($this->errno) {
2132                  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2133              } else {
2134                  $msg .= ' prior to connect().  This is often a problem looking up the host name.';
2135              }
2136              $this->debug($msg);
2137              $this->setError($msg);
2138              return false;
2139          }
2140  
2141          // set response timeout
2142          $this->debug('set response timeout to ' . $response_timeout);
2143          socket_set_timeout( $this->fp, $response_timeout);
2144  
2145          $this->debug('socket connected');
2146          return true;
2147        } else if ($this->scheme == 'https') {
2148          if (!extension_loaded('curl')) {
2149              $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2150              return false;
2151          }
2152          $this->debug('connect using https');
2153          // init CURL
2154          $this->ch = curl_init();
2155          // set url
2156          $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
2157          // add path
2158          $hostURL .= $this->path;
2159          curl_setopt($this->ch, CURLOPT_URL, $hostURL);
2160          // follow location headers (re-directs)
2161          curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1);
2162          // ask for headers in the response output
2163          curl_setopt($this->ch, CURLOPT_HEADER, 1);
2164          // ask for the response output as the return value
2165          curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
2166          // encode
2167          // We manage this ourselves through headers and encoding
2168  //        if(function_exists('gzuncompress')){
2169  //            curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
2170  //        }
2171          // persistent connection
2172          if ($this->persistentConnection) {
2173              // The way we send data, we cannot use persistent connections, since
2174              // there will be some "junk" at the end of our request.
2175              //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
2176              $this->persistentConnection = false;
2177              $this->outgoing_headers['Connection'] = 'close';
2178              $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
2179          }
2180          // set timeout
2181          if ($connection_timeout != 0) {
2182              curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
2183          }
2184          // TODO: cURL has added a connection timeout separate from the response timeout
2185          //if ($connection_timeout != 0) {
2186          //    curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2187          //}
2188          //if ($response_timeout != 0) {
2189          //    curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_timeout);
2190          //}
2191  
2192          // recent versions of cURL turn on peer/host checking by default,
2193          // while PHP binaries are not compiled with a default location for the
2194          // CA cert bundle, so disable peer/host checking.
2195  //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
2196          curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
2197          curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
2198  
2199          // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2200          if ($this->authtype == 'certificate') {
2201              if (isset($this->certRequest['cainfofile'])) {
2202                  curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2203              }
2204              if (isset($this->certRequest['verifypeer'])) {
2205                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2206              } else {
2207                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
2208              }
2209              if (isset($this->certRequest['verifyhost'])) {
2210                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2211              } else {
2212                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
2213              }
2214              if (isset($this->certRequest['sslcertfile'])) {
2215                  curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2216              }
2217              if (isset($this->certRequest['sslkeyfile'])) {
2218                  curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2219              }
2220              if (isset($this->certRequest['passphrase'])) {
2221                  curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']);
2222              }
2223          }
2224          $this->debug('cURL connection set up');
2225          return true;
2226        } else {
2227          $this->setError('Unknown scheme ' . $this->scheme);
2228          $this->debug('Unknown scheme ' . $this->scheme);
2229          return false;
2230        }
2231      }
2232  
2233      /**
2234      * send the SOAP message via HTTP
2235      *
2236      * @param    string $data message data
2237      * @param    integer $timeout set connection timeout in seconds
2238      * @param    integer $response_timeout set response timeout in seconds
2239      * @param    array $cookies cookies to send
2240      * @return    string data
2241      * @access   public
2242      */
2243  	function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
2244  
2245          $this->debug('entered send() with data of length: '.strlen($data));
2246  
2247          $this->tryagain = true;
2248          $tries = 0;
2249          while ($this->tryagain) {
2250              $this->tryagain = false;
2251              if ($tries++ < 2) {
2252                  // make connnection
2253                  if (!$this->connect($timeout, $response_timeout)){
2254                      return false;
2255                  }
2256  
2257                  // send request
2258                  if (!$this->sendRequest($data, $cookies)){
2259                      return false;
2260                  }
2261  
2262                  // get response
2263                  $respdata = $this->getResponse();
2264              } else {
2265                  $this->setError('Too many tries to get an OK response');
2266              }
2267          }
2268          $this->debug('end of send()');
2269          return $respdata;
2270      }
2271  
2272  
2273      /**
2274      * send the SOAP message via HTTPS 1.0 using CURL
2275      *
2276      * @param    string $msg message data
2277      * @param    integer $timeout set connection timeout in seconds
2278      * @param    integer $response_timeout set response timeout in seconds
2279      * @param    array $cookies cookies to send
2280      * @return    string data
2281      * @access   public
2282      */
2283  	function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
2284          return $this->send($data, $timeout, $response_timeout, $cookies);
2285      }
2286  
2287      /**
2288      * if authenticating, set user credentials here
2289      *
2290      * @param    string $username
2291      * @param    string $password
2292      * @param    string $authtype (basic, digest, certificate)
2293      * @param    array $digestRequest (keys must be nonce, nc, realm, qop)
2294      * @param    array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
2295      * @access   public
2296      */
2297  	function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
2298          $this->debug("Set credentials for authtype $authtype");
2299          // cf. RFC 2617
2300          if ($authtype == 'basic') {
2301              $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$username).':'.$password);
2302          } elseif ($authtype == 'digest') {
2303              if (isset($digestRequest['nonce'])) {
2304                  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2305  
2306                  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2307  
2308                  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2309                  $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2310  
2311                  // H(A1) = MD5(A1)
2312                  $HA1 = md5($A1);
2313  
2314                  // A2 = Method ":" digest-uri-value
2315                  $A2 = 'POST:' . $this->digest_uri;
2316  
2317                  // H(A2)
2318                  $HA2 =  md5($A2);
2319  
2320                  // KD(secret, data) = H(concat(secret, ":", data))
2321                  // if qop == auth:
2322                  // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
2323                  //                              ":" nc-value
2324                  //                              ":" unq(cnonce-value)
2325                  //                              ":" unq(qop-value)
2326                  //                              ":" H(A2)
2327                  //                            ) <">
2328                  // if qop is missing,
2329                  // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2330  
2331                  $unhashedDigest = '';
2332                  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2333                  $cnonce = $nonce;
2334                  if ($digestRequest['qop'] != '') {
2335                      $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2336                  } else {
2337                      $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2338                  }
2339  
2340                  $hashedDigest = md5($unhashedDigest);
2341  
2342                  $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"';
2343              }
2344          } elseif ($authtype == 'certificate') {
2345              $this->certRequest = $certRequest;
2346          }
2347          $this->username = $username;
2348          $this->password = $password;
2349          $this->authtype = $authtype;
2350          $this->digestRequest = $digestRequest;
2351  
2352          if (isset($this->outgoing_headers['Authorization'])) {
2353              $this->debug('set Authorization: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
2354          } else {
2355              $this->debug('Authorization header not set');
2356          }
2357      }
2358  
2359      /**
2360      * set the soapaction value
2361      *
2362      * @param    string $soapaction
2363      * @access   public
2364      */
2365  	function setSOAPAction($soapaction) {
2366          $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
2367          $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']);
2368      }
2369  
2370      /**
2371      * use http encoding
2372      *
2373      * @param    string $enc encoding style. supported values: gzip, deflate, or both
2374      * @access   public
2375      */
2376  	function setEncoding($enc='gzip, deflate') {
2377          if (function_exists('gzdeflate')) {
2378              $this->protocol_version = '1.1';
2379              $this->outgoing_headers['Accept-Encoding'] = $enc;
2380              $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']);
2381              if (!isset($this->outgoing_headers['Connection'])) {
2382                  $this->outgoing_headers['Connection'] = 'close';
2383                  $this->persistentConnection = false;
2384                  $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
2385              }
2386              set_magic_quotes_runtime(0);
2387              // deprecated
2388              $this->encoding = $enc;
2389          }
2390      }
2391  
2392      /**
2393      * set proxy info here
2394      *
2395      * @param    string $proxyhost
2396      * @param    string $proxyport
2397      * @param    string $proxyusername
2398      * @param    string $proxypassword
2399      * @access   public
2400      */
2401  	function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
2402          $this->uri = $this->url;
2403          $this->host = $proxyhost;
2404          $this->port = $proxyport;
2405          if ($proxyusername != '' && $proxypassword != '') {
2406              $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
2407              $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']);
2408          }
2409      }
2410  
2411      /**
2412      * decode a string that is encoded w/ "chunked' transfer encoding
2413       * as defined in RFC2068 19.4.6
2414      *
2415      * @param    string $buffer
2416      * @param    string $lb
2417      * @returns    string
2418      * @access   public
2419      * @deprecated
2420      */
2421  	function decodeChunked($buffer, $lb){
2422          // length := 0
2423          $length = 0;
2424          $new = '';
2425  
2426          // read chunk-size, chunk-extension (if any) and CRLF
2427          // get the position of the linebreak
2428          $chunkend = strpos($buffer, $lb);
2429          if ($chunkend == FALSE) {
2430              $this->debug('no linebreak found in decodeChunked');
2431              return $new;
2432          }
2433          $temp = substr($buffer,0,$chunkend);
2434          $chunk_size = hexdec( trim($temp) );
2435          $chunkstart = $chunkend + strlen($lb);
2436          // while (chunk-size > 0) {
2437          while ($chunk_size > 0) {
2438              $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2439              $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2440  
2441              // Just in case we got a broken connection
2442                if ($chunkend == FALSE) {
2443                    $chunk = substr($buffer,$chunkstart);
2444                  // append chunk-data to entity-body
2445                  $new .= $chunk;
2446                    $length += strlen($chunk);
2447                    break;
2448              }
2449  
2450                // read chunk-data and CRLF
2451                $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2452                // append chunk-data to entity-body
2453                $new .= $chunk;
2454                // length := length + chunk-size
2455                $length += strlen($chunk);
2456                // read chunk-size and CRLF
2457                $chunkstart = $chunkend + strlen($lb);
2458  
2459                $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2460              if ($chunkend == FALSE) {
2461                  break; //Just in case we got a broken connection
2462              }
2463              $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2464              $chunk_size = hexdec( trim($temp) );
2465              $chunkstart = $chunkend;
2466          }
2467          return $new;
2468      }
2469  
2470      /*
2471       *    Writes payload, including HTTP headers, to $this->outgoing_payload.
2472       */
2473  	function buildPayload($data, $cookie_str = '') {
2474          // add content-length header
2475          $this->outgoing_headers['Content-Length'] = strlen($data);
2476          $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']);
2477  
2478          // start building outgoing payload:
2479          $req = "$this->request_method $this->uri HTTP/$this->protocol_version";
2480          $this->debug("HTTP request: $req");
2481          $this->outgoing_payload = "$req\r\n";
2482  
2483          // loop thru headers, serializing
2484          foreach($this->outgoing_headers as $k => $v){
2485              $hdr = $k.': '.$v;
2486              $this->debug("HTTP header: $hdr");
2487              $this->outgoing_payload .= "$hdr\r\n";
2488          }
2489  
2490          // add any cookies
2491          if ($cookie_str != '') {
2492              $hdr = 'Cookie: '.$cookie_str;
2493              $this->debug("HTTP header: $hdr");
2494              $this->outgoing_payload .= "$hdr\r\n";
2495          }
2496  
2497          // header/body separator
2498          $this->outgoing_payload .= "\r\n";
2499  
2500          // add data
2501          $this->outgoing_payload .= $data;
2502      }
2503  
2504  	function sendRequest($data, $cookies = NULL) {
2505          // build cookie string
2506          $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2507  
2508          // build payload
2509          $this->buildPayload($data, $cookie_str);
2510  
2511        if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2512          // send payload
2513          if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2514              $this->setError('couldn\'t write message data to socket');
2515              $this->debug('couldn\'t write message data to socket');
2516              return false;
2517          }
2518          $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2519          return true;
2520        } else if ($this->scheme == 'https') {
2521          // set payload
2522          // TODO: cURL does say this should only be the verb, and in fact it
2523          // turns out that the URI and HTTP version are appended to this, which
2524          // some servers refuse to work with
2525          //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2526          foreach($this->outgoing_headers as $k => $v){
2527              $curl_headers[] = "$k: $v";
2528          }
2529          if ($cookie_str != '') {
2530              $curl_headers[] = 'Cookie: ' . $cookie_str;
2531          }
2532          curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
2533          if ($this->request_method == "POST") {
2534                curl_setopt($this->ch, CURLOPT_POST, 1);
2535                curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
2536            } else {
2537            }
2538          $this->debug('set cURL payload');
2539          return true;
2540        }
2541      }
2542  
2543  	function getResponse(){
2544          $this->incoming_payload = '';
2545  
2546        if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2547          // loop until headers have been retrieved
2548          $data = '';
2549          while (!isset($lb)){
2550  
2551              // We might EOF during header read.
2552              if(feof($this->fp)) {
2553                  $this->incoming_payload = $data;
2554                  $this->debug('found no headers before EOF after length ' . strlen($data));
2555                  $this->debug("received before EOF:\n" . $data);
2556                  $this->setError('server failed to send headers');
2557                  return false;
2558              }
2559  
2560              $tmp = fgets($this->fp, 256);
2561              $tmplen = strlen($tmp);
2562              $this->debug("read line of $tmplen bytes: " . trim($tmp));
2563  
2564              if ($tmplen == 0) {
2565                  $this->incoming_payload = $data;
2566                  $this->debug('socket read of headers timed out after length ' . strlen($data));
2567                  $this->debug("read before timeout: " . $data);
2568                  $this->setError('socket read of headers timed out');
2569                  return false;
2570              }
2571  
2572              $data .= $tmp;
2573              $pos = strpos($data,"\r\n\r\n");
2574              if($pos > 1){
2575                  $lb = "\r\n";
2576              } else {
2577                  $pos = strpos($data,"\n\n");
2578                  if($pos > 1){
2579                      $lb = "\n";
2580                  }
2581              }
2582              // remove 100 header
2583              if(isset($lb) && ereg('^HTTP/1.1 100',$data)){
2584                  unset($lb);
2585                  $data = '';
2586              }//
2587          }
2588          // store header data
2589          $this->incoming_payload .= $data;
2590          $this->debug('found end of headers after length ' . strlen($data));
2591          // process headers
2592          $header_data = trim(substr($data,0,$pos));
2593          $header_array = explode($lb,$header_data);
2594          $this->incoming_headers = array();
2595          $this->incoming_cookies = array();
2596          foreach($header_array as $header_line){
2597              $arr = explode(':',$header_line, 2);
2598              if(count($arr) > 1){
2599                  $header_name = strtolower(trim($arr[0]));
2600                  $this->incoming_headers[$header_name] = trim($arr[1]);
2601                  if ($header_name == 'set-cookie') {
2602                      // TODO: allow multiple cookies from parseCookie
2603                      $cookie = $this->parseCookie(trim($arr[1]));
2604                      if ($cookie) {
2605                          $this->incoming_cookies[] = $cookie;
2606                          $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2607                      } else {
2608                          $this->debug('did not find cookie in ' . trim($arr[1]));
2609                      }
2610                  }
2611              } else if (isset($header_name)) {
2612                  // append continuation line to previous header
2613                  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2614              }
2615          }
2616  
2617          // loop until msg has been received
2618          if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2619              $content_length =  2147483647;    // ignore any content-length header
2620              $chunked = true;
2621              $this->debug("want to read chunked content");
2622          } elseif (isset($this->incoming_headers['content-length'])) {
2623              $content_length = $this->incoming_headers['content-length'];
2624              $chunked = false;
2625              $this->debug("want to read content of length $content_length");
2626          } else {
2627              $content_length =  2147483647;
2628              $chunked = false;
2629              $this->debug("want to read content to EOF");
2630          }
2631          $data = '';
2632          do {
2633              if ($chunked) {
2634                  $tmp = fgets($this->fp, 256);
2635                  $tmplen = strlen($tmp);
2636                  $this->debug("read chunk line of $tmplen bytes");
2637                  if ($tmplen == 0) {
2638                      $this->incoming_payload = $data;
2639                      $this->debug('socket read of chunk length timed out after length ' . strlen($data));
2640                      $this->debug("read before timeout:\n" . $data);
2641                      $this->setError('socket read of chunk length timed out');
2642                      return false;
2643                  }
2644                  $content_length = hexdec(trim($tmp));
2645                  $this->debug("chunk length $content_length");
2646              }
2647              $strlen = 0;
2648              while (($strlen < $content_length) && (!feof($this->fp))) {
2649                  $readlen = min(8192, $content_length - $strlen);
2650                  $tmp = fread($this->fp, $readlen);
2651                  $tmplen = strlen($tmp);
2652                  $this->debug("read buffer of $tmplen bytes");
2653                  if (($tmplen == 0) && (!feof($this->fp))) {
2654                      $this->incoming_payload = $data;
2655                      $this->debug('socket read of body timed out after length ' . strlen($data));
2656                      $this->debug("read before timeout:\n" . $data);
2657                      $this->setError('socket read of body timed out');
2658                      return false;
2659                  }
2660                  $strlen += $tmplen;
2661                  $data .= $tmp;
2662              }
2663              if ($chunked && ($content_length > 0)) {
2664                  $tmp = fgets($this->fp, 256);
2665                  $tmplen = strlen($tmp);
2666                  $this->debug("read chunk terminator of $tmplen bytes");
2667                  if ($tmplen == 0) {
2668                      $this->incoming_payload = $data;
2669                      $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
2670                      $this->debug("read before timeout:\n" . $data);
2671                      $this->setError('socket read of chunk terminator timed out');
2672                      return false;
2673                  }
2674              }
2675          } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
2676          if (feof($this->fp)) {
2677              $this->debug('read to EOF');
2678          }
2679          $this->debug('read body of length ' . strlen($data));
2680          $this->incoming_payload .= $data;
2681          $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
2682  
2683          // close filepointer
2684          if(
2685              (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
2686              (! $this->persistentConnection) || feof($this->fp)){
2687              fclose($this->fp);
2688              $this->fp = false;
2689              $this->debug('closed socket');
2690          }
2691  
2692          // connection was closed unexpectedly
2693          if($this->incoming_payload == ''){
2694              $this->setError('no response from server');
2695              return false;
2696          }
2697  
2698          // decode transfer-encoding
2699  //        if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
2700  //            if(!$data = $this->decodeChunked($data, $lb)){
2701  //                $this->setError('Decoding of chunked data failed');
2702  //                return false;
2703  //            }
2704              //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
2705              // set decoded payload
2706  //            $this->incoming_payload = $header_data.$lb.$lb.$data;
2707  //        }
2708  
2709        } else if ($this->scheme == 'https') {
2710          // send and receive
2711          $this->debug('send and receive with cURL');
2712          $this->incoming_payload = curl_exec($this->ch);
2713          $data = $this->incoming_payload;
2714  
2715          $cErr = curl_error($this->ch);
2716          if ($cErr != '') {
2717              $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
2718              // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
2719              foreach(curl_getinfo($this->ch) as $k => $v){
2720                  $err .= "$k: $v<br>";
2721              }
2722              $this->debug($err);
2723              $this->setError($err);
2724              curl_close($this->ch);
2725              return false;
2726          } else {
2727              //echo '<pre>';
2728              //var_dump(curl_getinfo($this->ch));
2729              //echo '</pre>';
2730          }
2731          // close curl
2732          $this->debug('No cURL error, closing cURL');
2733          curl_close($this->ch);
2734  
2735          // remove 100 header(s)
2736          while (ereg('^HTTP/1.1 100',$data)) {
2737              if ($pos = strpos($data,"\r\n\r\n")) {
2738                  $data = ltrim(substr($data,$pos));
2739              } elseif($pos = strpos($data,"\n\n") ) {
2740                  $data = ltrim(substr($data,$pos));
2741              }
2742          }
2743  
2744          // separate content from HTTP headers
2745          if ($pos = strpos($data,"\r\n\r\n")) {
2746              $lb = "\r\n";
2747          } elseif( $pos = strpos($data,"\n\n")) {
2748              $lb = "\n";
2749          } else {
2750              $this->debug('no proper separation of headers and document');
2751              $this->setError('no proper separation of headers and document');
2752              return false;
2753          }
2754          $header_data = trim(substr($data,0,$pos));
2755          $header_array = explode($lb,$header_data);
2756          $data = ltrim(substr($data,$pos));
2757          $this->debug('found proper separation of headers and document');
2758          $this->debug('cleaned data, stringlen: '.strlen($data));
2759          // clean headers
2760          foreach ($header_array as $header_line) {
2761              $arr = explode(':',$header_line,2);
2762              if(count($arr) > 1){
2763                  $header_name = strtolower(trim($arr[0]));
2764                  $this->incoming_headers[$header_name] = trim($arr[1]);
2765                  if ($header_name == 'set-cookie') {
2766                      // TODO: allow multiple cookies from parseCookie
2767                      $cookie = $this->parseCookie(trim($arr[1]));
2768                      if ($cookie) {
2769                          $this->incoming_cookies[] = $cookie;
2770                          $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2771                      } else {
2772                          $this->debug('did not find cookie in ' . trim($arr[1]));
2773                      }
2774                  }
2775              } else if (isset($header_name)) {
2776                  // append continuation line to previous header
2777                  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2778              }
2779          }
2780        }
2781  
2782          $arr = explode(' ', $header_array[0], 3);
2783          $http_version = $arr[0];
2784          $http_status = intval($arr[1]);
2785          $http_reason = count($arr) > 2 ? $arr[2] : '';
2786  
2787           // see if we need to resend the request with http digest authentication
2788           if (isset($this->incoming_headers['location']) && $http_status == 301) {
2789               $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']);
2790               $this->setURL($this->incoming_headers['location']);
2791              $this->tryagain = true;
2792              return false;
2793          }
2794  
2795           // see if we need to resend the request with http digest authentication
2796           if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
2797               $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
2798               if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
2799                   $this->debug('Server wants digest authentication');
2800                   // remove "Digest " from our elements
2801                   $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
2802  
2803                   // parse elements into array
2804                   $digestElements = explode(',', $digestString);
2805                   foreach ($digestElements as $val) {
2806                       $tempElement = explode('=', trim($val), 2);
2807                       $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
2808                   }
2809  
2810                  // should have (at least) qop, realm, nonce
2811                   if (isset($digestRequest['nonce'])) {
2812                       $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
2813                       $this->tryagain = true;
2814                       return false;
2815                   }
2816               }
2817              $this->debug('HTTP authentication failed');
2818              $this->setError('HTTP authentication failed');
2819              return false;
2820           }
2821  
2822          if (
2823              ($http_status >= 300 && $http_status <= 307) ||
2824              ($http_status >= 400 && $http_status <= 417) ||
2825              ($http_status >= 501 && $http_status <= 505)
2826             ) {
2827              $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
2828              return false;
2829          }
2830  
2831          // decode content-encoding
2832          if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
2833              if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
2834                  // if decoding works, use it. else assume data wasn't gzencoded
2835                  if(function_exists('gzinflate')){
2836                      //$timer->setMarker('starting decoding of gzip/deflated content');
2837                      // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
2838                      // this means there are no Zlib headers, although there should be
2839                      $this->debug('The gzinflate function exists');
2840                      $datalen = strlen($data);
2841                      if ($this->incoming_headers['content-encoding'] == 'deflate') {
2842                          if ($degzdata = @gzinflate($data)) {
2843                              $data = $degzdata;
2844                              $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
2845                              if (strlen($data) < $datalen) {
2846                                  // test for the case that the payload has been compressed twice
2847                                  $this->debug('The inflated payload is smaller than the gzipped one; try again');
2848                                  if ($degzdata = @gzinflate($data)) {
2849                                      $data = $degzdata;
2850                                      $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
2851                                  }
2852                              }
2853                          } else {
2854                              $this->debug('Error using gzinflate to inflate the payload');
2855                              $this->setError('Error using gzinflate to inflate the payload');
2856                          }
2857                      } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
2858                          if ($degzdata = @gzinflate(substr($data, 10))) {    // do our best
2859                              $data = $degzdata;
2860                              $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
2861                              if (strlen($data) < $datalen) {
2862                                  // test for the case that the payload has been compressed twice
2863                                  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
2864                                  if ($degzdata = @gzinflate(substr($data, 10))) {
2865                                      $data = $degzdata;
2866                                      $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
2867                                  }
2868                              }
2869                          } else {
2870                              $this->debug('Error using gzinflate to un-gzip the payload');
2871                              $this->setError('Error using gzinflate to un-gzip the payload');
2872                          }
2873                      }
2874                      //$timer->setMarker('finished decoding of gzip/deflated content');
2875                      //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
2876                      // set decoded payload
2877                      $this->incoming_payload = $header_data.$lb.$lb.$data;
2878                  } else {
2879                      $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
2880                      $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
2881                  }
2882              } else {
2883                  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
2884                  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
2885              }
2886          } else {
2887              $this->debug('No Content-Encoding header');
2888          }
2889  
2890          if(strlen($data) == 0){
2891              $this->debug('no data after headers!');
2892              $this->setError('no data present after HTTP headers');
2893              return false;
2894          }
2895  
2896          return $data;
2897      }
2898  
2899  	function setContentType($type, $charset = false) {
2900          $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
2901          $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']);
2902      }
2903  
2904  	function usePersistentConnection(){
2905          if (isset($this->outgoing_headers['Accept-Encoding'])) {
2906              return false;
2907          }
2908          $this->protocol_version = '1.1';
2909          $this->persistentConnection = true;
2910          $this->outgoing_headers['Connection'] = 'Keep-Alive';
2911          $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
2912          return true;
2913      }
2914  
2915      /**
2916       * parse an incoming Cookie into it's parts
2917       *
2918       * @param    string $cookie_str content of cookie
2919       * @return    array with data of that cookie
2920       * @access    private
2921       */
2922      /*
2923       * TODO: allow a Set-Cookie string to be parsed into multiple cookies
2924       */
2925  	function parseCookie($cookie_str) {
2926          $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
2927          $data = split(';', $cookie_str);
2928          $value_str = $data[0];
2929  
2930          $cookie_param = 'domain=';
2931          $start = strpos($cookie_str, $cookie_param);
2932          if ($start > 0) {
2933              $domain = substr($cookie_str, $start + strlen($cookie_param));
2934              $domain = substr($domain, 0, strpos($domain, ';'));
2935          } else {
2936              $domain = '';
2937          }
2938  
2939          $cookie_param = 'expires=';
2940          $start = strpos($cookie_str, $cookie_param);
2941          if ($start > 0) {
2942              $expires = substr($cookie_str, $start + strlen($cookie_param));
2943              $expires = substr($expires, 0, strpos($expires, ';'));
2944          } else {
2945              $expires = '';
2946          }
2947  
2948          $cookie_param = 'path=';
2949          $start = strpos($cookie_str, $cookie_param);
2950          if ( $start > 0 ) {
2951              $path = substr($cookie_str, $start + strlen($cookie_param));
2952              $path = substr($path, 0, strpos($path, ';'));
2953          } else {
2954              $path = '/';
2955          }
2956  
2957          $cookie_param = ';secure;';
2958          if (strpos($cookie_str, $cookie_param) !== FALSE) {
2959              $secure = true;
2960          } else {
2961              $secure = false;
2962          }
2963  
2964          $sep_pos = strpos($value_str, '=');
2965  
2966          if ($sep_pos) {
2967              $name = substr($value_str, 0, $sep_pos);
2968              $value = substr($value_str, $sep_pos + 1);
2969              $cookie= array(    'name' => $name,
2970                              'value' => $value,
2971                              'domain' => $domain,
2972                              'path' => $path,
2973                              'expires' => $expires,
2974                              'secure' => $secure
2975                              );
2976              return $cookie;
2977          }
2978          return false;
2979      }
2980  
2981      /**
2982       * sort out cookies for the current request
2983       *
2984       * @param    array $cookies array with all cookies
2985       * @param    boolean $secure is the send-content secure or not?
2986       * @return    string for Cookie-HTTP-Header
2987       * @access    private
2988       */
2989  	function getCookiesForRequest($cookies, $secure=false) {
2990          $cookie_str = '';
2991          if ((! is_null($cookies)) && (is_array($cookies))) {
2992              foreach ($cookies as $cookie) {
2993                  if (! is_array($cookie)) {
2994                      continue;
2995                  }
2996                  $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
2997                  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
2998                      if (strtotime($cookie['expires']) <= time()) {
2999                          $this->debug('cookie has expired');
3000                          continue;
3001                      }
3002                  }
3003                  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3004                      $domain = preg_quote($cookie['domain']);
3005                      if (! preg_match("'.*$domain$'i", $this->host)) {
3006                          $this->debug('cookie has different domain');
3007                          continue;
3008                      }
3009                  }
3010                  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3011                      $path = preg_quote($cookie['path']);
3012                      if (! preg_match("'^$path.*'i", $this->path)) {
3013                          $this->debug('cookie is for a different path');
3014                          continue;
3015                      }
3016                  }
3017                  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3018                      $this->debug('cookie is secure, transport is not');
3019                      continue;
3020                  }
3021                  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3022                  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3023              }
3024          }
3025          return $cookie_str;
3026    }
3027  }
3028  
3029  ?><?php
3030  
3031  
3032  
3033  /**
3034  *
3035  * soap_server allows the user to create a SOAP server
3036  * that is capable of receiving messages and returning responses
3037  *
3038  * NOTE: WSDL functionality is experimental
3039  *
3040  * @author   Dietrich Ayala <dietrich@ganx4.com>
3041  * @version  $Id: nusoap.php,v 1.95 2006/02/02 15:52:34 snichol Exp $
3042  * @access   public
3043  */
3044  class soap_server extends nusoap_base {
3045      /**
3046       * HTTP headers of request
3047       * @var array
3048       * @access private
3049       */
3050      var $headers = array();
3051      /**
3052       * HTTP request
3053       * @var string
3054       * @access private
3055       */
3056      var $request = '';
3057      /**
3058       * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
3059       * @var string
3060       * @access public
3061       */
3062      var $requestHeaders = '';
3063      /**
3064       * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
3065       * @var string
3066       * @access public
3067       */
3068      var $document = '';
3069      /**
3070       * SOAP payload for request (text)
3071       * @var string
3072       * @access public
3073       */
3074      var $requestSOAP = '';
3075      /**
3076       * requested method namespace URI
3077       * @var string
3078       * @access private
3079       */
3080      var $methodURI = '';
3081      /**
3082       * name of method requested
3083       * @var string
3084       * @access private
3085       */
3086      var $methodname = '';
3087      /**
3088       * method parameters from request
3089       * @var array
3090       * @access private
3091       */
3092      var $methodparams = array();
3093      /**
3094       * SOAP Action from request
3095       * @var string
3096       * @access private
3097       */
3098      var $SOAPAction = '';
3099      /**
3100       * character set encoding of incoming (request) messages
3101       * @var string
3102       * @access public
3103       */
3104      var $xml_encoding = '';
3105      /**
3106       * toggles whether the parser decodes element content w/ utf8_decode()
3107       * @var boolean
3108       * @access public
3109       */
3110      var $decode_utf8 = true;
3111  
3112      /**
3113       * HTTP headers of response
3114       * @var array
3115       * @access public
3116       */
3117      var $outgoing_headers = array();
3118      /**
3119       * HTTP response
3120       * @var string
3121       * @access private
3122       */
3123      var $response = '';
3124      /**
3125       * SOAP headers for response (text)
3126       * @var string
3127       * @access public
3128       */
3129      var $responseHeaders = '';
3130      /**
3131       * SOAP payload for response (text)
3132       * @var string
3133       * @access private
3134       */
3135      var $responseSOAP = '';
3136      /**
3137       * method return value to place in response
3138       * @var mixed
3139       * @access private
3140       */
3141      var $methodreturn = false;
3142      /**
3143       * whether $methodreturn is a string of literal XML
3144       * @var boolean
3145       * @access public
3146       */
3147      var $methodreturnisliteralxml = false;
3148      /**
3149       * SOAP fault for response (or false)
3150       * @var mixed
3151       * @access private
3152       */
3153      var $fault = false;
3154      /**
3155       * text indication of result (for debugging)
3156       * @var string
3157       * @access private
3158       */
3159      var $result = 'successful';
3160  
3161      /**
3162       * assoc array of operations => opData; operations are added by the register()
3163       * method or by parsing an external WSDL definition
3164       * @var array
3165       * @access private
3166       */
3167      var $operations = array();
3168      /**
3169       * wsdl instance (if one)
3170       * @var mixed
3171       * @access private
3172       */
3173      var $wsdl = false;
3174      /**
3175       * URL for WSDL (if one)
3176       * @var mixed
3177       * @access private
3178       */
3179      var $externalWSDLURL = false;
3180      /**
3181       * whether to append debug to response as XML comment
3182       * @var boolean
3183       * @access public
3184       */
3185      var $debug_flag = false;
3186  
3187  
3188      /**
3189      * constructor
3190      * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
3191      *
3192      * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
3193      * @access   public
3194      */
3195  	function soap_server($wsdl=false){
3196          parent::nusoap_base();
3197          // turn on debugging?
3198          global $debug;
3199          global $HTTP_SERVER_VARS;
3200  
3201          if (isset($_SERVER)) {
3202              $this->debug("_SERVER is defined:");
3203              $this->appendDebug($this->varDump($_SERVER));
3204          } elseif (isset($HTTP_SERVER_VARS)) {
3205              $this->debug("HTTP_SERVER_VARS is defined:");
3206              $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3207          } else {
3208              $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3209          }
3210  
3211          if (isset($debug)) {
3212              $this->debug("In soap_server, set debug_flag=$debug based on global flag");
3213              $this->debug_flag = $debug;
3214          } elseif (isset($_SERVER['QUERY_STRING'])) {
3215              $qs = explode('&', $_SERVER['QUERY_STRING']);
3216              foreach ($qs as $v) {
3217                  if (substr($v, 0, 6) == 'debug=') {
3218                      $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3219                      $this->debug_flag = substr($v, 6);
3220                  }
3221              }
3222          } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3223              $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3224              foreach ($qs as $v) {
3225                  if (substr($v, 0, 6) == 'debug=') {
3226                      $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3227                      $this->debug_flag = substr($v, 6);
3228                  }
3229              }
3230          }
3231  
3232          // wsdl
3233          if($wsdl){
3234              $this->debug("In soap_server, WSDL is specified");
3235              if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3236                  $this->wsdl = $wsdl;
3237                  $this->externalWSDLURL = $this->wsdl->wsdl;
3238                  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3239              } else {
3240                  $this->debug('Create wsdl from ' . $wsdl);
3241                  $this->wsdl = new wsdl($wsdl);
3242                  $this->externalWSDLURL = $wsdl;
3243              }
3244              $this->appendDebug($this->wsdl->getDebug());
3245              $this->wsdl->clearDebug();
3246              if($err = $this->wsdl->getError()){
3247                  die('WSDL ERROR: '.$err);
3248              }
3249          }
3250      }
3251  
3252      /**
3253      * processes request and returns response
3254      *
3255      * @param    string $data usually is the value of $HTTP_RAW_POST_DATA
3256      * @access   public
3257      */
3258  	function service($data){
3259          global $HTTP_SERVER_VARS;
3260  
3261          if (isset($_SERVER['QUERY_STRING'])) {
3262              $qs = $_SERVER['QUERY_STRING'];
3263          } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3264              $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3265          } else {
3266              $qs = '';
3267          }
3268          $this->debug("In service, query string=$qs");
3269  
3270          if (ereg('wsdl', $qs) ){
3271              $this->debug("In service, this is a request for WSDL");
3272              if($this->externalWSDLURL){
3273                if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
3274                  header('Location: '.$this->externalWSDLURL);
3275                } else { // assume file
3276                  header("Content-Type: text/xml\r\n");
3277                  $fp = fopen($this->externalWSDLURL, 'r');
3278                  fpassthru($fp);
3279                }
3280              } elseif ($this->wsdl) {
3281                  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3282                  print $this->wsdl->serialize($this->debug_flag);
3283                  if ($this->debug_flag) {
3284                      $this->debug('wsdl:');
3285                      $this->appendDebug($this->varDump($this->wsdl));
3286                      print $this->getDebugAsXMLComment();
3287                  }
3288              } else {
3289                  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3290                  print "This service does not provide WSDL";
3291              }
3292          } elseif ($data == '' && $this->wsdl) {
3293              $this->debug("In service, there is no data, so return Web description");
3294              print $this->wsdl->webDescription();
3295          } else {
3296              $this->debug("In service, invoke the request");
3297              $this->parse_request($data);
3298              if (! $this->fault) {
3299                  $this->invoke_method();
3300              }
3301              if (! $this->fault) {
3302                  $this->serialize_return();
3303              }
3304              $this->send_response();
3305          }
3306      }
3307  
3308      /**
3309      * parses HTTP request headers.
3310      *
3311      * The following fields are set by this function (when successful)
3312      *
3313      * headers
3314      * request
3315      * xml_encoding
3316      * SOAPAction
3317      *
3318      * @access   private
3319      */
3320  	function parse_http_headers() {
3321          global $HTTP_SERVER_VARS;
3322  
3323          $this->request = '';
3324          $this->SOAPAction = '';
3325          if(function_exists('getallheaders')){
3326              $this->debug("In parse_http_headers, use getallheaders");
3327              $headers = getallheaders();
3328              foreach($headers as $k=>$v){
3329                  $k = strtolower($k);
3330                  $this->headers[$k] = $v;
3331                  $this->request .= "$k: $v\r\n";
3332                  $this->debug("$k: $v");
3333              }
3334              // get SOAPAction header
3335              if(isset($this->headers['soapaction'])){
3336                  $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
3337              }
3338              // get the character encoding of the incoming request
3339              if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
3340                  $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
3341                  if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
3342                      $this->xml_encoding = strtoupper($enc);
3343                  } else {
3344                      $this->xml_encoding = 'US-ASCII';
3345                  }
3346              } else {
3347                  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3348                  $this->xml_encoding = 'ISO-8859-1';
3349              }
3350          } elseif(isset($_SERVER) && is_array($_SERVER)){
3351              $this->debug("In parse_http_headers, use _SERVER");
3352              foreach ($_SERVER as $k => $v) {
3353                  if (substr($k, 0, 5) == 'HTTP_') {
3354                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                              $k = strtolower(substr($k, 5));
3355                  } else {
3356                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                              $k = strtolower($k);
3357                  }
3358                  if ($k == 'soapaction') {
3359                      // get SOAPAction header
3360                      $k = 'SOAPAction';
3361                      $v = str_replace('"', '', $v);
3362                      $v = str_replace('\\', '', $v);
3363                      $this->SOAPAction = $v;
3364                  } else if ($k == 'content-type') {
3365                      // get the character encoding of the incoming request
3366                      if (strpos($v, '=')) {
3367                          $enc = substr(strstr($v, '='), 1);
3368                          $enc = str_replace('"', '', $enc);
3369                          $enc = str_replace('\\', '', $enc);
3370                          if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
3371                              $this->xml_encoding = strtoupper($enc);
3372                          } else {
3373                              $this->xml_encoding = 'US-ASCII';
3374                          }
3375                      } else {
3376                          // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3377                          $this->xml_encoding = 'ISO-8859-1';
3378                      }
3379                  }
3380                  $this->headers[$k] = $v;
3381                  $this->request .= "$k: $v\r\n";
3382                  $this->debug("$k: $v");
3383              }
3384          } elseif (is_array($HTTP_SERVER_VARS)) {
3385              $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3386              foreach ($HTTP_SERVER_VARS as $k => $v) {
3387                  if (substr($k, 0, 5) == 'HTTP_') {
3388                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                              $k = strtolower(substr($k, 5));
3389                  } else {
3390                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                              $k = strtolower($k);
3391                  }
3392                  if ($k == 'soapaction') {
3393                      // get SOAPAction header
3394                      $k = 'SOAPAction';
3395                      $v = str_replace('"', '', $v);
3396                      $v = str_replace('\\', '', $v);
3397                      $this->SOAPAction = $v;
3398                  } else if ($k == 'content-type') {
3399                      // get the character encoding of the incoming request
3400                      if (strpos($v, '=')) {
3401                          $enc = substr(strstr($v, '='), 1);
3402                          $enc = str_replace('"', '', $enc);
3403                          $enc = str_replace('\\', '', $enc);
3404                          if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
3405                              $this->xml_encoding = strtoupper($enc);
3406                          } else {
3407                              $this->xml_encoding = 'US-ASCII';
3408                          }
3409                      } else {
3410                          // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3411                          $this->xml_encoding = 'ISO-8859-1';
3412                      }
3413                  }
3414                  $this->headers[$k] = $v;
3415                  $this->request .= "$k: $v\r\n";
3416                  $this->debug("$k: $v");
3417              }
3418          } else {
3419              $this->debug("In parse_http_headers, HTTP headers not accessible");
3420              $this->setError("HTTP headers not accessible");
3421          }
3422      }
3423  
3424      /**
3425      * parses a request
3426      *
3427      * The following fields are set by this function (when successful)
3428      *
3429      * headers
3430      * request
3431      * xml_encoding
3432      * SOAPAction
3433      * request
3434      * requestSOAP
3435      * methodURI
3436      * methodname
3437      * methodparams
3438      * requestHeaders
3439      * document
3440      *
3441      * This sets the fault field on error
3442      *
3443      * @param    string $data XML string
3444      * @access   private
3445      */
3446  	function parse_request($data='') {
3447          $this->debug('entering parse_request()');
3448          $this->parse_http_headers();
3449          $this->debug('got character encoding: '.$this->xml_encoding);
3450          // uncompress if necessary
3451          if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3452              $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3453              if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3454                  // if decoding works, use it. else assume data wasn't gzencoded
3455                  if (function_exists('gzuncompress')) {
3456                      if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3457                          $data = $degzdata;
3458                      } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3459                          $data = $degzdata;
3460                      } else {
3461                          $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
3462                          return;
3463                      }
3464                  } else {
3465                      $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
3466                      return;
3467                  }
3468              }
3469          }
3470          $this->request .= "\r\n".$data;
3471          $data = $this->parseRequest($this->headers, $data);
3472          $this->requestSOAP = $data;
3473          $this->debug('leaving parse_request');
3474      }
3475  
3476      /**
3477      * invokes a PHP function for the requested SOAP method
3478      *
3479      * The following fields are set by this function (when successful)
3480      *
3481      * methodreturn
3482      *
3483      * Note that the PHP function that is called may also set the following
3484      * fields to affect the response sent to the client
3485      *
3486      * responseHeaders
3487      * outgoing_headers
3488      *
3489      * This sets the fault field on error
3490      *
3491      * @access   private
3492      */
3493  	function invoke_method() {
3494          $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3495  
3496          if ($this->wsdl) {
3497              if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3498                  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3499                  $this->appendDebug('opData=' . $this->varDump($this->opData));
3500              } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3501                  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3502                  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3503                  $this->appendDebug('opData=' . $this->varDump($this->opData));
3504                  $this->methodname = $this->opData['name'];
3505              } else {
3506                  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3507                  $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3508                  return;
3509              }
3510          } else {
3511              $this->debug('in invoke_method, no WSDL to validate method');
3512          }
3513  
3514          // if a . is present in $this->methodname, we see if there is a class in scope,
3515          // which could be referred to. We will also distinguish between two deliminators,
3516          // to allow methods to be called a the class or an instance
3517          $class = '';
3518          $method = '';
3519          if (strpos($this->methodname, '..') > 0) {
3520              $delim = '..';
3521          } else if (strpos($this->methodname, '.') > 0) {
3522              $delim = '.';
3523          } else {
3524              $delim = '';
3525          }
3526  
3527          if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3528              class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3529              // get the class and method name
3530              $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3531              $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3532              $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3533          }
3534  
3535          // does method exist?
3536          if ($class == '') {
3537              if (!function_exists($this->methodname)) {
3538                  $this->debug("in invoke_method, function '$this->methodname' not found!");
3539                  $this->result = 'fault: method not found';
3540                  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3541                  return;
3542              }
3543          } else {
3544              $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
3545              if (!in_array($method_to_compare, get_class_methods($class))) {
3546                  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
3547                  $this->result = 'fault: method not found';
3548                  $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
3549                  return;
3550              }
3551          }
3552  
3553          // evaluate message, getting back parameters
3554          // verify that request parameters match the method's signature
3555          if(! $this->verify_method($this->methodname,$this->methodparams)){
3556              // debug
3557              $this->debug('ERROR: request not verified against method signature');
3558              $this->result = 'fault: request failed validation against method signature';
3559              // return fault
3560              $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
3561              return;
3562          }
3563  
3564          // if there are parameters to pass
3565          $this->debug('in invoke_method, params:');
3566          $this->appendDebug($this->varDump($this->methodparams));
3567          $this->debug("in invoke_method, calling '$this->methodname'");
3568          if (!function_exists('call_user_func_array')) {
3569              if ($class == '') {
3570                  $this->debug('in invoke_method, calling function using eval()');
3571                  $funcCall = "\$this->methodreturn = $this->methodname(";
3572              } else {
3573                  if ($delim == '..') {
3574                      $this->debug('in invoke_method, calling class method using eval()');
3575                      $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
3576                  } else {
3577                      $this->debug('in invoke_method, calling instance method using eval()');
3578                      // generate unique instance name
3579                      $instname = "\$inst_".time();
3580                      $funcCall = $instname." = new ".$class."(); ";
3581                      $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
3582                  }
3583              }
3584              if ($this->methodparams) {
3585                  foreach ($this->methodparams as $param) {
3586                      if (is_array($param)) {
3587                          $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
3588                          return;
3589                      }
3590                      $funcCall .= "\"$param\",";
3591                  }
3592                  $funcCall = substr($funcCall, 0, -1);
3593              }
3594              $funcCall .= ');';
3595              $this->debug('in invoke_method, function call: '.$funcCall);
3596              @eval($funcCall);
3597          } else {
3598              if ($class == '') {
3599                  $this->debug('in invoke_method, calling function using call_user_func_array()');
3600                  $call_arg = "$this->methodname";    // straight assignment changes $this->methodname to lower case after call_user_func_array()
3601              } elseif ($delim == '..') {
3602                  $this->debug('in invoke_method, calling class method using call_user_func_array()');
3603                  $call_arg = array ($class, $method);
3604              } else {
3605                  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
3606                  $instance = new $class ();
3607                  $call_arg = array(&$instance, $method);
3608              }
3609              $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
3610          }
3611          $this->debug('in invoke_method, methodreturn:');
3612          $this->appendDebug($this->varDump($this->methodreturn));
3613          $this->debug("in invoke_method, called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
3614      }
3615  
3616      /**
3617      * serializes the return value from a PHP function into a full SOAP Envelope
3618      *
3619      * The following fields are set by this function (when successful)
3620      *
3621      * responseSOAP
3622      *
3623      * This sets the fault field on error
3624      *
3625      * @access   private
3626      */
3627  	function serialize_return() {
3628          $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
3629          // if fault
3630          if (isset($this->methodreturn) && (get_class($this->methodreturn) == 'soap_fault')) {
3631              $this->debug('got a fault object from method');
3632              $this->fault = $this->methodreturn;
3633              return;
3634          } elseif ($this->methodreturnisliteralxml) {
3635              $return_val = $this->methodreturn;
3636          // returned value(s)
3637          } else {
3638              $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
3639              $this->debug('serializing return value');
3640              if($this->wsdl){
3641                  // weak attempt at supporting multiple output params
3642                  if(sizeof($this->opData['output']['parts']) > 1){
3643                      $opParams = $this->methodreturn;
3644                  } else {
3645                      // TODO: is this really necessary?
3646                      $opParams = array($this->methodreturn);
3647                  }
3648                  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
3649                  $this->appendDebug($this->wsdl->getDebug());
3650                  $this->wsdl->clearDebug();
3651                  if($errstr = $this->wsdl->getError()){
3652                      $this->debug('got wsdl error: '.$errstr);
3653                      $this->fault('SOAP-ENV:Server', 'unable to serialize result');
3654                      return;
3655                  }
3656              } else {
3657                  if (isset($this->methodreturn)) {
3658                      $return_val = $this->serialize_val($this->methodreturn, 'return');
3659                  } else {
3660                      $return_val = '';
3661                      $this->debug('in absence of WSDL, assume void return for backward compatibility');
3662                  }
3663              }
3664          }
3665          $this->debug('return value:');
3666          $this->appendDebug($this->varDump($return_val));
3667  
3668          $this->debug('serializing response');
3669          if ($this->wsdl) {
3670              $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
3671              if ($this->opData['style'] == 'rpc') {
3672                  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
3673                  if ($this->opData['output']['use'] == 'literal') {
3674                      $payload = '<'.$this->methodname.'Response xmlns="'.$this->methodURI.'">'.$return_val.'</'.$this->methodname."Response>";
3675                  } else {
3676                      $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
3677                  }
3678              } else {
3679                  $this->debug('style is not rpc for serialization: assume document');
3680                  $payload = $return_val;
3681              }
3682          } else {
3683              $this->debug('do not have WSDL for serialization: assume rpc/encoded');
3684              $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
3685          }
3686          $this->result = 'successful';
3687          if($this->wsdl){
3688              //if($this->debug_flag){
3689                  $this->appendDebug($this->wsdl->getDebug());
3690              //    }
3691              if (isset($opData['output']['encodingStyle'])) {
3692                  $encodingStyle = $opData['output']['encodingStyle'];
3693              } else {
3694                  $encodingStyle = '';
3695              }
3696              // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
3697              $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$encodingStyle);
3698          } else {
3699              $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
3700          }
3701          $this->debug("Leaving serialize_return");
3702      }
3703  
3704      /**
3705      * sends an HTTP response
3706      *
3707      * The following fields are set by this function (when successful)
3708      *
3709      * outgoing_headers
3710      * response
3711      *
3712      * @access   private
3713      */
3714  	function send_response() {
3715          $this->debug('Enter send_response');
3716          if ($this->fault) {
3717              $payload = $this->fault->serialize();
3718              $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
3719              $this->outgoing_headers[] = "Status: 500 Internal Server Error";
3720          } else {
3721              $payload = $this->responseSOAP;
3722              // Some combinations of PHP+Web server allow the Status
3723              // to come through as a header.  Since OK is the default
3724              // just do nothing.
3725              // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
3726              // $this->outgoing_headers[] = "Status: 200 OK";
3727          }
3728          // add debug data if in debug mode
3729          if(isset($this->debug_flag) && $this->debug_flag){
3730              $payload .= $this->getDebugAsXMLComment();
3731          }
3732          $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
3733          ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
3734          $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
3735          // Let the Web server decide about this
3736          //$this->outgoing_headers[] = "Connection: Close\r\n";
3737          $payload = $this->getHTTPBody($payload);
3738          $type = $this->getHTTPContentType();
3739          $charset = $this->getHTTPContentTypeCharset();
3740          $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
3741          //begin code to compress payload - by John
3742          // NOTE: there is no way to know whether the Web server will also compress
3743          // this data.
3744          if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
3745              if (strstr($this->headers['accept-encoding'], 'gzip')) {
3746                  if (function_exists('gzencode')) {
3747                      if (isset($this->debug_flag) && $this->debug_flag) {
3748                          $payload .= "<!-- Content being gzipped -->";
3749                      }
3750                      $this->outgoing_headers[] = "Content-Encoding: gzip";
3751                      $payload = gzencode($payload);
3752                  } else {
3753                      if (isset($this->debug_flag) && $this->debug_flag) {
3754                          $payload .= "<!-- Content will not be gzipped: no gzencode -->";
3755                      }
3756                  }
3757              } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
3758                  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
3759                  // instead of gzcompress output,
3760                  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
3761                  if (function_exists('gzdeflate')) {
3762                      if (isset($this->debug_flag) && $this->debug_flag) {
3763                          $payload .= "<!-- Content being deflated -->";
3764                      }
3765                      $this->outgoing_headers[] = "Content-Encoding: deflate";
3766                      $payload = gzdeflate($payload);
3767                  } else {
3768                      if (isset($this->debug_flag) && $this->debug_flag) {
3769                          $payload .= "<!-- Content will not be deflated: no gzcompress -->";
3770                      }
3771                  }
3772              }
3773          }
3774          //end code
3775          $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
3776          reset($this->outgoing_headers);
3777          foreach($this->outgoing_headers as $hdr){
3778              header($hdr, false);
3779          }
3780          print $payload;
3781          $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
3782      }
3783  
3784      /**
3785      * takes the value that was created by parsing the request
3786      * and compares to the method's signature, if available.
3787      *
3788      * @param    string    $operation    The operation to be invoked
3789      * @param    array    $request    The array of parameter values
3790      * @return    boolean    Whether the operation was found
3791      * @access   private
3792      */
3793  	function verify_method($operation,$request){
3794          if(isset($this->wsdl) && is_object($this->wsdl)){
3795              if($this->wsdl->getOperationData($operation)){
3796                  return true;
3797              }
3798          } elseif(isset($this->operations[$operation])){
3799              return true;
3800          }
3801          return false;
3802      }
3803  
3804      /**
3805      * processes SOAP message received from client
3806      *
3807      * @param    array    $headers    The HTTP headers
3808      * @param    string    $data        unprocessed request data from client
3809      * @return    mixed    value of the message, decoded into a PHP type
3810      * @access   private
3811      */
3812      function parseRequest($headers, $data) {
3813          $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
3814          if (!strstr($headers['content-type'], 'text/xml')) {
3815              $this->setError('Request not of type text/xml');
3816              return false;
3817          }
3818          if (strpos($headers['content-type'], '=')) {
3819              $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
3820              $this->debug('Got response encoding: ' . $enc);
3821              if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
3822                  $this->xml_encoding = strtoupper($enc);
3823              } else {
3824                  $this->xml_encoding = 'US-ASCII';
3825              }
3826          } else {
3827              // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3828              $this->xml_encoding = 'ISO-8859-1';
3829          }
3830          $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
3831          // parse response, get soap parser obj
3832          $parser = new soap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
3833          // parser debug
3834          $this->debug("parser debug: \n".$parser->getDebug());
3835          // if fault occurred during message parsing
3836          if($err = $parser->getError()){
3837              $this->result = 'fault: error in msg parsing: '.$err;
3838              $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
3839          // else successfully parsed request into soapval object
3840          } else {
3841              // get/set methodname
3842              $this->methodURI = $parser->root_struct_namespace;
3843              $this->methodname = $parser->root_struct_name;
3844              $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
3845