[ Index ]
 

Code source de vtiger CRM 5.0.2

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/include/nusoap/ -> nusoap.php (source)

   1  <?php
   2  
   3  require_once ('include/logging.php');
   4  /*
   5  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
   6  
   7  NuSOAP - Web Services Toolkit for PHP
   8  
   9  Copyright (c) 2002 NuSphere Corporation
  10  
  11  This library is free software; you can redistribute it and/or
  12  modify it under the terms of the GNU Lesser General Public
  13  License as published by the Free Software Foundation; either
  14  version 2.1 of the License, or (at your option) any later version.
  15  
  16  This library is distributed in the hope that it will be useful,
  17  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  19  Lesser General Public License for more details.
  20  
  21  You should have received a copy of the GNU Lesser General Public
  22  License along with this library; if not, write to the Free Software
  23  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  24  
  25  If you have any questions or comments, please email:
  26  
  27  Dietrich Ayala
  28  dietrich@ganx4.com
  29  http://dietrich.ganx4.com/nusoap
  30  
  31  NuSphere Corporation
  32  http://www.nusphere.com
  33  
  34  */
  35  
  36  /* load classes
  37  
  38  // necessary classes
  39  require_once('class.soapclient.php');
  40  require_once('class.soap_val.php');
  41  require_once('class.soap_parser.php');
  42  require_once('class.soap_fault.php');
  43  
  44  // transport classes
  45  require_once('class.soap_transport_http.php');
  46  
  47  // optional add-on classes
  48  require_once('class.xmlschema.php');
  49  require_once('class.wsdl.php');
  50  
  51  // server class
  52  require_once('class.soap_server.php');*/
  53  
  54  // class variable emulation
  55  // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
  56  $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
  57  global $soap_log;
  58  $soap_log =& LoggerManager::getLogger('SOAP');
  59  /**
  60  *
  61  * nusoap_base
  62  *
  63  * @author   Dietrich Ayala <dietrich@ganx4.com>
  64  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
  65  * @access   public
  66  */
  67  class nusoap_base {
  68      /**
  69       * Identification for HTTP headers.
  70       *
  71       * @var string
  72       * @access private
  73       */
  74      var $title = 'NuSOAP';
  75      /**
  76       * Version for HTTP headers.
  77       *
  78       * @var string
  79       * @access private
  80       */
  81      var $version = '0.7.2';
  82      /**
  83       * CVS revision for HTTP headers.
  84       *
  85       * @var string
  86       * @access private
  87       */
  88      var $revision = '$Revision: 1.94 $';
  89      /**
  90       * Current error string (manipulated by getError/setError)
  91       *
  92       * @var string
  93       * @access private
  94       */
  95      var $error_str = '';
  96      /**
  97       * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
  98       *
  99       * @var string
 100       * @access private
 101       */
 102      var $debug_str = '';
 103      /**
 104       * toggles automatic encoding of special characters as entities
 105       * (should always be true, I think)
 106       *
 107       * @var boolean
 108       * @access private
 109       */
 110      var $charencoding = true;
 111      /**
 112       * the debug level for this instance
 113       *
 114       * @var    integer
 115       * @access private
 116       */
 117      var $debugLevel = 9;
 118  
 119      /**
 120      * set schema version
 121      *
 122      * @var      string
 123      * @access   public
 124      */
 125      var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
 126      
 127      /**
 128      * charset encoding for outgoing messages
 129      *
 130      * @var      string
 131      * @access   public
 132      */
 133          //var $soap_defencoding = 'ISO-8859-1';
 134      var $soap_defencoding = 'UTF-8';
 135  
 136      /**
 137      * namespaces in an array of prefix => uri
 138      *
 139      * this is "seeded" by a set of constants, but it may be altered by code
 140      *
 141      * @var      array
 142      * @access   public
 143      */
 144      var $namespaces = array(
 145          'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
 146          'xsd' => 'http://www.w3.org/2001/XMLSchema',
 147          'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
 148          'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
 149          );
 150  
 151      /**
 152      * namespaces used in the current context, e.g. during serialization
 153      *
 154      * @var      array
 155      * @access   private
 156      */
 157      var $usedNamespaces = array();
 158  
 159      /**
 160      * XML Schema types in an array of uri => (array of xml type => php type)
 161      * is this legacy yet?
 162      * no, this is used by the xmlschema class to verify type => namespace mappings.
 163      * @var      array
 164      * @access   public
 165      */
 166      var $typemap = array(
 167      'http://www.w3.org/2001/XMLSchema' => array(
 168          'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
 169          'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
 170          'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
 171          // abstract "any" types
 172          'anyType'=>'string','anySimpleType'=>'string',
 173          // derived datatypes
 174          'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
 175          'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
 176          'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
 177          'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
 178      'http://www.w3.org/2000/10/XMLSchema' => array(
 179          'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
 180          'float'=>'double','dateTime'=>'string',
 181          'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
 182      'http://www.w3.org/1999/XMLSchema' => array(
 183          'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
 184          'float'=>'double','dateTime'=>'string',
 185          'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
 186      'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
 187      'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
 188      'http://xml.apache.org/xml-soap' => array('Map')
 189      );
 190  
 191      /**
 192      * XML entities to convert
 193      *
 194      * @var      array
 195      * @access   public
 196      * @deprecated
 197      * @see    expandEntities
 198      */
 199      var $xmlEntities = array('quot' => '"','amp' => '&',
 200          'lt' => '<','gt' => '>','apos' => "'");
 201      
 202      
 203  
 204      /**
 205      * constructor
 206      *
 207      * @access    public
 208      */
 209  	function nusoap_base() {
 210          $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
 211      }
 212  
 213      /**
 214      * gets the global debug level, which applies to future instances
 215      *
 216      * @return    integer    Debug level 0-9, where 0 turns off
 217      * @access    public
 218      */
 219  	function getGlobalDebugLevel() {
 220          return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
 221      }
 222  
 223      /**
 224      * sets the global debug level, which applies to future instances
 225      *
 226      * @param    int    $level    Debug level 0-9, where 0 turns off
 227      * @access    public
 228      */
 229  	function setGlobalDebugLevel($level) {
 230          $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
 231      }
 232  
 233      /**
 234      * gets the debug level for this instance
 235      *
 236      * @return    int    Debug level 0-9, where 0 turns off
 237      * @access    public
 238      */
 239  	function getDebugLevel() {
 240          return $this->debugLevel;
 241      }
 242  
 243      /**
 244      * sets the debug level for this instance
 245      *
 246      * @param    int    $level    Debug level 0-9, where 0 turns off
 247      * @access    public
 248      */
 249  	function setDebugLevel($level) {
 250          $this->debugLevel = $level;
 251      }
 252  
 253      /**
 254      * adds debug data to the instance debug string with formatting
 255      *
 256      * @param    string $string debug data
 257      * @access   private
 258      */
 259  	function debug($string){
 260          if ($this->debugLevel > 0) {
 261              $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
 262          }
 263      }
 264  
 265      /**
 266      * adds debug data to the instance debug string without formatting
 267      *
 268      * @param    string $string debug data
 269      * @access   public
 270      */
 271  	function appendDebug($string){
 272          if ($this->debugLevel > 0) {
 273              // it would be nice to use a memory stream here to use
 274              // memory more efficiently
 275              global $soap_log;
 276              $soap_log->debug($string);
 277              $this->debug_str .= $string;
 278          }
 279      }
 280  
 281      /**
 282      * clears the current debug data for this instance
 283      *
 284      * @access   public
 285      */
 286  	function clearDebug() {
 287          // it would be nice to use a memory stream here to use
 288          // memory more efficiently
 289          $this->debug_str = '';
 290      }
 291  
 292      /**
 293      * gets the current debug data for this instance
 294      *
 295      * @return   debug data
 296      * @access   public
 297      */
 298      function &getDebug() {
 299          // it would be nice to use a memory stream here to use
 300          // memory more efficiently
 301          return $this->debug_str;
 302      }
 303  
 304      /**
 305      * gets the current debug data for this instance as an XML comment
 306      * this may change the contents of the debug data
 307      *
 308      * @return   debug data as an XML comment
 309      * @access   public
 310      */
 311      function &getDebugAsXMLComment() {
 312          // it would be nice to use a memory stream here to use
 313          // memory more efficiently
 314          while (strpos($this->debug_str, '--')) {
 315              $this->debug_str = str_replace('--', '- -', $this->debug_str);
 316          }
 317          return "<!--\n" . $this->debug_str . "\n-->";
 318      }
 319  
 320      /**
 321      * expands entities, e.g. changes '<' to '&lt;'.
 322      *
 323      * @param    string    $val    The string in which to expand entities.
 324      * @access    private
 325      */
 326  	function expandEntities($val) {
 327          if ($this->charencoding) {
 328              $val = str_replace('&', '&amp;', $val);
 329              $val = str_replace("'", '&apos;', $val);
 330              $val = str_replace('"', '&quot;', $val);
 331              $val = str_replace('<', '&lt;', $val);
 332              $val = str_replace('>', '&gt;', $val);
 333          }
 334          return $val;
 335      }
 336  
 337      /**
 338      * returns error string if present
 339      *
 340      * @return   mixed error string or false
 341      * @access   public
 342      */
 343  	function getError(){
 344          if($this->error_str != ''){
 345              return $this->error_str;
 346          }
 347          return false;
 348      }
 349  
 350      /**
 351      * sets error string
 352      *
 353      * @return   boolean $string error string
 354      * @access   private
 355      */
 356  	function setError($str){
 357          $this->error_str = $str;
 358      }
 359  
 360      /**
 361      * detect if array is a simple array or a struct (associative array)
 362      *
 363      * @param    mixed    $val    The PHP array
 364      * @return    string    (arraySimple|arrayStruct)
 365      * @access    private
 366      */
 367  	function isArraySimpleOrStruct($val) {
 368          $keyList = array_keys($val);
 369          foreach ($keyList as $keyListValue) {
 370              if (!is_int($keyListValue)) {
 371                  return 'arrayStruct';
 372              }
 373          }
 374          return 'arraySimple';
 375      }
 376  
 377      /**
 378      * serializes PHP values in accordance w/ section 5. Type information is
 379      * not serialized if $use == 'literal'.
 380      *
 381      * @param    mixed    $val    The value to serialize
 382      * @param    string    $name    The name (local part) of the XML element
 383      * @param    string    $type    The XML schema type (local part) for the element
 384      * @param    string    $name_ns    The namespace for the name of the XML element
 385      * @param    string    $type_ns    The namespace for the type of the element
 386      * @param    array    $attributes    The attributes to serialize as name=>value pairs
 387      * @param    string    $use    The WSDL "use" (encoded|literal)
 388      * @return    string    The serialized element, possibly with child elements
 389      * @access    public
 390      */
 391  	function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
 392          $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
 393          $this->appendDebug('value=' . $this->varDump($val));
 394          $this->appendDebug('attributes=' . $this->varDump($attributes));
 395          
 396          if(is_object($val) && get_class($val) == 'soapval'){
 397              return $val->serialize($use);
 398          }
 399          // force valid name if necessary
 400          if (is_numeric($name)) {
 401              $name = '__numeric_' . $name;
 402          } elseif (! $name) {
 403              $name = 'noname';
 404          }
 405          // if name has ns, add ns prefix to name
 406          $xmlns = '';
 407          if($name_ns){
 408              $prefix = 'nu'.rand(1000,9999);
 409              $name = $prefix.':'.$name;
 410              $xmlns .= " xmlns:$prefix=\"$name_ns\"";
 411          }
 412          // if type is prefixed, create type prefix
 413          if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
 414              // need to fix this. shouldn't default to xsd if no ns specified
 415              // w/o checking against typemap
 416              $type_prefix = 'xsd';
 417          } elseif($type_ns){
 418              $type_prefix = 'ns'.rand(1000,9999);
 419              $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
 420          }
 421          // serialize attributes if present
 422          $atts = '';
 423          if($attributes){
 424              foreach($attributes as $k => $v){
 425                  $atts .= " $k=\"".$this->expandEntities($v).'"';
 426              }
 427          }
 428          // serialize null value
 429          if (is_null($val)) {
 430              if ($use == 'literal') {
 431                  // TODO: depends on minOccurs
 432                  return "<$name$xmlns $atts/>";
 433              } else {
 434                  if (isset($type) && isset($type_prefix)) {
 435                      $type_str = " xsi:type=\"$type_prefix:$type\"";
 436                  } else {
 437                      $type_str = '';
 438                  }
 439                  return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
 440              }
 441          }
 442          // serialize if an xsd built-in primitive type
 443          if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
 444              if (is_bool($val)) {
 445                  if ($type == 'boolean') {
 446                      $val = $val ? 'true' : 'false';
 447                  } elseif (! $val) {
 448                      $val = 0;
 449                  }
 450              } else if (is_string($val)) {
 451                  $val = $this->expandEntities($val);
 452              }
 453              if ($use == 'literal') {
 454                  return "<$name$xmlns $atts>$val</$name>";
 455              } else {
 456                  return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>";
 457              }
 458          }
 459          // detect type and serialize
 460          $xml = '';
 461          switch(true) {
 462              case (is_bool($val) || $type == 'boolean'):
 463                  if ($type == 'boolean') {
 464                      $val = $val ? 'true' : 'false';
 465                  } elseif (! $val) {
 466                      $val = 0;
 467                  }
 468                  if ($use == 'literal') {
 469                      $xml .= "<$name$xmlns $atts>$val</$name>";
 470                  } else {
 471                      $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
 472                  }
 473                  break;
 474              case (is_int($val) || is_long($val) || $type == 'int'):
 475                  if ($use == 'literal') {
 476                      $xml .= "<$name$xmlns $atts>$val</$name>";
 477                  } else {
 478                      $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
 479                  }
 480                  break;
 481              case (is_float($val)|| is_double($val) || $type == 'float'):
 482                  if ($use == 'literal') {
 483                      $xml .= "<$name$xmlns $atts>$val</$name>";
 484                  } else {
 485                      $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
 486                  }
 487                  break;
 488              case (is_string($val) || $type == 'string'):
 489                  $val = $this->expandEntities($val);
 490                  if ($use == 'literal') {
 491                      $xml .= "<$name$xmlns $atts>$val</$name>";
 492                  } else {
 493                      $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
 494                  }
 495                  break;
 496              case is_object($val):
 497                  if (! $name) {
 498                      $name = get_class($val);
 499                      $this->debug("In serialize_val, used class name $name as element name");
 500                  } else {
 501                      $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
 502                  }
 503                  foreach(get_object_vars($val) as $k => $v){
 504                      $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
 505                  }
 506                  $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
 507                  break;
 508              break;
 509              case (is_array($val) || $type):
 510                  // detect if struct or array
 511                  $valueType = $this->isArraySimpleOrStruct($val);
 512                  if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
 513                      $i = 0;
 514                      if(is_array($val) && count($val)> 0){
 515                          foreach($val as $v){
 516                              if(is_object($v) && get_class($v) ==  'soapval'){
 517                                  $tt_ns = $v->type_ns;
 518                                  $tt = $v->type;
 519                              } elseif (is_array($v)) {
 520                                  $tt = $this->isArraySimpleOrStruct($v);
 521                              } else {
 522                                  $tt = gettype($v);
 523                              }
 524                              $array_types[$tt] = 1;
 525                              // TODO: for literal, the name should be $name
 526                              $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
 527                              ++$i;
 528                          }
 529                          if(count($array_types) > 1){
 530                              $array_typename = 'xsd:anyType';
 531                          } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
 532                              if ($tt == 'integer') {
 533                                  $tt = 'int';
 534                              }
 535                              $array_typename = 'xsd:'.$tt;
 536                          } elseif(isset($tt) && $tt == 'arraySimple'){
 537                              $array_typename = 'SOAP-ENC:Array';
 538                          } elseif(isset($tt) && $tt == 'arrayStruct'){
 539                              $array_typename = 'unnamed_struct_use_soapval';
 540                          } else {
 541                              // if type is prefixed, create type prefix
 542                              if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
 543                                   $array_typename = 'xsd:' . $tt;
 544                              } elseif ($tt_ns) {
 545                                  $tt_prefix = 'ns' . rand(1000, 9999);
 546                                  $array_typename = "$tt_prefix:$tt";
 547                                  $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
 548                              } else {
 549                                  $array_typename = $tt;
 550                              }
 551                          }
 552                          $array_type = $i;
 553                          if ($use == 'literal') {
 554                              $type_str = '';
 555                          } else if (isset($type) && isset($type_prefix)) {
 556                              $type_str = " xsi:type=\"$type_prefix:$type\"";
 557                          } else {
 558                              $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
 559                          }
 560                      // empty array
 561                      } else {
 562                          if ($use == 'literal') {
 563                              $type_str = '';
 564                          } else if (isset($type) && isset($type_prefix)) {
 565                              $type_str = " xsi:type=\"$type_prefix:$type\"";
 566                          } else {
 567                              $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
 568                          }
 569                      }
 570                      // TODO: for array in literal, there is no wrapper here
 571                      $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
 572                  } else {
 573                      // got a struct
 574                      if(isset($type) && isset($type_prefix)){
 575                          $type_str = " xsi:type=\"$type_prefix:$type\"";
 576                      } else {
 577                          $type_str = '';
 578                      }
 579                      if ($use == 'literal') {
 580                          $xml .= "<$name$xmlns $atts>";
 581                      } else {
 582                          $xml .= "<$name$xmlns$type_str$atts>";
 583                      }
 584                      foreach($val as $k => $v){
 585                          // Apache Map
 586                          if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
 587                              $xml .= '<item>';
 588                              $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
 589                              $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
 590                              $xml .= '</item>';
 591                          } else {
 592                              $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
 593                          }
 594                      }
 595                      $xml .= "</$name>";
 596                  }
 597                  break;
 598              default:
 599                  $xml .= 'not detected, got '.gettype($val).' for '.$val;
 600                  break;
 601          }
 602          return $xml;
 603      }
 604  
 605      /**
 606      * serializes a message
 607      *
 608      * @param string $body the XML of the SOAP body
 609      * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers
 610      * @param array $namespaces optional the namespaces used in generating the body and headers
 611      * @param string $style optional (rpc|document)
 612      * @param string $use optional (encoded|literal)
 613      * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
 614      * @return string the message
 615      * @access public
 616      */
 617      function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
 618      // TODO: add an option to automatically run utf8_encode on $body and $headers
 619      // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
 620      // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
 621  
 622      $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
 623      $this->debug("headers:");
 624      $this->appendDebug($this->varDump($headers));
 625      $this->debug("namespaces:");
 626      $this->appendDebug($this->varDump($namespaces));
 627  
 628      // serialize namespaces
 629      $ns_string = '';
 630      foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
 631          $ns_string .= " xmlns:$k=\"$v\"";
 632      }
 633      if($encodingStyle) {
 634          $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
 635      }
 636  
 637      // serialize headers
 638      if($headers){
 639          if (is_array($headers)) {
 640              $xml = '';
 641              foreach ($headers as $header) {
 642                  $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
 643              }
 644              $headers = $xml;
 645              $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
 646          }
 647          $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
 648      }
 649      // serialize envelope
 650      return
 651      '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
 652      '<SOAP-ENV:Envelope'.$ns_string.">".
 653      $headers.
 654      "<SOAP-ENV:Body>".
 655          $body.
 656      "</SOAP-ENV:Body>".
 657      "</SOAP-ENV:Envelope>";
 658      }
 659  
 660      /**
 661       * formats a string to be inserted into an HTML stream
 662       *
 663       * @param string $str The string to format
 664       * @return string The formatted string
 665       * @access public
 666       * @deprecated
 667       */
 668      function formatDump($str){
 669          $str = htmlspecialchars($str);
 670          return nl2br($str);
 671      }
 672  
 673      /**
 674      * contracts (changes namespace to prefix) a qualified name
 675      *
 676      * @param    string $qname qname
 677      * @return    string contracted qname
 678      * @access   private
 679      */
 680  	function contractQname($qname){
 681          // get element namespace
 682          //$this->xdebug("Contract $qname");
 683          if (strrpos($qname, ':')) {
 684              // get unqualified name
 685              $name = substr($qname, strrpos($qname, ':') + 1);
 686              // get ns
 687              $ns = substr($qname, 0, strrpos($qname, ':'));
 688              $p = $this->getPrefixFromNamespace($ns);
 689              if ($p) {
 690                  return $p . ':' . $name;
 691              }
 692              return $qname;
 693          } else {
 694              return $qname;
 695          }
 696      }
 697  
 698      /**
 699      * expands (changes prefix to namespace) a qualified name
 700      *
 701      * @param    string $string qname
 702      * @return    string expanded qname
 703      * @access   private
 704      */
 705  	function expandQname($qname){
 706          // get element prefix
 707          if(strpos($qname,':') && !ereg('^http://',$qname)){
 708              // get unqualified name
 709              $name = substr(strstr($qname,':'),1);
 710              // get ns prefix
 711              $prefix = substr($qname,0,strpos($qname,':'));
 712              if(isset($this->namespaces[$prefix])){
 713                  return $this->namespaces[$prefix].':'.$name;
 714              } else {
 715                  return $qname;
 716              }
 717          } else {
 718              return $qname;
 719          }
 720      }
 721  
 722      /**
 723      * returns the local part of a prefixed string
 724      * returns the original string, if not prefixed
 725      *
 726      * @param string $str The prefixed string
 727      * @return string The local part
 728      * @access public
 729      */
 730  	function getLocalPart($str){
 731          if($sstr = strrchr($str,':')){
 732              // get unqualified name
 733              return substr( $sstr, 1 );
 734          } else {
 735              return $str;
 736          }
 737      }
 738  
 739      /**
 740      * returns the prefix part of a prefixed string
 741      * returns false, if not prefixed
 742      *
 743      * @param string $str The prefixed string
 744      * @return mixed The prefix or false if there is no prefix
 745      * @access public
 746      */
 747  	function getPrefix($str){
 748          if($pos = strrpos($str,':')){
 749              // get prefix
 750              return substr($str,0,$pos);
 751          }
 752          return false;
 753      }
 754  
 755      /**
 756      * pass it a prefix, it returns a namespace
 757      *
 758      * @param string $prefix The prefix
 759      * @return mixed The namespace, false if no namespace has the specified prefix
 760      * @access public
 761      */
 762  	function getNamespaceFromPrefix($prefix){
 763          if (isset($this->namespaces[$prefix])) {
 764              return $this->namespaces[$prefix];
 765          }
 766          //$this->setError("No namespace registered for prefix '$prefix'");
 767          return false;
 768      }
 769  
 770      /**
 771      * returns the prefix for a given namespace (or prefix)
 772      * or false if no prefixes registered for the given namespace
 773      *
 774      * @param string $ns The namespace
 775      * @return mixed The prefix, false if the namespace has no prefixes
 776      * @access public
 777      */
 778  	function getPrefixFromNamespace($ns) {
 779          foreach ($this->namespaces as $p => $n) {
 780              if ($ns == $n || $ns == $p) {
 781                  $this->usedNamespaces[$p] = $n;
 782                  return $p;
 783              }
 784          }
 785          return false;
 786      }
 787  
 788      /**
 789      * returns the time in ODBC canonical form with microseconds
 790      *
 791      * @return string The time in ODBC canonical form with microseconds
 792      * @access public
 793      */
 794  	function getmicrotime() {
 795          if (function_exists('gettimeofday')) {
 796              $tod = gettimeofday();
 797              $sec = $tod['sec'];
 798              $usec = $tod['usec'];
 799          } else {
 800              $sec = time();
 801              $usec = 0;
 802          }
 803          return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
 804      }
 805  
 806      /**
 807       * Returns a string with the output of var_dump
 808       *
 809       * @param mixed $data The variable to var_dump
 810       * @return string The output of var_dump
 811       * @access public
 812       */
 813      function varDump($data) {
 814          ob_start();
 815          var_dump($data);
 816          $ret_val = ob_get_contents();
 817          ob_end_clean();
 818          return $ret_val;
 819      }
 820  }
 821  
 822  // XML Schema Datatype Helper Functions
 823  
 824  //xsd:dateTime helpers
 825  
 826  /**
 827  * convert unix timestamp to ISO 8601 compliant date string
 828  *
 829  * @param    string $timestamp Unix time stamp
 830  * @access   public
 831  */
 832  function timestamp_to_iso8601($timestamp,$utc=true){
 833      $datestr = date('Y-m-d\TH:i:sO',$timestamp);
 834      if($utc){
 835          $eregStr =
 836          '([0-9]{4})-'.    // centuries & years CCYY-
 837          '([0-9]{2})-'.    // months MM-
 838          '([0-9]{2})'.    // days DD
 839          'T'.            // separator T
 840          '([0-9]{2}):'.    // hours hh:
 841          '([0-9]{2}):'.    // minutes mm:
 842          '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
 843          '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
 844  
 845          if(ereg($eregStr,$datestr,$regs)){
 846              return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
 847          }
 848          return false;
 849      } else {
 850          return $datestr;
 851      }
 852  }
 853  
 854  /**
 855  * convert ISO 8601 compliant date string to unix timestamp
 856  *
 857  * @param    string $datestr ISO 8601 compliant date string
 858  * @access   public
 859  */
 860  function iso8601_to_timestamp($datestr){
 861      $eregStr =
 862      '([0-9]{4})-'.    // centuries & years CCYY-
 863      '([0-9]{2})-'.    // months MM-
 864      '([0-9]{2})'.    // days DD
 865      'T'.            // separator T
 866      '([0-9]{2}):'.    // hours hh:
 867      '([0-9]{2}):'.    // minutes mm:
 868      '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
 869      '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
 870      if(ereg($eregStr,$datestr,$regs)){
 871          // not utc
 872          if($regs[8] != 'Z'){
 873              $op = substr($regs[8],0,1);
 874              $h = substr($regs[8],1,2);
 875              $m = substr($regs[8],strlen($regs[8])-2,2);
 876              if($op == '-'){
 877                  $regs[4] = $regs[4] + $h;
 878                  $regs[5] = $regs[5] + $m;
 879              } elseif($op == '+'){
 880                  $regs[4] = $regs[4] - $h;
 881                  $regs[5] = $regs[5] - $m;
 882              }
 883          }
 884          return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
 885      } else {
 886          return false;
 887      }
 888  }
 889  
 890  /**
 891  * sleeps some number of microseconds
 892  *
 893  * @param    string $usec the number of microseconds to sleep
 894  * @access   public
 895  * @deprecated
 896  */
 897  function usleepWindows($usec)
 898  {
 899      $start = gettimeofday();
 900      
 901      do
 902      {
 903          $stop = gettimeofday();
 904          $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
 905          + $stop['usec'] - $start['usec'];
 906      }
 907      while ($timePassed < $usec);
 908  }
 909  
 910  ?><?php
 911  
 912  
 913  
 914  /**
 915  * Contains information for a SOAP fault.
 916  * Mainly used for returning faults from deployed functions
 917  * in a server instance.
 918  * @author   Dietrich Ayala <dietrich@ganx4.com>
 919  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
 920  * @access public
 921  */
 922  class soap_fault extends nusoap_base {
 923      /**
 924       * The fault code (client|server)
 925       * @var string
 926       * @access private
 927       */
 928      var $faultcode;
 929      /**
 930       * The fault actor
 931       * @var string
 932       * @access private
 933       */
 934      var $faultactor;
 935      /**
 936       * The fault string, a description of the fault
 937       * @var string
 938       * @access private
 939       */
 940      var $faultstring;
 941      /**
 942       * The fault detail, typically a string or array of string
 943       * @var mixed
 944       * @access private
 945       */
 946      var $faultdetail;
 947  
 948      /**
 949      * constructor
 950      *
 951      * @param string $faultcode (client | server)
 952      * @param string $faultactor only used when msg routed between multiple actors
 953      * @param string $faultstring human readable error message
 954      * @param mixed $faultdetail detail, typically a string or array of string
 955      */
 956  	function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
 957          parent::nusoap_base();
 958          $this->faultcode = $faultcode;
 959          $this->faultactor = $faultactor;
 960          $this->faultstring = $faultstring;
 961          $this->faultdetail = $faultdetail;
 962      }
 963  
 964      /**
 965      * serialize a fault
 966      *
 967      * @return    string    The serialization of the fault instance.
 968      * @access   public
 969      */
 970  	function serialize(){
 971          $ns_string = '';
 972          foreach($this->namespaces as $k => $v){
 973              $ns_string .= "\n  xmlns:$k=\"$v\"";
 974          }
 975          $return_msg =
 976              '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
 977              '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
 978                  '<SOAP-ENV:Body>'.
 979                  '<SOAP-ENV:Fault>'.
 980                      $this->serialize_val($this->faultcode, 'faultcode').
 981                      $this->serialize_val($this->faultactor, 'faultactor').
 982                      $this->serialize_val($this->faultstring, 'faultstring').
 983                      $this->serialize_val($this->faultdetail, 'detail').
 984                  '</SOAP-ENV:Fault>'.
 985                  '</SOAP-ENV:Body>'.
 986              '</SOAP-ENV:Envelope>';
 987          return $return_msg;
 988      }
 989  }
 990  
 991  
 992  
 993  ?><?php
 994  
 995  
 996  
 997  /**
 998  * parses an XML Schema, allows access to it's data, other utility methods
 999  * no validation... yet.
1000  * very experimental and limited. As is discussed on XML-DEV, I'm one of the people
1001  * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
1002  * tutorials I refer to :)
1003  *
1004  * @author   Dietrich Ayala <dietrich@ganx4.com>
1005  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
1006  * @access   public
1007  */
1008  class XMLSchema extends nusoap_base  {
1009      
1010      // files
1011      var $schema = '';
1012      var $xml = '';
1013      // namespaces
1014      var $enclosingNamespaces;
1015      // schema info
1016      var $schemaInfo = array();
1017      var $schemaTargetNamespace = '';
1018      // types, elements, attributes defined by the schema
1019      var $attributes = array();
1020      var $complexTypes = array();
1021      var $complexTypeStack = array();
1022      var $currentComplexType = null;
1023      var $elements = array();
1024      var $elementStack = array();
1025      var $currentElement = null;
1026      var $simpleTypes = array();
1027      var $simpleTypeStack = array();
1028      var $currentSimpleType = null;
1029      // imports
1030      var $imports = array();
1031      // parser vars
1032      var $parser;
1033      var $position = 0;
1034      var $depth = 0;
1035      var $depth_array = array();
1036      var $message = array();
1037      var $defaultNamespace = array();
1038      
1039      /**
1040      * constructor
1041      *
1042      * @param    string $schema schema document URI
1043      * @param    string $xml xml document URI
1044      * @param    string $namespaces namespaces defined in enclosing XML
1045      * @access   public
1046      */
1047  	function XMLSchema($schema='',$xml='',$namespaces=array()){
1048          parent::nusoap_base();
1049          $this->debug('xmlschema class instantiated, inside constructor');
1050          // files
1051          $this->schema = $schema;
1052          $this->xml = $xml;
1053  
1054          // namespaces
1055          $this->enclosingNamespaces = $namespaces;
1056          $this->namespaces = array_merge($this->namespaces, $namespaces);
1057  
1058          // parse schema file
1059          if($schema != ''){
1060              $this->debug('initial schema file: '.$schema);
1061              $this->parseFile($schema, 'schema');
1062          }
1063  
1064          // parse xml file
1065          if($xml != ''){
1066              $this->debug('initial xml file: '.$xml);
1067              $this->parseFile($xml, 'xml');
1068          }
1069  
1070      }
1071  
1072      /**
1073      * parse an XML file
1074      *
1075      * @param string $xml, path/URL to XML file
1076      * @param string $type, (schema | xml)
1077      * @return boolean
1078      * @access public
1079      */
1080  	function parseFile($xml,$type){
1081          // parse xml file
1082          if($xml != ""){
1083              $xmlStr = @join("",@file($xml));
1084              if($xmlStr == ""){
1085                  $msg = 'Error reading XML from '.$xml;
1086                  $this->setError($msg);
1087                  $this->debug($msg);
1088              return false;
1089              } else {
1090                  $this->debug("parsing $xml");
1091                  $this->parseString($xmlStr,$type);
1092                  $this->debug("done parsing $xml");
1093              return true;
1094              }
1095          }
1096          return false;
1097      }
1098  
1099      /**
1100      * parse an XML string
1101      *
1102      * @param    string $xml path or URL
1103      * @param string $type, (schema|xml)
1104      * @access   private
1105      */
1106  	function parseString($xml,$type){
1107          // parse xml string
1108          if($xml != ""){
1109  
1110              // Create an XML parser.
1111              $this->parser = xml_parser_create();
1112              // Set the options for parsing the XML data.
1113              xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1114  
1115              // Set the object for the parser.
1116              xml_set_object($this->parser, $this);
1117  
1118              // Set the element handlers for the parser.
1119              if($type == "schema"){
1120                  xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1121                  xml_set_character_data_handler($this->parser,'schemaCharacterData');
1122              } elseif($type == "xml"){
1123                  xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1124                  xml_set_character_data_handler($this->parser,'xmlCharacterData');
1125              }
1126  
1127              // Parse the XML file.
1128              if(!xml_parse($this->parser,$xml,true)){
1129              // Display an error message.
1130                  $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1131                  xml_get_current_line_number($this->parser),
1132                  xml_error_string(xml_get_error_code($this->parser))
1133                  );
1134                  $this->debug($errstr);
1135                  $this->debug("XML payload:\n" . $xml);
1136                  $this->setError($errstr);
1137              }
1138              
1139              xml_parser_free($this->parser);
1140          } else{
1141              $this->debug('no xml passed to parseString()!!');
1142              $this->setError('no xml passed to parseString()!!');
1143          }
1144      }
1145  
1146      /**
1147      * start-element handler
1148      *
1149      * @param    string $parser XML parser object
1150      * @param    string $name element name
1151      * @param    string $attrs associative array of attributes
1152      * @access   private
1153      */
1154  	function schemaStartElement($parser, $name, $attrs) {
1155          
1156          // position in the total number of elements, starting from 0
1157          $pos = $this->position++;
1158          $depth = $this->depth++;
1159          // set self as current value for this depth
1160          $this->depth_array[$depth] = $pos;
1161          $this->message[$pos] = array('cdata' => ''); 
1162          if ($depth > 0) {
1163              $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1164          } else {
1165              $this->defaultNamespace[$pos] = false;
1166          }
1167  
1168          // get element prefix
1169          if($prefix = $this->getPrefix($name)){
1170              // get unqualified name
1171              $name = $this->getLocalPart($name);
1172          } else {
1173              $prefix = '';
1174          }
1175          
1176          // loop thru attributes, expanding, and registering namespace declarations
1177          if(count($attrs) > 0){
1178              foreach($attrs as $k => $v){
1179                  // if ns declarations, add to class level array of valid namespaces
1180                  if(ereg("^xmlns",$k)){
1181                      //$this->xdebug("$k: $v");
1182                      //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1183                      if($ns_prefix = substr(strrchr($k,':'),1)){
1184                          //$this->xdebug("Add namespace[$ns_prefix] = $v");
1185                          $this->namespaces[$ns_prefix] = $v;
1186                      } else {
1187                          $this->defaultNamespace[$pos] = $v;
1188                          if (! $this->getPrefixFromNamespace($v)) {
1189                              $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1190                          }
1191                      }
1192                      if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1193                          $this->XMLSchemaVersion = $v;
1194                          $this->namespaces['xsi'] = $v.'-instance';
1195                      }
1196                  }
1197              }
1198              foreach($attrs as $k => $v){
1199                  // expand each attribute
1200                  $k = strpos($k,':') ? $this->expandQname($k) : $k;
1201                  $v = strpos($v,':') ? $this->expandQname($v) : $v;
1202                  $eAttrs[$k] = $v;
1203              }
1204              $attrs = $eAttrs;
1205          } else {
1206              $attrs = array();
1207          }
1208          // find status, register data
1209          switch($name){
1210              case 'all':            // (optional) compositor content for a complexType
1211              case 'choice':
1212              case 'group':
1213              case 'sequence':
1214                  //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1215                  $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1216                  //if($name == 'all' || $name == 'sequence'){
1217                  //    $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1218                  //}
1219              break;
1220              case 'attribute':    // complexType attribute
1221                  //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1222                  $this->xdebug("parsing attribute:");
1223                  $this->appendDebug($this->varDump($attrs));
1224                  if (!isset($attrs['form'])) {
1225                      $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1226                  }
1227                  if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1228                      $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1229                      if (!strpos($v, ':')) {
1230                          // no namespace in arrayType attribute value...
1231                          if ($this->defaultNamespace[$pos]) {
1232                              // ...so use the default
1233                              $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1234                          }
1235                      }
1236                  }
1237                  if(isset($attrs['name'])){
1238                      $this->attributes[$attrs['name']] = $attrs;
1239                      $aname = $attrs['name'];
1240                  } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1241                      if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1242                          $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1243                      } else {
1244                          $aname = '';
1245                      }
1246                  } elseif(isset($attrs['ref'])){
1247                      $aname = $attrs['ref'];
1248                      $this->attributes[$attrs['ref']] = $attrs;
1249                  }
1250                  
1251                  if($this->currentComplexType){    // This should *always* be
1252                      $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1253                  }
1254                  // arrayType attribute
1255                  if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1256                      $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1257                      $prefix = $this->getPrefix($aname);
1258                      if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
1259                          $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1260                      } else {
1261                          $v = '';
1262                      }
1263                      if(strpos($v,'[,]')){
1264                          $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1265                      }
1266                      $v = substr($v,0,strpos($v,'[')); // clip the []
1267                      if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
1268                          $v = $this->XMLSchemaVersion.':'.$v;
1269                      }
1270                      $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1271                  }
1272              break;
1273              case 'complexContent':    // (optional) content for a complexType
1274              break;
1275              case 'complexType':
1276                  array_push($this->complexTypeStack, $this->currentComplexType);
1277                  if(isset($attrs['name'])){
1278                      $this->xdebug('processing named complexType '.$attrs['name']);
1279                      //$this->currentElement = false;
1280                      $this->currentComplexType = $attrs['name'];
1281                      $this->complexTypes[$this->currentComplexType] = $attrs;
1282                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1283                      // This is for constructs like
1284                      //           <complexType name="ListOfString" base="soap:Array">
1285                      //                <sequence>
1286                      //                    <element name="string" type="xsd:string"
1287                      //                        minOccurs="0" maxOccurs="unbounded" />
1288                      //                </sequence>
1289                      //            </complexType>
1290                      if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1291                          $this->xdebug('complexType is unusual array');
1292                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1293                      } else {
1294                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1295                      }
1296                  }else{
1297                      $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
1298                      $this->currentComplexType = $this->currentElement . '_ContainedType';
1299                      //$this->currentElement = false;
1300                      $this->complexTypes[$this->currentComplexType] = $attrs;
1301                      $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1302                      // This is for constructs like
1303                      //           <complexType name="ListOfString" base="soap:Array">
1304                      //                <sequence>
1305                      //                    <element name="string" type="xsd:string"
1306                      //                        minOccurs="0" maxOccurs="unbounded" />
1307                      //                </sequence>
1308                      //            </complexType>
1309                      if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
1310                          $this->xdebug('complexType is unusual array');
1311                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1312                      } else {
1313                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1314                      }
1315                  }
1316              break;
1317              case 'element':
1318                  array_push($this->elementStack, $this->currentElement);
1319                  // elements defined as part of a complex type should
1320                  // not really be added to $this->elements, but for some
1321                  // reason, they are
1322                  if (!isset($attrs['form'])) {
1323                      $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1324                  }
1325                  if(isset($attrs['type'])){
1326                      $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
1327                      if (! $this->getPrefix($attrs['type'])) {
1328                          if ($this->defaultNamespace[$pos]) {
1329                              $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1330                              $this->xdebug('used default namespace to make type ' . $attrs['type']);
1331                          }
1332                      }
1333                      // This is for constructs like
1334                      //           <complexType name="ListOfString" base="soap:Array">
1335                      //                <sequence>
1336                      //                    <element name="string" type="xsd:string"
1337                      //                        minOccurs="0" maxOccurs="unbounded" />
1338                      //                </sequence>
1339                      //            </complexType>
1340                      if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
1341                          $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1342                          $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1343                      }
1344                      $this->currentElement = $attrs['name'];
1345                      $this->elements[ $attrs['name'] ] = $attrs;
1346                      $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1347                      $ename = $attrs['name'];
1348                  } elseif(isset($attrs['ref'])){
1349                      $this->xdebug("processing element as ref to ".$attrs['ref']);
1350                      $this->currentElement = "ref to ".$attrs['ref'];
1351                      $ename = $this->getLocalPart($attrs['ref']);
1352                  } else {
1353                      $this->xdebug("processing untyped element ".$attrs['name']);
1354                      $this->currentElement = $attrs['name'];
1355                      $this->elements[ $attrs['name'] ] = $attrs;
1356                      $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1357                      $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
1358                      $this->elements[ $attrs['name'] ]['type'] = $attrs['type'];
1359                      $ename = $attrs['name'];
1360                  }
1361                  if(isset($ename) && $this->currentComplexType){
1362                      $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1363                  }
1364              break;
1365              case 'enumeration':    //    restriction value list member
1366                  $this->xdebug('enumeration ' . $attrs['value']);
1367                  if ($this->currentSimpleType) {
1368                      $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1369                  } elseif ($this->currentComplexType) {
1370                      $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1371                  }
1372              break;
1373              case 'extension':    // simpleContent or complexContent type extension
1374                  $this->xdebug('extension ' . $attrs['base']);
1375                  if ($this->currentComplexType) {
1376                      $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1377                  }
1378              break;
1379              case 'import':
1380                  if (isset($attrs['schemaLocation'])) {
1381                      //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1382                      $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
1383                  } else {
1384                      //$this->xdebug('import namespace ' . $attrs['namespace']);
1385                      $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1386                      if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
1387                          $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
1388                      }
1389                  }
1390              break;
1391              case 'list':    // simpleType value list
1392              break;
1393              case 'restriction':    // simpleType, simpleContent or complexContent value restriction
1394                  $this->xdebug('restriction ' . $attrs['base']);
1395                  if($this->currentSimpleType){
1396                      $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1397                  } elseif($this->currentComplexType){
1398                      $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1399                      if(strstr($attrs['base'],':') == ':Array'){
1400                          $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1401                      }
1402                  }
1403              break;
1404              case 'schema':
1405                  $this->schemaInfo = $attrs;
1406                  $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1407                  if (isset($attrs['targetNamespace'])) {
1408                      $this->schemaTargetNamespace = $attrs['targetNamespace'];
1409                  }
1410                  if (!isset($attrs['elementFormDefault'])) {
1411                      $this->schemaInfo['elementFormDefault'] = 'unqualified';
1412                  }
1413                  if (!isset($attrs['attributeFormDefault'])) {
1414                      $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1415                  }
1416              break;
1417              case 'simpleContent':    // (optional) content for a complexType
1418              break;
1419              case 'simpleType':
1420                  array_push($this->simpleTypeStack, $this->currentSimpleType);
1421                  if(isset($attrs['name'])){
1422                      $this->xdebug("processing simpleType for name " . $attrs['name']);
1423                      $this->currentSimpleType = $attrs['name'];
1424                      $this->simpleTypes[ $attrs['name'] ] = $attrs;
1425                      $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
1426                      $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
1427                  } else {
1428                      $this->xdebug('processing unnamed simpleType for element '.$this->currentElement);
1429                      $this->currentSimpleType = $this->currentElement . '_ContainedType';
1430                      //$this->currentElement = false;
1431                      $this->simpleTypes[$this->currentSimpleType] = $attrs;
1432                      $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1433                  }
1434              break;
1435              case 'union':    // simpleType type list
1436              break;
1437              default:
1438                  //$this->xdebug("do not have anything to do for element $name");
1439          }
1440      }
1441  
1442      /**
1443      * end-element handler
1444      *
1445      * @param    string $parser XML parser object
1446      * @param    string $name element name
1447      * @access   private
1448      */
1449  	function schemaEndElement($parser, $name) {
1450          // bring depth down a notch
1451          $this->depth--;
1452          // position of current element is equal to the last value left in depth_array for my depth
1453          if(isset($this->depth_array[$this->depth])){
1454              $pos = $this->depth_array[$this->depth];
1455          }
1456          // get element prefix
1457          if ($prefix = $this->getPrefix($name)){
1458              // get unqualified name
1459              $name = $this->getLocalPart($name);
1460          } else {
1461              $prefix = '';
1462          }
1463          // move on...
1464          if($name == 'complexType'){
1465              $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
1466              $this->currentComplexType = array_pop($this->complexTypeStack);
1467              //$this->currentElement = false;
1468          }
1469          if($name == 'element'){
1470              $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
1471              $this->currentElement = array_pop($this->elementStack);
1472          }
1473          if($name == 'simpleType'){
1474              $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
1475              $this->currentSimpleType = array_pop($this->simpleTypeStack);
1476          }
1477      }
1478  
1479      /**
1480      * element content handler
1481      *
1482      * @param    string $parser XML parser object
1483      * @param    string $data element content
1484      * @access   private
1485      */
1486  	function schemaCharacterData($parser, $data){
1487          $pos = $this->depth_array[$this->depth - 1];
1488          $this->message[$pos]['cdata'] .= $data;
1489      }
1490  
1491      /**
1492      * serialize the schema
1493      *
1494      * @access   public
1495      */
1496  	function serializeSchema(){
1497  
1498          $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1499          $xml = '';
1500          // imports
1501          if (sizeof($this->imports) > 0) {
1502              foreach($this->imports as $ns => $list) {
1503                  foreach ($list as $ii) {
1504                      if ($ii['location'] != '') {
1505                          $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1506                      } else {
1507                          $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1508                      }
1509                  }
1510              } 
1511          } 
1512          // complex types
1513          foreach($this->complexTypes as $typeName => $attrs){
1514              $contentStr = '';
1515              // serialize child elements
1516              if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
1517                  foreach($attrs['elements'] as $element => $eParts){
1518                      if(isset($eParts['ref'])){
1519                          $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
1520                      } else {
1521                          $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
1522                          foreach ($eParts as $aName => $aValue) {
1523                              // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1524                              if ($aName != 'name' && $aName != 'type') {
1525                                  $contentStr .= " $aName=\"$aValue\"";
1526                              }
1527                          }
1528                          $contentStr .= "/>\n";
1529                      }
1530                  }
1531                  // compositor wraps elements
1532                  if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1533                      $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
1534                  }
1535              }
1536              // attributes
1537              if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
1538                  foreach($attrs['attrs'] as $attr => $aParts){
1539                      $contentStr .= "    <$schemaPrefix:attribute";
1540                      foreach ($aParts as $a => $v) {
1541                          if ($a == 'ref' || $a == 'type') {
1542                              $contentStr .= " $a=\"".$this->contractQName($v).'"';
1543                          } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1544                              $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1545                              $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
1546                          } else {
1547                              $contentStr .= " $a=\"$v\"";
1548                          }
1549                      }
1550                      $contentStr .= "/>\n";
1551                  }
1552              }
1553              // if restriction
1554              if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
1555                  $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
1556                  // complex or simple content
1557                  if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
1558                      $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
1559                  }
1560              }
1561              // finalize complex type
1562              if($contentStr != ''){
1563                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
1564              } else {
1565                  $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1566              }
1567              $xml .= $contentStr;
1568          }
1569          // simple types
1570          if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
1571              foreach($this->simpleTypes as $typeName => $eParts){
1572                  $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n";
1573                  if (isset($eParts['enumeration'])) {
1574                      foreach ($eParts['enumeration'] as $e) {
1575                          $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
1576                      }
1577                  }
1578                  $xml .= " </$schemaPrefix:simpleType>";
1579              }
1580          }
1581          // elements
1582          if(isset($this->elements) && count($this->elements) > 0){
1583              foreach($this->elements as $element => $eParts){
1584                  $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
1585              }
1586          }
1587          // attributes
1588          if(isset($this->attributes) && count($this->attributes) > 0){
1589              foreach($this->attributes as $attr => $aParts){
1590                  $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
1591              }
1592          }
1593          // finish 'er up
1594          $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
1595          foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1596              $el .= " xmlns:$nsp=\"$ns\"\n";
1597          }
1598          $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
1599          return $xml;
1600      }
1601  
1602      /**
1603      * adds debug data to the clas level debug string
1604      *
1605      * @param    string $string debug data
1606      * @access   private
1607      */
1608  	function xdebug($string){
1609          $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
1610      }
1611  
1612      /**
1613      * get the PHP type of a user defined type in the schema
1614      * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1615      * returns false if no type exists, or not w/ the given namespace
1616      * else returns a string that is either a native php type, or 'struct'
1617      *
1618      * @param string $type, name of defined type
1619      * @param string $ns, namespace of type
1620      * @return mixed
1621      * @access public
1622      * @deprecated
1623      */
1624  	function getPHPType($type,$ns){
1625          if(isset($this->typemap[$ns][$type])){
1626              //print "found type '$type' and ns $ns in typemap<br>";
1627              return $this->typemap[$ns][$type];
1628          } elseif(isset($this->complexTypes[$type])){
1629              //print "getting type '$type' and ns $ns from complexTypes array<br>";
1630              return $this->complexTypes[$type]['phpType'];
1631          }
1632          return false;
1633      }
1634  
1635      /**
1636      * returns an associative array of information about a given type
1637      * returns false if no type exists by the given name
1638      *
1639      *    For a complexType typeDef = array(
1640      *    'restrictionBase' => '',
1641      *    'phpType' => '',
1642      *    'compositor' => '(sequence|all)',
1643      *    'elements' => array(), // refs to elements array
1644      *    'attrs' => array() // refs to attributes array
1645      *    ... and so on (see addComplexType)
1646      *    )
1647      *
1648      *   For simpleType or element, the array has different keys.
1649      *
1650      * @param string
1651      * @return mixed
1652      * @access public
1653      * @see addComplexType
1654      * @see addSimpleType
1655      * @see addElement
1656      */
1657  	function getTypeDef($type){
1658          //$this->debug("in getTypeDef for type $type");
1659          if(isset($this->complexTypes[$type])){
1660              $this->xdebug("in getTypeDef, found complexType $type");
1661              return $this->complexTypes[$type];
1662          } elseif(isset($this->simpleTypes[$type])){
1663              $this->xdebug("in getTypeDef, found simpleType $type");
1664              if (!isset($this->simpleTypes[$type]['phpType'])) {
1665                  // get info for type to tack onto the simple type
1666                  // TODO: can this ever really apply (i.e. what is a simpleType really?)
1667                  $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1668                  $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
1669                  $etype = $this->getTypeDef($uqType);
1670                  if ($etype) {
1671                      $this->xdebug("in getTypeDef, found type for simpleType $type:");
1672                      $this->xdebug($this->varDump($etype));
1673                      if (isset($etype['phpType'])) {
1674                          $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1675                      }
1676                      if (isset($etype['elements'])) {
1677                          $this->simpleTypes[$type]['elements'] = $etype['elements'];
1678                      }
1679                  }
1680              }
1681              return $this->simpleTypes[$type];
1682          } elseif(isset($this->elements[$type])){
1683              $this->xdebug("in getTypeDef, found element $type");
1684              if (!isset($this->elements[$type]['phpType'])) {
1685                  // get info for type to tack onto the element
1686                  $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1687                  $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1688                  $etype = $this->getTypeDef($uqType);
1689                  if ($etype) {
1690                      $this->xdebug("in getTypeDef, found type for element $type:");
1691                      $this->xdebug($this->varDump($etype));
1692                      if (isset($etype['phpType'])) {
1693                          $this->elements[$type]['phpType'] = $etype['phpType'];
1694                      }
1695                      if (isset($etype['elements'])) {
1696                          $this->elements[$type]['elements'] = $etype['elements'];
1697                      }
1698                  } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
1699                      $this->xdebug("in getTypeDef, element $type is an XSD type");
1700                      $this->elements[$type]['phpType'] = 'scalar';
1701                  }
1702              }
1703              return $this->elements[$type];
1704          } elseif(isset($this->attributes[$type])){
1705              $this->xdebug("in getTypeDef, found attribute $type");
1706              return $this->attributes[$type];
1707          } elseif (ereg('_ContainedType$', $type)) {
1708              $this->xdebug("in getTypeDef, have an untyped element $type");
1709              $typeDef['typeClass'] = 'simpleType';
1710              $typeDef['phpType'] = 'scalar';
1711              $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
1712              return $typeDef;
1713          }
1714          $this->xdebug("in getTypeDef, did not find $type");
1715          return false;
1716      }
1717  
1718      /**
1719      * returns a sample serialization of a given type, or false if no type by the given name
1720      *
1721      * @param string $type, name of type
1722      * @return mixed
1723      * @access public
1724      * @deprecated
1725      */
1726      function serializeTypeDef($type){
1727          //print "in sTD() for type $type<br>";
1728      if($typeDef = $this->getTypeDef($type)){
1729          $str .= '<'.$type;
1730          if(is_array($typeDef['attrs'])){
1731          foreach($attrs as $attName => $data){
1732              $str .= " $attName=\"{type = ".$data['type']."}\"";
1733          }
1734          }
1735          $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
1736          if(count($typeDef['elements']) > 0){
1737          $str .= ">";
1738          foreach($typeDef['elements'] as $element => $eData){
1739              $str .= $this->serializeTypeDef($element);
1740          }
1741          $str .= "</$type>";
1742          } elseif($typeDef['typeClass'] == 'element') {
1743          $str .= "></$type>";
1744          } else {
1745          $str .= "/>";
1746          }
1747              return $str;
1748      }
1749          return false;
1750      }
1751  
1752      /**
1753      * returns HTML form elements that allow a user
1754      * to enter values for creating an instance of the given type.
1755      *
1756      * @param string $name, name for type instance
1757      * @param string $type, name of type
1758      * @return string
1759      * @access public
1760      * @deprecated
1761      */
1762  	function typeToForm($name,$type){
1763          // get typedef
1764          if($typeDef = $this->getTypeDef($type)){
1765              // if struct
1766              if($typeDef['phpType'] == 'struct'){
1767                  $buffer .= '<table>';
1768                  foreach($typeDef['elements'] as $child => $childDef){
1769                      $buffer .= "
1770                      <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
1771                      <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
1772                  }
1773                  $buffer .= '</table>';
1774              // if array
1775              } elseif($typeDef['phpType'] == 'array'){
1776                  $buffer .= '<table>';
1777                  for($i=0;$i < 3; $i++){
1778                      $buffer .= "
1779                      <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
1780                      <td><input type='text' name='parameters[".$name."][]'></td></tr>";
1781                  }
1782                  $buffer .= '</table>';
1783              // if scalar
1784              } else {
1785                  $buffer .= "<input type='text' name='parameters[$name]'>";
1786              }
1787          } else {
1788              $buffer .= "<input type='text' name='parameters[$name]'>";
1789          }
1790          return $buffer;
1791      }
1792      
1793      /**
1794      * adds a complex type to the schema
1795      * 
1796      * example: array
1797      * 
1798      * addType(
1799      *     'ArrayOfstring',
1800      *     'complexType',
1801      *     'array',
1802      *     '',
1803      *     'SOAP-ENC:Array',
1804      *     array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
1805      *     'xsd:string'
1806      * );
1807      * 
1808      * example: PHP associative array ( SOAP Struct )
1809      * 
1810      * addType(
1811      *     'SOAPStruct',
1812      *     'complexType',
1813      *     'struct',
1814      *     'all',
1815      *     array('myVar'=> array('name'=>'myVar','type'=>'string')
1816      * );
1817      * 
1818      * @param name
1819      * @param typeClass (complexType|simpleType|attribute)
1820      * @param phpType: currently supported are array and struct (php assoc array)
1821      * @param compositor (all|sequence|choice)
1822      * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1823      * @param elements = array ( name = array(name=>'',type=>'') )
1824      * @param attrs = array(
1825      *     array(
1826      *        'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
1827      *        "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
1828      *     )
1829      * )
1830      * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
1831      * @access public
1832      * @see getTypeDef
1833      */
1834  	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
1835          $this->complexTypes[$name] = array(
1836          'name'        => $name,
1837          'typeClass'    => $typeClass,
1838          'phpType'    => $phpType,
1839          'compositor'=> $compositor,
1840          'restrictionBase' => $restrictionBase,
1841          'elements'    => $elements,
1842          'attrs'        => $attrs,
1843          'arrayType'    => $arrayType
1844          );
1845          
1846          $this->xdebug("addComplexType $name:");
1847          $this->appendDebug($this->varDump($this->complexTypes[$name]));
1848      }
1849      
1850      /**
1851      * adds a simple type to the schema
1852      *
1853      * @param string $name
1854      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1855      * @param string $typeClass (should always be simpleType)
1856      * @param string $phpType (should always be scalar)
1857      * @param array $enumeration array of values
1858      * @access public
1859      * @see xmlschema
1860      * @see getTypeDef
1861      */
1862  	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1863          $this->simpleTypes[$name] = array(
1864          'name'            => $name,
1865          'typeClass'        => $typeClass,
1866          'phpType'        => $phpType,
1867          'type'            => $restrictionBase,
1868          'enumeration'    => $enumeration
1869          );
1870          
1871          $this->xdebug("addSimpleType $name:");
1872          $this->appendDebug($this->varDump($this->simpleTypes[$name]));
1873      }
1874  
1875      /**
1876      * adds an element to the schema
1877      *
1878      * @param array $attrs attributes that must include name and type
1879      * @see xmlschema
1880      * @access public
1881      */
1882  	function addElement($attrs) {
1883          if (! $this->getPrefix($attrs['type'])) {
1884              $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
1885          }
1886          $this->elements[ $attrs['name'] ] = $attrs;
1887          $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
1888          
1889          $this->xdebug("addElement " . $attrs['name']);
1890          $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
1891      }
1892  }
1893  
1894  
1895  
1896  ?><?php
1897  
1898  
1899  
1900  /**
1901  * For creating serializable abstractions of native PHP types.  This class
1902  * allows element name/namespace, XSD type, and XML attributes to be
1903  * associated with a value.  This is extremely useful when WSDL is not
1904  * used, but is also useful when WSDL is used with polymorphic types, including
1905  * xsd:anyType and user-defined types.
1906  *
1907  * @author   Dietrich Ayala <dietrich@ganx4.com>
1908  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
1909  * @access   public
1910  */
1911  class soapval extends nusoap_base {
1912      /**
1913       * The XML element name
1914       *
1915       * @var string
1916       * @access private
1917       */
1918      var $name;
1919      /**
1920       * The XML type name (string or false)
1921       *
1922       * @var mixed
1923       * @access private
1924       */
1925      var $type;
1926      /**
1927       * The PHP value
1928       *
1929       * @var mixed
1930       * @access private
1931       */
1932      var $value;
1933      /**
1934       * The XML element namespace (string or false)
1935       *
1936       * @var mixed
1937       * @access private
1938       */
1939      var $element_ns;
1940      /**
1941       * The XML type namespace (string or false)
1942       *
1943       * @var mixed
1944       * @access private
1945       */
1946      var $type_ns;
1947      /**
1948       * The XML element attributes (array or false)
1949       *
1950       * @var mixed
1951       * @access private
1952       */
1953      var $attributes;
1954  
1955      /**
1956      * constructor
1957      *
1958      * @param    string $name optional name
1959      * @param    mixed $type optional type name
1960      * @param    mixed $value optional value
1961      * @param    mixed $element_ns optional namespace of value
1962      * @param    mixed $type_ns optional namespace of type
1963      * @param    mixed $attributes associative array of attributes to add to element serialization
1964      * @access   public
1965      */
1966    	function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
1967          parent::nusoap_base();
1968          $this->name = $name;
1969          $this->type = $type;
1970          $this->value = $value;
1971          $this->element_ns = $element_ns;
1972          $this->type_ns = $type_ns;
1973          $this->attributes = $attributes;
1974      }
1975  
1976      /**
1977      * return serialized value
1978      *
1979      * @param    string $use The WSDL use value (encoded|literal)
1980      * @return    string XML data
1981      * @access   public
1982      */
1983  	function serialize($use='encoded') {
1984          return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
1985      }
1986  
1987      /**
1988      * decodes a soapval object into a PHP native type
1989      *
1990      * @return    mixed
1991      * @access   public
1992      */
1993  	function decode(){
1994          return $this->value;
1995      }
1996  }
1997  
1998  
1999  
2000  ?><?php
2001  
2002  
2003  
2004  /**
2005  * transport class for sending/receiving data via HTTP and HTTPS
2006  * NOTE: PHP must be compiled with the CURL extension for HTTPS support
2007  *
2008  * @author   Dietrich Ayala <dietrich@ganx4.com>
2009  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
2010  * @access public
2011  */
2012  class soap_transport_http extends nusoap_base {
2013  
2014      var $url = '';
2015      var $uri = '';
2016      var $digest_uri = '';
2017      var $scheme = '';
2018      var $host = '';
2019      var $port = '';
2020      var $path = '';
2021      var $request_method = 'POST';
2022      var $protocol_version = '1.0';
2023      var $encoding = '';
2024      var $outgoing_headers = array();
2025      var $incoming_headers = array();
2026      var $incoming_cookies = array();
2027      var $outgoing_payload = '';
2028      var $incoming_payload = '';
2029      var $useSOAPAction = true;
2030      var $persistentConnection = false;
2031      var $ch = false;    // cURL handle
2032      var $username = '';
2033      var $password = '';
2034      var $authtype = '';
2035      var $digestRequest = array();
2036      var $certRequest = array();    // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional)
2037                                  // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2038                                  // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2039                                  // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2040                                  // passphrase: SSL key password/passphrase
2041                                  // verifypeer: default is 1
2042                                  // verifyhost: default is 1
2043  
2044      /**
2045      * constructor
2046      */
2047  	function soap_transport_http($url){
2048          parent::nusoap_base();
2049          $this->setURL($url);
2050          ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
2051          $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
2052          $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']);
2053      }
2054  
2055  	function setURL($url) {
2056          $this->url = $url;
2057  
2058          $u = parse_url($url);
2059          foreach($u as $k => $v){
2060              $this->debug("$k = $v");
2061              $this->$k = $v;
2062          }
2063          
2064          // add any GET params to path
2065          if(isset($u['query']) && $u['query'] != ''){
2066              $this->path .= '?' . $u['query'];
2067          }
2068          
2069          // set default port
2070          if(!isset($u['port'])){
2071              if($u['scheme'] == 'https'){
2072                  $this->port = 443;
2073              } else {
2074                  $this->port = 80;
2075              }
2076          }
2077          
2078          $this->uri = $this->path;
2079          $this->digest_uri = $this->uri;
2080          
2081          // build headers
2082          if (!isset($u['port'])) {
2083              $this->outgoing_headers['Host'] = $this->host;
2084          } else {
2085              $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
2086          }
2087          $this->debug('set Host: ' . $this->outgoing_headers['Host']);
2088  
2089          if (isset($u['user']) && $u['user'] != '') {
2090              $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2091          }
2092      }
2093      
2094  	function connect($connection_timeout=0,$response_timeout=30){
2095            // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2096            // "regular" socket.
2097            // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2098            //       loaded), and until PHP5 stream_get_wrappers is not available.
2099  //          if ($this->scheme == 'https') {
2100  //              if (version_compare(phpversion(), '4.3.0') >= 0) {
2101  //                  if (extension_loaded('openssl')) {
2102  //                      $this->scheme = 'ssl';
2103  //                      $this->debug('Using SSL over OpenSSL');
2104  //                  }
2105  //              }
2106  //        }
2107          $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2108        if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2109          // use persistent connection
2110          if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
2111              if (!feof($this->fp)) {
2112                  $this->debug('Re-use persistent connection');
2113                  return true;
2114              }
2115              fclose($this->fp);
2116              $this->debug('Closed persistent connection at EOF');
2117          }
2118  
2119          // munge host if using OpenSSL
2120          if ($this->scheme == 'ssl') {
2121              $host = 'ssl://' . $this->host;
2122          } else {
2123              $host = $this->host;
2124          }
2125          $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2126  
2127          // open socket
2128          if($connection_timeout > 0){
2129              $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
2130          } else {
2131              $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
2132          }
2133          
2134          // test pointer
2135          if(!$this->fp) {
2136              $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2137              if ($this->errno) {
2138                  $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
2139              } else {
2140                  $msg .= ' prior to connect().  This is often a problem looking up the host name.';
2141              }
2142              $this->debug($msg);
2143              $this->setError($msg);
2144              return false;
2145          }
2146          
2147          // set response timeout
2148          $this->debug('set response timeout to ' . $response_timeout);
2149          socket_set_timeout( $this->fp, $response_timeout);
2150  
2151          $this->debug('socket connected');
2152          return true;
2153        } else if ($this->scheme == 'https') {
2154          if (!extension_loaded('curl')) {
2155              $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
2156              return false;
2157          }
2158          $this->debug('connect using https');
2159          // init CURL
2160          $this->ch = curl_init();
2161          // set url
2162          $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
2163          // add path
2164          $hostURL .= $this->path;
2165          curl_setopt($this->ch, CURLOPT_URL, $hostURL);
2166          // follow location headers (re-directs)
2167          curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1);
2168          // ask for headers in the response output
2169          curl_setopt($this->ch, CURLOPT_HEADER, 1);
2170          // ask for the response output as the return value
2171          curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
2172          // encode
2173          // We manage this ourselves through headers and encoding
2174  //        if(function_exists('gzuncompress')){
2175  //            curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
2176  //        }
2177          // persistent connection
2178          if ($this->persistentConnection) {
2179              // The way we send data, we cannot use persistent connections, since
2180              // there will be some "junk" at the end of our request.
2181              //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
2182              $this->persistentConnection = false;
2183              $this->outgoing_headers['Connection'] = 'close';
2184              $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
2185          }
2186          // set timeout
2187          if ($connection_timeout != 0) {
2188              curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
2189          }
2190          // TODO: cURL has added a connection timeout separate from the response timeout
2191          //if ($connection_timeout != 0) {
2192          //    curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2193          //}
2194          //if ($response_timeout != 0) {
2195          //    curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_timeout);
2196          //}
2197  
2198          // recent versions of cURL turn on peer/host checking by default,
2199          // while PHP binaries are not compiled with a default location for the
2200          // CA cert bundle, so disable peer/host checking.
2201  //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');        
2202          curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
2203          curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
2204  
2205          // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2206          if ($this->authtype == 'certificate') {
2207              if (isset($this->certRequest['cainfofile'])) {
2208                  curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2209              }
2210              if (isset($this->certRequest['verifypeer'])) {
2211                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2212              } else {
2213                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
2214              }
2215              if (isset($this->certRequest['verifyhost'])) {
2216                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2217              } else {
2218                  curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
2219              }
2220              if (isset($this->certRequest['sslcertfile'])) {
2221                  curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2222              }
2223              if (isset($this->certRequest['sslkeyfile'])) {
2224                  curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2225              }
2226              if (isset($this->certRequest['passphrase'])) {
2227                  curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']);
2228              }
2229          }
2230          $this->debug('cURL connection set up');
2231          return true;
2232        } else {
2233          $this->setError('Unknown scheme ' . $this->scheme);
2234          $this->debug('Unknown scheme ' . $this->scheme);
2235          return false;
2236        }
2237      }
2238      
2239      /**
2240      * send the SOAP message via HTTP
2241      *
2242      * @param    string $data message data
2243      * @param    integer $timeout set connection timeout in seconds
2244      * @param    integer $response_timeout set response timeout in seconds
2245      * @param    array $cookies cookies to send
2246      * @return    string data
2247      * @access   public
2248      */
2249  	function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
2250          
2251          $this->debug('entered send() with data of length: '.strlen($data));
2252  
2253          $this->tryagain = true;
2254          $tries = 0;
2255          while ($this->tryagain) {
2256              $this->tryagain = false;
2257              if ($tries++ < 2) {
2258                  // make connnection
2259                  if (!$this->connect($timeout, $response_timeout)){
2260                      return false;
2261                  }
2262                  
2263                  // send request
2264                  if (!$this->sendRequest($data, $cookies)){
2265                      return false;
2266                  }
2267                  
2268                  // get response
2269                  $respdata = $this->getResponse();
2270              } else {
2271                  $this->setError('Too many tries to get an OK response');
2272              }
2273          }        
2274          $this->debug('end of send()');
2275          return $respdata;
2276      }
2277  
2278  
2279      /**
2280      * send the SOAP message via HTTPS 1.0 using CURL
2281      *
2282      * @param    string $msg message data
2283      * @param    integer $timeout set connection timeout in seconds
2284      * @param    integer $response_timeout set response timeout in seconds
2285      * @param    array $cookies cookies to send
2286      * @return    string data
2287      * @access   public
2288      */
2289  	function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
2290          return $this->send($data, $timeout, $response_timeout, $cookies);
2291      }
2292      
2293      /**
2294      * if authenticating, set user credentials here
2295      *
2296      * @param    string $username
2297      * @param    string $password
2298      * @param    string $authtype (basic, digest, certificate)
2299      * @param    array $digestRequest (keys must be nonce, nc, realm, qop)
2300      * @param    array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
2301      * @access   public
2302      */
2303  	function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
2304          $this->debug("Set credentials for authtype $authtype");
2305          // cf. RFC 2617
2306          if ($authtype == 'basic') {
2307              $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$username).':'.$password);
2308          } elseif ($authtype == 'digest') {
2309              if (isset($digestRequest['nonce'])) {
2310                  $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2311                  
2312                  // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2313      
2314                  // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2315                  $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2316      
2317                  // H(A1) = MD5(A1)
2318                  $HA1 = md5($A1);
2319      
2320                  // A2 = Method ":" digest-uri-value
2321                  $A2 = 'POST:' . $this->digest_uri;
2322      
2323                  // H(A2)
2324                  $HA2 =  md5($A2);
2325      
2326                  // KD(secret, data) = H(concat(secret, ":", data))
2327                  // if qop == auth:
2328                  // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
2329                  //                              ":" nc-value
2330                  //                              ":" unq(cnonce-value)
2331                  //                              ":" unq(qop-value)
2332                  //                              ":" H(A2)
2333                  //                            ) <">
2334                  // if qop is missing,
2335                  // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2336      
2337                  $unhashedDigest = '';
2338                  $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2339                  $cnonce = $nonce;
2340                  if ($digestRequest['qop'] != '') {
2341                      $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2342                  } else {
2343                      $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2344                  }
2345      
2346                  $hashedDigest = md5($unhashedDigest);
2347      
2348                  $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 . '"';
2349              }
2350          } elseif ($authtype == 'certificate') {
2351              $this->certRequest = $certRequest;
2352          }
2353          $this->username = $username;
2354          $this->password = $password;
2355          $this->authtype = $authtype;
2356          $this->digestRequest = $digestRequest;
2357          
2358          if (isset($this->outgoing_headers['Authorization'])) {
2359              $this->debug('set Authorization: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
2360          } else {
2361              $this->debug('Authorization header not set');
2362          }
2363      }
2364      
2365      /**
2366      * set the soapaction value
2367      *
2368      * @param    string $soapaction
2369      * @access   public
2370      */
2371  	function setSOAPAction($soapaction) {
2372          $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
2373          $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']);
2374      }
2375      
2376      /**
2377      * use http encoding
2378      *
2379      * @param    string $enc encoding style. supported values: gzip, deflate, or both
2380      * @access   public
2381      */
2382  	function setEncoding($enc='gzip, deflate') {
2383          if (function_exists('gzdeflate')) {
2384              $this->protocol_version = '1.1';
2385              $this->outgoing_headers['Accept-Encoding'] = $enc;
2386              $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']);
2387              if (!isset($this->outgoing_headers['Connection'])) {
2388                  $this->outgoing_headers['Connection'] = 'close';
2389                  $this->persistentConnection = false;
2390                  $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
2391              }
2392              set_magic_quotes_runtime(0);
2393              // deprecated
2394              $this->encoding = $enc;
2395          }
2396      }
2397      
2398      /**
2399      * set proxy info here
2400      *
2401      * @param    string $proxyhost
2402      * @param    string $proxyport
2403      * @param    string $proxyusername
2404      * @param    string $proxypassword
2405      * @access   public
2406      */
2407  	function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
2408          $this->uri = $this->url;
2409          $this->host = $proxyhost;
2410          $this->port = $proxyport;
2411          if ($proxyusername != '' && $proxypassword != '') {
2412              $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
2413              $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']);
2414          }
2415      }
2416      
2417      /**
2418      * decode a string that is encoded w/ "chunked' transfer encoding
2419       * as defined in RFC2068 19.4.6
2420      *
2421      * @param    string $buffer
2422      * @param    string $lb
2423      * @returns    string
2424      * @access   public
2425      * @deprecated
2426      */
2427  	function decodeChunked($buffer, $lb){
2428          // length := 0
2429          $length = 0;
2430          $new = '';
2431          
2432          // read chunk-size, chunk-extension (if any) and CRLF
2433          // get the position of the linebreak
2434          $chunkend = strpos($buffer, $lb);
2435          if ($chunkend == FALSE) {
2436              $this->debug('no linebreak found in decodeChunked');
2437              return $new;
2438          }
2439          $temp = substr($buffer,0,$chunkend);
2440          $chunk_size = hexdec( trim($temp) );
2441          $chunkstart = $chunkend + strlen($lb);
2442          // while (chunk-size > 0) {
2443          while ($chunk_size > 0) {
2444              $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
2445              $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
2446                
2447              // Just in case we got a broken connection
2448                if ($chunkend == FALSE) {
2449                    $chunk = substr($buffer,$chunkstart);
2450                  // append chunk-data to entity-body
2451                  $new .= $chunk;
2452                    $length += strlen($chunk);
2453                    break;
2454              }
2455              
2456                // read chunk-data and CRLF
2457                $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2458                // append chunk-data to entity-body
2459                $new .= $chunk;
2460                // length := length + chunk-size
2461                $length += strlen($chunk);
2462                // read chunk-size and CRLF
2463                $chunkstart = $chunkend + strlen($lb);
2464              
2465                $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
2466              if ($chunkend == FALSE) {
2467                  break; //Just in case we got a broken connection
2468              }
2469              $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
2470              $chunk_size = hexdec( trim($temp) );
2471              $chunkstart = $chunkend;
2472          }
2473          return $new;
2474      }
2475      
2476      /*
2477       *    Writes payload, including HTTP headers, to $this->outgoing_payload.
2478       */
2479  	function buildPayload($data, $cookie_str = '') {
2480          // add content-length header
2481          $this->outgoing_headers['Content-Length'] = strlen($data);
2482          $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']);
2483  
2484          // start building outgoing payload:
2485          $req = "$this->request_method $this->uri HTTP/$this->protocol_version";
2486          $this->debug("HTTP request: $req");
2487          $this->outgoing_payload = "$req\r\n";
2488  
2489          // loop thru headers, serializing
2490          foreach($this->outgoing_headers as $k => $v){
2491              $hdr = $k.': '.$v;
2492              $this->debug("HTTP header: $hdr");
2493              $this->outgoing_payload .= "$hdr\r\n";
2494          }
2495  
2496          // add any cookies
2497          if ($cookie_str != '') {
2498              $hdr = 'Cookie: '.$cookie_str;
2499              $this->debug("HTTP header: $hdr");
2500              $this->outgoing_payload .= "$hdr\r\n";
2501          }
2502  
2503          // header/body separator
2504          $this->outgoing_payload .= "\r\n";
2505          
2506          // add data
2507          $this->outgoing_payload .= $data;
2508      }
2509  
2510  	function sendRequest($data, $cookies = NULL) {
2511          // build cookie string
2512          $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
2513  
2514          // build payload
2515          $this->buildPayload($data, $cookie_str);
2516  
2517        if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2518          // send payload
2519          if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
2520              $this->setError('couldn\'t write message data to socket');
2521              $this->debug('couldn\'t write message data to socket');
2522              return false;
2523          }
2524          $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
2525          return true;
2526        } else if ($this->scheme == 'https') {
2527          // set payload
2528          // TODO: cURL does say this should only be the verb, and in fact it
2529          // turns out that the URI and HTTP version are appended to this, which
2530          // some servers refuse to work with
2531          //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
2532          foreach($this->outgoing_headers as $k => $v){
2533              $curl_headers[] = "$k: $v";
2534          }
2535          if ($cookie_str != '') {
2536              $curl_headers[] = 'Cookie: ' . $cookie_str;
2537          }
2538          curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
2539          if ($this->request_method == "POST") {
2540                curl_setopt($this->ch, CURLOPT_POST, 1);
2541                curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
2542            } else {
2543            }
2544          $this->debug('set cURL payload');
2545          return true;
2546        }
2547      }
2548  
2549  	function getResponse(){
2550          $this->incoming_payload = '';
2551          
2552        if ($this->scheme == 'http' || $this->scheme == 'ssl') {
2553          // loop until headers have been retrieved
2554          $data = '';
2555          while (!isset($lb)){
2556  
2557              // We might EOF during header read.
2558              if(feof($this->fp)) {
2559                  $this->incoming_payload = $data;
2560                  $this->debug('found no headers before EOF after length ' . strlen($data));
2561                  $this->debug("received before EOF:\n" . $data);
2562                  $this->setError('server failed to send headers');
2563                  return false;
2564              }
2565  
2566              $tmp = fgets($this->fp, 256);
2567              $tmplen = strlen($tmp);
2568              $this->debug("read line of $tmplen bytes: " . trim($tmp));
2569  
2570              if ($tmplen == 0) {
2571                  $this->incoming_payload = $data;
2572                  $this->debug('socket read of headers timed out after length ' . strlen($data));
2573                  $this->debug("read before timeout: " . $data);
2574                  $this->setError('socket read of headers timed out');
2575                  return false;
2576              }
2577  
2578              $data .= $tmp;
2579              $pos = strpos($data,"\r\n\r\n");
2580              if($pos > 1){
2581                  $lb = "\r\n";
2582              } else {
2583                  $pos = strpos($data,"\n\n");
2584                  if($pos > 1){
2585                      $lb = "\n";
2586                  }
2587              }
2588              // remove 100 header
2589              if(isset($lb) && ereg('^HTTP/1.1 100',$data)){
2590                  unset($lb);
2591                  $data = '';
2592              }//
2593          }
2594          // store header data
2595          $this->incoming_payload .= $data;
2596          $this->debug('found end of headers after length ' . strlen($data));
2597          // process headers
2598          $header_data = trim(substr($data,0,$pos));
2599          $header_array = explode($lb,$header_data);
2600          $this->incoming_headers = array();
2601          $this->incoming_cookies = array();
2602          foreach($header_array as $header_line){
2603              $arr = explode(':',$header_line, 2);
2604              if(count($arr) > 1){
2605                  $header_name = strtolower(trim($arr[0]));
2606                  $this->incoming_headers[$header_name] = trim($arr[1]);
2607                  if ($header_name == 'set-cookie') {
2608                      // TODO: allow multiple cookies from parseCookie
2609                      $cookie = $this->parseCookie(trim($arr[1]));
2610                      if ($cookie) {
2611                          $this->incoming_cookies[] = $cookie;
2612                          $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2613                      } else {
2614                          $this->debug('did not find cookie in ' . trim($arr[1]));
2615                      }
2616                  }
2617              } else if (isset($header_name)) {
2618                  // append continuation line to previous header
2619                  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2620              }
2621          }
2622          
2623          // loop until msg has been received
2624          if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
2625              $content_length =  2147483647;    // ignore any content-length header
2626              $chunked = true;
2627              $this->debug("want to read chunked content");
2628          } elseif (isset($this->incoming_headers['content-length'])) {
2629              $content_length = $this->incoming_headers['content-length'];
2630              $chunked = false;
2631              $this->debug("want to read content of length $content_length");
2632          } else {
2633              $content_length =  2147483647;
2634              $chunked = false;
2635              $this->debug("want to read content to EOF");
2636          }
2637          $data = '';
2638          do {
2639              if ($chunked) {
2640                  $tmp = fgets($this->fp, 256);
2641                  $tmplen = strlen($tmp);
2642                  $this->debug("read chunk line of $tmplen bytes");
2643                  if ($tmplen == 0) {
2644                      $this->incoming_payload = $data;
2645                      $this->debug('socket read of chunk length timed out after length ' . strlen($data));
2646                      $this->debug("read before timeout:\n" . $data);
2647                      $this->setError('socket read of chunk length timed out');
2648                      return false;
2649                  }
2650                  $content_length = hexdec(trim($tmp));
2651                  $this->debug("chunk length $content_length");
2652              }
2653              $strlen = 0;
2654              while (($strlen < $content_length) && (!feof($this->fp))) {
2655                  $readlen = min(8192, $content_length - $strlen);
2656                  $tmp = fread($this->fp, $readlen);
2657                  $tmplen = strlen($tmp);
2658                  $this->debug("read buffer of $tmplen bytes");
2659                  if (($tmplen == 0) && (!feof($this->fp))) {
2660                      $this->incoming_payload = $data;
2661                      $this->debug('socket read of body timed out after length ' . strlen($data));
2662                      $this->debug("read before timeout:\n" . $data);
2663                      $this->setError('socket read of body timed out');
2664                      return false;
2665                  }
2666                  $strlen += $tmplen;
2667                  $data .= $tmp;
2668              }
2669              if ($chunked && ($content_length > 0)) {
2670                  $tmp = fgets($this->fp, 256);
2671                  $tmplen = strlen($tmp);
2672                  $this->debug("read chunk terminator of $tmplen bytes");
2673                  if ($tmplen == 0) {
2674                      $this->incoming_payload = $data;
2675                      $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
2676                      $this->debug("read before timeout:\n" . $data);
2677                      $this->setError('socket read of chunk terminator timed out');
2678                      return false;
2679                  }
2680              }
2681          } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
2682          if (feof($this->fp)) {
2683              $this->debug('read to EOF');
2684          }
2685          $this->debug('read body of length ' . strlen($data));
2686          $this->incoming_payload .= $data;
2687          $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
2688          
2689          // close filepointer
2690          if(
2691              (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 
2692              (! $this->persistentConnection) || feof($this->fp)){
2693              fclose($this->fp);
2694              $this->fp = false;
2695              $this->debug('closed socket');
2696          }
2697          
2698          // connection was closed unexpectedly
2699          if($this->incoming_payload == ''){
2700              $this->setError('no response from server');
2701              return false;
2702          }
2703          
2704          // decode transfer-encoding
2705  //        if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
2706  //            if(!$data = $this->decodeChunked($data, $lb)){
2707  //                $this->setError('Decoding of chunked data failed');
2708  //                return false;
2709  //            }
2710              //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
2711              // set decoded payload
2712  //            $this->incoming_payload = $header_data.$lb.$lb.$data;
2713  //        }
2714      
2715        } else if ($this->scheme == 'https') {
2716          // send and receive
2717          $this->debug('send and receive with cURL');
2718          $this->incoming_payload = curl_exec($this->ch);
2719          $data = $this->incoming_payload;
2720  
2721          $cErr = curl_error($this->ch);
2722          if ($cErr != '') {
2723              $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
2724              // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
2725              foreach(curl_getinfo($this->ch) as $k => $v){
2726                  $err .= "$k: $v<br>";
2727              }
2728              $this->debug($err);
2729              $this->setError($err);
2730              curl_close($this->ch);
2731              return false;
2732          } else {
2733              //echo '<pre>';
2734              //var_dump(curl_getinfo($this->ch));
2735              //echo '</pre>';
2736          }
2737          // close curl
2738          $this->debug('No cURL error, closing cURL');
2739          curl_close($this->ch);
2740          
2741          // remove 100 header(s)
2742          while (ereg('^HTTP/1.1 100',$data)) {
2743              if ($pos = strpos($data,"\r\n\r\n")) {
2744                  $data = ltrim(substr($data,$pos));
2745              } elseif($pos = strpos($data,"\n\n") ) {
2746                  $data = ltrim(substr($data,$pos));
2747              }
2748          }
2749          
2750          // separate content from HTTP headers
2751          if ($pos = strpos($data,"\r\n\r\n")) {
2752              $lb = "\r\n";
2753          } elseif( $pos = strpos($data,"\n\n")) {
2754              $lb = "\n";
2755          } else {
2756              $this->debug('no proper separation of headers and document');
2757              $this->setError('no proper separation of headers and document');
2758              return false;
2759          }
2760          $header_data = trim(substr($data,0,$pos));
2761          $header_array = explode($lb,$header_data);
2762          $data = ltrim(substr($data,$pos));
2763          $this->debug('found proper separation of headers and document');
2764          $this->debug('cleaned data, stringlen: '.strlen($data));
2765          // clean headers
2766          foreach ($header_array as $header_line) {
2767              $arr = explode(':',$header_line,2);
2768              if(count($arr) > 1){
2769                  $header_name = strtolower(trim($arr[0]));
2770                  $this->incoming_headers[$header_name] = trim($arr[1]);
2771                  if ($header_name == 'set-cookie') {
2772                      // TODO: allow multiple cookies from parseCookie
2773                      $cookie = $this->parseCookie(trim($arr[1]));
2774                      if ($cookie) {
2775                          $this->incoming_cookies[] = $cookie;
2776                          $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
2777                      } else {
2778                          $this->debug('did not find cookie in ' . trim($arr[1]));
2779                      }
2780                  }
2781              } else if (isset($header_name)) {
2782                  // append continuation line to previous header
2783                  $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
2784              }
2785          }
2786        }
2787  
2788          $arr = explode(' ', $header_array[0], 3);
2789          $http_version = $arr[0];
2790          $http_status = intval($arr[1]);
2791          $http_reason = count($arr) > 2 ? $arr[2] : '';
2792  
2793           // see if we need to resend the request with http digest authentication
2794           if (isset($this->incoming_headers['location']) && $http_status == 301) {
2795               $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']);
2796               $this->setURL($this->incoming_headers['location']);
2797              $this->tryagain = true;
2798              return false;
2799          }
2800  
2801           // see if we need to resend the request with http digest authentication
2802           if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
2803               $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
2804               if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
2805                   $this->debug('Server wants digest authentication');
2806                   // remove "Digest " from our elements
2807                   $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
2808                   
2809                   // parse elements into array
2810                   $digestElements = explode(',', $digestString);
2811                   foreach ($digestElements as $val) {
2812                       $tempElement = explode('=', trim($val), 2);
2813                       $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
2814                   }
2815  
2816                  // should have (at least) qop, realm, nonce
2817                   if (isset($digestRequest['nonce'])) {
2818                       $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
2819                       $this->tryagain = true;
2820                       return false;
2821                   }
2822               }
2823              $this->debug('HTTP authentication failed');
2824              $this->setError('HTTP authentication failed');
2825              return false;
2826           }
2827          
2828          if (
2829              ($http_status >= 300 && $http_status <= 307) ||
2830              ($http_status >= 400 && $http_status <= 417) ||
2831              ($http_status >= 501 && $http_status <= 505)
2832             ) {
2833              $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient2->response has contents of the response)");
2834              return false;
2835          }
2836  
2837          // decode content-encoding
2838          if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
2839              if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
2840                  // if decoding works, use it. else assume data wasn't gzencoded
2841                  if(function_exists('gzinflate')){
2842                      //$timer->setMarker('starting decoding of gzip/deflated content');
2843                      // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
2844                      // this means there are no Zlib headers, although there should be
2845                      $this->debug('The gzinflate function exists');
2846                      $datalen = strlen($data);
2847                      if ($this->incoming_headers['content-encoding'] == 'deflate') {
2848                          if ($degzdata = @gzinflate($data)) {
2849                              $data = $degzdata;
2850                              $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
2851                              if (strlen($data) < $datalen) {
2852                                  // test for the case that the payload has been compressed twice
2853                                  $this->debug('The inflated payload is smaller than the gzipped one; try again');
2854                                  if ($degzdata = @gzinflate($data)) {
2855                                      $data = $degzdata;
2856                                      $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
2857                                  }
2858                              }
2859                          } else {
2860                              $this->debug('Error using gzinflate to inflate the payload');
2861                              $this->setError('Error using gzinflate to inflate the payload');
2862                          }
2863                      } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
2864                          if ($degzdata = @gzinflate(substr($data, 10))) {    // do our best
2865                              $data = $degzdata;
2866                              $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
2867                              if (strlen($data) < $datalen) {
2868                                  // test for the case that the payload has been compressed twice
2869                                  $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
2870                                  if ($degzdata = @gzinflate(substr($data, 10))) {
2871                                      $data = $degzdata;
2872                                      $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
2873                                  }
2874                              }
2875                          } else {
2876                              $this->debug('Error using gzinflate to un-gzip the payload');
2877                              $this->setError('Error using gzinflate to un-gzip the payload');
2878                          }
2879                      }
2880                      //$timer->setMarker('finished decoding of gzip/deflated content');
2881                      //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
2882                      // set decoded payload
2883                      $this->incoming_payload = $header_data.$lb.$lb.$data;
2884                  } else {
2885                      $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
2886                      $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
2887                  }
2888              } else {
2889                  $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
2890                  $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
2891              }
2892          } else {
2893              $this->debug('No Content-Encoding header');
2894          }
2895          
2896          if(strlen($data) == 0){
2897              $this->debug('no data after headers!');
2898              $this->setError('no data present after HTTP headers');
2899              return false;
2900          }
2901          
2902          return $data;
2903      }
2904  
2905  	function setContentType($type, $charset = false) {
2906          $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
2907          $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']);
2908      }
2909  
2910  	function usePersistentConnection(){
2911          if (isset($this->outgoing_headers['Accept-Encoding'])) {
2912              return false;
2913          }
2914          $this->protocol_version = '1.1';
2915          $this->persistentConnection = true;
2916          $this->outgoing_headers['Connection'] = 'Keep-Alive';
2917          $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
2918          return true;
2919      }
2920  
2921      /**
2922       * parse an incoming Cookie into it's parts
2923       *
2924       * @param    string $cookie_str content of cookie
2925       * @return    array with data of that cookie
2926       * @access    private
2927       */
2928      /*
2929       * TODO: allow a Set-Cookie string to be parsed into multiple cookies
2930       */
2931  	function parseCookie($cookie_str) {
2932          $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
2933          $data = split(';', $cookie_str);
2934          $value_str = $data[0];
2935  
2936          $cookie_param = 'domain=';
2937          $start = strpos($cookie_str, $cookie_param);
2938          if ($start > 0) {
2939              $domain = substr($cookie_str, $start + strlen($cookie_param));
2940              $domain = substr($domain, 0, strpos($domain, ';'));
2941          } else {
2942              $domain = '';
2943          }
2944  
2945          $cookie_param = 'expires=';
2946          $start = strpos($cookie_str, $cookie_param);
2947          if ($start > 0) {
2948              $expires = substr($cookie_str, $start + strlen($cookie_param));
2949              $expires = substr($expires, 0, strpos($expires, ';'));
2950          } else {
2951              $expires = '';
2952          }
2953  
2954          $cookie_param = 'path=';
2955          $start = strpos($cookie_str, $cookie_param);
2956          if ( $start > 0 ) {
2957              $path = substr($cookie_str, $start + strlen($cookie_param));
2958              $path = substr($path, 0, strpos($path, ';'));
2959          } else {
2960              $path = '/';
2961          }
2962                          
2963          $cookie_param = ';secure;';
2964          if (strpos($cookie_str, $cookie_param) !== FALSE) {
2965              $secure = true;
2966          } else {
2967              $secure = false;
2968          }
2969  
2970          $sep_pos = strpos($value_str, '=');
2971  
2972          if ($sep_pos) {
2973              $name = substr($value_str, 0, $sep_pos);
2974              $value = substr($value_str, $sep_pos + 1);
2975              $cookie= array(    'name' => $name,
2976                              'value' => $value,
2977                              'domain' => $domain,
2978                              'path' => $path,
2979                              'expires' => $expires,
2980                              'secure' => $secure
2981                              );        
2982              return $cookie;
2983          }
2984          return false;
2985      }
2986    
2987      /**
2988       * sort out cookies for the current request
2989       *
2990       * @param    array $cookies array with all cookies
2991       * @param    boolean $secure is the send-content secure or not?
2992       * @return    string for Cookie-HTTP-Header
2993       * @access    private
2994       */
2995  	function getCookiesForRequest($cookies, $secure=false) {
2996          $cookie_str = '';
2997          if ((! is_null($cookies)) && (is_array($cookies))) {
2998              foreach ($cookies as $cookie) {
2999                  if (! is_array($cookie)) {
3000                      continue;
3001                  }
3002                  $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
3003                  if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
3004                      if (strtotime($cookie['expires']) <= time()) {
3005                          $this->debug('cookie has expired');
3006                          continue;
3007                      }
3008                  }
3009                  if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
3010                      $domain = preg_quote($cookie['domain']);
3011                      if (! preg_match("'.*$domain$'i", $this->host)) {
3012                          $this->debug('cookie has different domain');
3013                          continue;
3014                      }
3015                  }
3016                  if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
3017                      $path = preg_quote($cookie['path']);
3018                      if (! preg_match("'^$path.*'i", $this->path)) {
3019                          $this->debug('cookie is for a different path');
3020                          continue;
3021                      }
3022                  }
3023                  if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
3024                      $this->debug('cookie is secure, transport is not');
3025                      continue;
3026                  }
3027                  $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3028                  $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3029              }
3030          }
3031          return $cookie_str;
3032    }
3033  }
3034  
3035  ?><?php
3036  
3037  
3038  
3039  /**
3040  *
3041  * soap_server allows the user to create a SOAP server
3042  * that is capable of receiving messages and returning responses
3043  *
3044  * NOTE: WSDL functionality is experimental
3045  *
3046  * @author   Dietrich Ayala <dietrich@ganx4.com>
3047  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
3048  * @access   public
3049  */
3050  class soap_server extends nusoap_base {
3051      /**
3052       * HTTP headers of request
3053       * @var array
3054       * @access private
3055       */
3056      var $headers = array();
3057      /**
3058       * HTTP request
3059       * @var string
3060       * @access private
3061       */
3062      var $request = '';
3063      /**
3064       * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
3065       * @var string
3066       * @access public
3067       */
3068      var $requestHeaders = '';
3069      /**
3070       * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
3071       * @var string
3072       * @access public
3073       */
3074      var $document = '';
3075      /**
3076       * SOAP payload for request (text)
3077       * @var string
3078       * @access public
3079       */
3080      var $requestSOAP = '';
3081      /**
3082       * requested method namespace URI
3083       * @var string
3084       * @access private
3085       */
3086      var $methodURI = '';
3087      /**
3088       * name of method requested
3089       * @var string
3090       * @access private
3091       */
3092      var $methodname = '';
3093      /**
3094       * method parameters from request
3095       * @var array
3096       * @access private
3097       */
3098      var $methodparams = array();
3099      /**
3100       * SOAP Action from request
3101       * @var string
3102       * @access private
3103       */
3104      var $SOAPAction = '';
3105      /**
3106       * character set encoding of incoming (request) messages
3107       * @var string
3108       * @access public
3109       */
3110      var $xml_encoding = '';
3111      /**
3112       * toggles whether the parser decodes element content w/ utf8_decode()
3113       * @var boolean
3114       * @access public
3115       */
3116      var $decode_utf8 = true;
3117  
3118      /**
3119       * HTTP headers of response
3120       * @var array
3121       * @access public
3122       */
3123      var $outgoing_headers = array();
3124      /**
3125       * HTTP response
3126       * @var string
3127       * @access private
3128       */
3129      var $response = '';
3130      /**
3131       * SOAP headers for response (text)
3132       * @var string
3133       * @access public
3134       */
3135      var $responseHeaders = '';
3136      /**
3137       * SOAP payload for response (text)
3138       * @var string
3139       * @access private
3140       */
3141      var $responseSOAP = '';
3142      /**
3143       * method return value to place in response
3144       * @var mixed
3145       * @access private
3146       */
3147      var $methodreturn = false;
3148      /**
3149       * whether $methodreturn is a string of literal XML
3150       * @var boolean
3151       * @access public
3152       */
3153      var $methodreturnisliteralxml = false;
3154      /**
3155       * SOAP fault for response (or false)
3156       * @var mixed
3157       * @access private
3158       */
3159      var $fault = false;
3160      /**
3161       * text indication of result (for debugging)
3162       * @var string
3163       * @access private
3164       */
3165      var $result = 'successful';
3166  
3167      /**
3168       * assoc array of operations => opData; operations are added by the register()
3169       * method or by parsing an external WSDL definition
3170       * @var array
3171       * @access private
3172       */
3173      var $operations = array();
3174      /**
3175       * wsdl instance (if one)
3176       * @var mixed
3177       * @access private
3178       */
3179      var $wsdl = false;
3180      /**
3181       * URL for WSDL (if one)
3182       * @var mixed
3183       * @access private
3184       */
3185      var $externalWSDLURL = false;
3186      /**
3187       * whether to append debug to response as XML comment
3188       * @var boolean
3189       * @access public
3190       */
3191      var $debug_flag = false;
3192  
3193  
3194      /**
3195      * constructor
3196      * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
3197      *
3198      * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
3199      * @access   public
3200      */
3201  	function soap_server($wsdl=false){
3202          parent::nusoap_base();
3203          // turn on debugging?
3204          global $debug;
3205          global $HTTP_SERVER_VARS;
3206  
3207          if (isset($_SERVER)) {
3208              $this->debug("_SERVER is defined:");
3209              $this->appendDebug($this->varDump($_SERVER));
3210          } elseif (isset($HTTP_SERVER_VARS)) {
3211              $this->debug("HTTP_SERVER_VARS is defined:");
3212              $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3213          } else {
3214              $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
3215          }
3216  
3217          if (isset($debug)) {
3218              $this->debug("In soap_server, set debug_flag=$debug based on global flag");
3219              $this->debug_flag = $debug;
3220          } elseif (isset($_SERVER['QUERY_STRING'])) {
3221              $qs = explode('&', $_SERVER['QUERY_STRING']);
3222              foreach ($qs as $v) {
3223                  if (substr($v, 0, 6) == 'debug=') {
3224                      $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
3225                      $this->debug_flag = substr($v, 6);
3226                  }
3227              }
3228          } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3229              $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3230              foreach ($qs as $v) {
3231                  if (substr($v, 0, 6) == 'debug=') {
3232                      $this->debug("In soap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
3233                      $this->debug_flag = substr($v, 6);
3234                  }
3235              }
3236          }
3237  
3238          // wsdl
3239          if($wsdl){
3240              $this->debug("In soap_server, WSDL is specified");
3241              if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
3242                  $this->wsdl = $wsdl;
3243                  $this->externalWSDLURL = $this->wsdl->wsdl;
3244                  $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3245              } else {
3246                  $this->debug('Create wsdl from ' . $wsdl);
3247                  $this->wsdl = new wsdl($wsdl);
3248                  $this->externalWSDLURL = $wsdl;
3249              }
3250              $this->appendDebug($this->wsdl->getDebug());
3251              $this->wsdl->clearDebug();
3252              if($err = $this->wsdl->getError()){
3253                  die('WSDL ERROR: '.$err);
3254              }
3255          }
3256      }
3257  
3258      /**
3259      * processes request and returns response
3260      *
3261      * @param    string $data usually is the value of $HTTP_RAW_POST_DATA
3262      * @access   public
3263      */
3264  	function service($data){
3265          global $HTTP_SERVER_VARS;
3266  
3267          if (isset($_SERVER['QUERY_STRING'])) {
3268              $qs = $_SERVER['QUERY_STRING'];
3269          } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3270              $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3271          } else {
3272              $qs = '';
3273          }
3274          $this->debug("In service, query string=$qs");
3275  
3276          if (ereg('wsdl', $qs) ){
3277              $this->debug("In service, this is a request for WSDL");
3278              if($this->externalWSDLURL){
3279                if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
3280                  header('Location: '.$this->externalWSDLURL);
3281                } else { // assume file
3282                  header("Content-Type: text/xml\r\n");
3283                  $fp = fopen($this->externalWSDLURL, 'r');
3284                  fpassthru($fp);
3285                }
3286              } elseif ($this->wsdl) {
3287                  header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
3288                  print $this->wsdl->serialize($this->debug_flag);
3289                  if ($this->debug_flag) {
3290                      $this->debug('wsdl:');
3291                      $this->appendDebug($this->varDump($this->wsdl));
3292                      print $this->getDebugAsXMLComment();
3293                  }
3294              } else {
3295                  header("Content-Type: text/html; charset=ISO-8859-1\r\n");
3296                  print "This service does not provide WSDL";
3297              }
3298          } elseif ($data == '' && $this->wsdl) {
3299              $this->debug("In service, there is no data, so return Web description");
3300              print $this->wsdl->webDescription();
3301          } else {
3302              $this->debug("In service, invoke the request");
3303              $this->parse_request($data);
3304              if (! $this->fault) {
3305                  $this->invoke_method();
3306              }
3307              if (! $this->fault) {
3308                  $this->serialize_return();
3309              }
3310              $this->send_response();
3311          }
3312      }
3313  
3314      /**
3315      * parses HTTP request headers.
3316      *
3317      * The following fields are set by this function (when successful)
3318      *
3319      * headers
3320      * request
3321      * xml_encoding
3322      * SOAPAction
3323      *
3324      * @access   private
3325      */
3326  	function parse_http_headers() {
3327          global $HTTP_SERVER_VARS;
3328  
3329          $this->request = '';
3330          $this->SOAPAction = '';
3331  
3332          //Commented to fix the issue in PHP 5 Windows system ---Jeri
3333          //when we use getallheaders function  we are geting an error description invalid gzip crc value when parsing the response in VB
3334          // hence the function is commented out and $_SERVER is used to get all the header informations.
3335          
3336          /*if(function_exists('getallheaders')){
3337              $this->debug("In parse_http_headers, use getallheaders");
3338              $headers = getallheaders();
3339              foreach($headers as $k=>$v){
3340                  $k = strtolower($k);
3341                  $this->headers[$k] = $v;
3342                  $this->request .= "$k: $v\r\n";
3343                  $this->debug("$k: $v");
3344              }
3345              // get SOAPAction header
3346              if(isset($this->headers['soapaction'])){
3347                  $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
3348              }
3349              // get the character encoding of the incoming request
3350              if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
3351                  $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
3352                  if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
3353                      $this->xml_encoding = strtoupper($enc);
3354                  } else {
3355                      $this->xml_encoding = 'US-ASCII';
3356                  }
3357              } else {
3358                  // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3359                  $this->xml_encoding = 'ISO-8859-1';
3360              }
3361          } else*/if(isset($_SERVER) && is_array($_SERVER)){
3362              $this->debug("In parse_http_headers, use _SERVER");
3363              foreach ($_SERVER as $k => $v) {
3364                  if (substr($k, 0, 5) == 'HTTP_') {
3365                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                              $k = strtolower(substr($k, 5));
3366                  } else {
3367                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                              $k = strtolower($k);
3368                  }
3369                  if ($k == 'soapaction') {
3370                      // get SOAPAction header
3371                      $k = 'SOAPAction';
3372                      $v = str_replace('"', '', $v);
3373                      $v = str_replace('\\', '', $v);
3374                      $this->SOAPAction = $v;
3375                  } else if ($k == 'content-type') {
3376                      // get the character encoding of the incoming request
3377                      if (strpos($v, '=')) {
3378                          $enc = substr(strstr($v, '='), 1);
3379                          $enc = str_replace('"', '', $enc);
3380                          $enc = str_replace('\\', '', $enc);
3381                          if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
3382                              $this->xml_encoding = strtoupper($enc);
3383                          } else {
3384                              $this->xml_encoding = 'US-ASCII';
3385                          }
3386                      } else {
3387                          // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3388                          $this->xml_encoding = 'ISO-8859-1';
3389                      }
3390                  }
3391                  $this->headers[$k] = $v;
3392                  $this->request .= "$k: $v\r\n";
3393                  $this->debug("$k: $v");
3394              }
3395          } elseif (is_array($HTTP_SERVER_VARS)) {
3396              $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
3397              foreach ($HTTP_SERVER_VARS as $k => $v) {
3398                  if (substr($k, 0, 5) == 'HTTP_') {
3399                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                              $k = strtolower(substr($k, 5));
3400                  } else {
3401                      $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                              $k = strtolower($k);
3402                  }
3403                  if ($k == 'soapaction') {
3404                      // get SOAPAction header
3405                      $k = 'SOAPAction';
3406                      $v = str_replace('"', '', $v);
3407                      $v = str_replace('\\', '', $v);
3408                      $this->SOAPAction = $v;
3409                  } else if ($k == 'content-type') {
3410                      // get the character encoding of the incoming request
3411                      if (strpos($v, '=')) {
3412                          $enc = substr(strstr($v, '='), 1);
3413                          $enc = str_replace('"', '', $enc);
3414                          $enc = str_replace('\\', '', $enc);
3415                          if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
3416                              $this->xml_encoding = strtoupper($enc);
3417                          } else {
3418                              $this->xml_encoding = 'US-ASCII';
3419                          }
3420                      } else {
3421                          // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3422                          $this->xml_encoding = 'ISO-8859-1';
3423                      }
3424                  }
3425                  $this->headers[$k] = $v;
3426                  $this->request .= "$k: $v\r\n";
3427                  $this->debug("$k: $v");
3428              }
3429          } else {
3430              $this->debug("In parse_http_headers, HTTP headers not accessible");
3431              $this->setError("HTTP headers not accessible");
3432          }
3433      }
3434  
3435      /**
3436      * parses a request
3437      *
3438      * The following fields are set by this function (when successful)
3439      *
3440      * headers
3441      * request
3442      * xml_encoding
3443      * SOAPAction
3444      * request
3445      * requestSOAP
3446      * methodURI
3447      * methodname
3448      * methodparams
3449      * requestHeaders
3450      * document
3451      *
3452      * This sets the fault field on error
3453      *
3454      * @param    string $data XML string
3455      * @access   private
3456      */
3457  	function parse_request($data='') {
3458          $this->debug('entering parse_request()');
3459          $this->parse_http_headers();
3460          $this->debug('got character encoding: '.$this->xml_encoding);
3461          // uncompress if necessary
3462          if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
3463              $this->debug('got content encoding: ' . $this->headers['content-encoding']);
3464              if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
3465                  // if decoding works, use it. else assume data wasn't gzencoded
3466                  if (function_exists('gzuncompress')) {
3467                      if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
3468                          $data = $degzdata;
3469                      } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
3470                          $data = $degzdata;
3471                      } else {
3472                          $this->fault('Client', 'Errors occurred when trying to decode the data');
3473                          return;
3474                      }
3475                  } else {
3476                      $this->fault('Client', 'This Server does not support compressed data');
3477                      return;
3478                  }
3479              }
3480          }
3481          $this->request .= "\r\n".$data;
3482          $data = $this->parseRequest($this->headers, $data);
3483          $this->requestSOAP = $data;
3484          $this->debug('leaving parse_request');
3485      }
3486  
3487      /**
3488      * invokes a PHP function for the requested SOAP method
3489      *
3490      * The following fields are set by this function (when successful)
3491      *
3492      * methodreturn
3493      *
3494      * Note that the PHP function that is called may also set the following
3495      * fields to affect the response sent to the client
3496      *
3497      * responseHeaders
3498      * outgoing_headers
3499      *
3500      * This sets the fault field on error
3501      *
3502      * @access   private
3503      */
3504  	function invoke_method() {
3505          $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
3506  
3507          if ($this->wsdl) {
3508              if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
3509                  $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
3510                  $this->appendDebug('opData=' . $this->varDump($this->opData));
3511              } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
3512                  // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
3513                  $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
3514                  $this->appendDebug('opData=' . $this->varDump($this->opData));
3515                  $this->methodname = $this->opData['name'];
3516              } else {
3517                  $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
3518                  $this->fault('Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
3519                  return;
3520              }
3521          } else {
3522              $this->debug('in invoke_method, no WSDL to validate method');
3523          }
3524  
3525          // if a . is present in $this->methodname, we see if there is a class in scope,
3526          // which could be referred to. We will also distinguish between two deliminators,
3527          // to allow methods to be called a the class or an instance
3528          $class = '';
3529          $method = '';
3530          if (strpos($this->methodname, '..') > 0) {
3531              $delim = '..';
3532          } else if (strpos($this->methodname, '.') > 0) {
3533              $delim = '.';
3534          } else {
3535              $delim = '';
3536          }
3537  
3538          if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
3539              class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
3540              // get the class and method name
3541              $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
3542              $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
3543              $this->debug("in invoke_method, class=$class method=$method delim=$delim");
3544          }
3545  
3546          // does method exist?
3547          if ($class == '') {
3548              if (!function_exists($this->methodname)) {
3549                  $this->debug("in invoke_method, function '$this->methodname' not found!");
3550                  $this->result = 'fault: method not found';
3551                  $this->fault('Client',"method '$this->methodname' not defined in service");
3552                  return;
3553              }
3554          } else {
3555              $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
3556              if (!in_array($method_to_compare, get_class_methods($class))) {
3557                  $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
3558                  $this->result = 'fault: method not found';
3559                  $this->fault('Client',"method '$this->methodname' not defined in service");
3560                  return;
3561              }
3562          }
3563  
3564          // evaluate message, getting back parameters
3565          // verify that request parameters match the method's signature
3566          if(! $this->verify_method($this->methodname,$this->methodparams)){
3567              // debug
3568              $this->debug('ERROR: request not verified against method signature');
3569              $this->result = 'fault: request failed validation against method signature';
3570              // return fault
3571              $this->fault('Client',"Operation '$this->methodname' not defined in service.");
3572              return;
3573          }
3574  
3575          // if there are parameters to pass
3576          $this->debug('in invoke_method, params:');
3577          $this->appendDebug($this->varDump($this->methodparams));
3578          $this->debug("in invoke_method, calling '$this->methodname'");
3579          if (!function_exists('call_user_func_array')) {
3580              if ($class == '') {
3581                  $this->debug('in invoke_method, calling function using eval()');
3582                  $funcCall = "\$this->methodreturn = $this->methodname(";
3583              } else {
3584                  if ($delim == '..') {
3585                      $this->debug('in invoke_method, calling class method using eval()');
3586                      $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
3587                  } else {
3588                      $this->debug('in invoke_method, calling instance method using eval()');
3589                      // generate unique instance name
3590                      $instname = "\$inst_".time();
3591                      $funcCall = $instname." = new ".$class."(); ";
3592                      $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
3593                  }
3594              }
3595              if ($this->methodparams) {
3596                  foreach ($this->methodparams as $param) {
3597                      if (is_array($param)) {
3598                          $this->fault('Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
3599                          return;
3600                      }
3601                      $funcCall .= "\"$param\",";
3602                  }
3603                  $funcCall = substr($funcCall, 0, -1);
3604              }
3605              $funcCall .= ');';
3606              $this->debug('in invoke_method, function call: '.$funcCall);
3607              @eval($funcCall);
3608          } else {
3609              if ($class == '') {
3610                  $this->debug('in invoke_method, calling function using call_user_func_array()');
3611                  $call_arg = "$this->methodname";    // straight assignment changes $this->methodname to lower case after call_user_func_array()
3612              } elseif ($delim == '..') {
3613                  $this->debug('in invoke_method, calling class method using call_user_func_array()');
3614                  $call_arg = array ($class, $method);
3615              } else {
3616                  $this->debug('in invoke_method, calling instance method using call_user_func_array()');
3617                  $instance = new $class ();
3618                  $call_arg = array(&$instance, $method);
3619              }
3620              $this->methodreturn = call_user_func_array($call_arg, $this->methodparams);
3621          }
3622          $this->debug('in invoke_method, methodreturn:');
3623          $this->appendDebug($this->varDump($this->methodreturn));
3624          $this->debug("in invoke_method, called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
3625      }
3626  
3627      /**
3628      * serializes the return value from a PHP function into a full SOAP Envelope
3629      *
3630      * The following fields are set by this function (when successful)
3631      *
3632      * responseSOAP
3633      *
3634      * This sets the fault field on error
3635      *
3636      * @access   private
3637      */
3638  	function serialize_return() {
3639          $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
3640          // if fault
3641          if (isset($this->methodreturn) && (get_class($this->methodreturn) == 'soap_fault')) {
3642              $this->debug('got a fault object from method');
3643              $this->fault = $this->methodreturn;
3644              return;
3645          } elseif ($this->methodreturnisliteralxml) {
3646              $return_val = $this->methodreturn;
3647          // returned value(s)
3648          } else {
3649              $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
3650              $this->debug('serializing return value');
3651              if($this->wsdl){
3652                  // weak attempt at supporting multiple output params
3653                  if(sizeof($this->opData['output']['parts']) > 1){
3654                      $opParams = $this->methodreturn;
3655                  } else {
3656                      // TODO: is this really necessary?
3657                      $opParams = array($this->methodreturn);
3658                  }
3659                  $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
3660                  $this->appendDebug($this->wsdl->getDebug());
3661                  $this->wsdl->clearDebug();
3662                  if($errstr = $this->wsdl->getError()){
3663                      $this->debug('got wsdl error: '.$errstr);
3664                      $this->fault('Server', 'unable to serialize result');
3665                      return;
3666                  }
3667              } else {
3668                  if (isset($this->methodreturn)) {
3669                      $return_val = $this->serialize_val($this->methodreturn, 'return');
3670                  } else {
3671                      $return_val = '';
3672                      $this->debug('in absence of WSDL, assume void return for backward compatibility');
3673                  }
3674              }
3675          }
3676          $this->debug('return value:');
3677          $this->appendDebug($this->varDump($return_val));
3678  
3679          $this->debug('serializing response');
3680          if ($this->wsdl) {
3681              $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
3682              if ($this->opData['style'] == 'rpc') {
3683                  $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
3684                  if ($this->opData['output']['use'] == 'literal') {
3685                      $payload = '<'.$this->methodname.'Response xmlns="'.$this->methodURI.'">'.$return_val.'</'.$this->methodname."Response>";
3686                  } else {
3687                      $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
3688                  }
3689              } else {
3690                  $this->debug('style is not rpc for serialization: assume document');
3691                  $payload = $return_val;
3692              }
3693          } else {
3694              $this->debug('do not have WSDL for serialization: assume rpc/encoded');
3695              $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
3696          }
3697          $this->result = 'successful';
3698          if($this->wsdl){
3699              //if($this->debug_flag){
3700                  $this->appendDebug($this->wsdl->getDebug());
3701              //    }
3702              if (isset($opData['output']['encodingStyle'])) {
3703                  $encodingStyle = $opData['output']['encodingStyle'];
3704              } else {
3705                  $encodingStyle = '';
3706              }
3707              // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
3708              $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$encodingStyle);
3709          } else {
3710              $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
3711          }
3712          $this->debug("Leaving serialize_return");
3713      }
3714  
3715      /**
3716      * sends an HTTP response
3717      *
3718      * The following fields are set by this function (when successful)
3719      *
3720      * outgoing_headers
3721      * response
3722      *
3723      * @access   private
3724      */
3725  	function send_response() {
3726          $this->debug('Enter send_response');
3727          if ($this->fault) {
3728              $payload = $this->fault->serialize();
3729              $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
3730              $this->outgoing_headers[] = "Status: 500 Internal Server Error";
3731          } else {
3732              $payload = $this->responseSOAP;
3733              // Some combinations of PHP+Web server allow the Status
3734              // to come through as a header.  Since OK is the default
3735              // just do nothing.
3736              // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
3737              // $this->outgoing_headers[] = "Status: 200 OK";
3738          }
3739          // add debug data if in debug mode
3740          if(isset($this->debug_flag) && $this->debug_flag){
3741              $payload .= $this->getDebugAsXMLComment();
3742          }
3743          $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
3744          ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
3745          $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
3746          // Let the Web server decide about this
3747          //$this->outgoing_headers[] = "Connection: Close\r\n";
3748          $payload = $this->getHTTPBody($payload);
3749          $type = $this->getHTTPContentType();
3750          $charset = $this->getHTTPContentTypeCharset();
3751          $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
3752          //begin code to compress payload - by John
3753          // NOTE: there is no way to know whether the Web server will also compress
3754          // this data.
3755          if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {    
3756              if (strstr($this->headers['accept-encoding'], 'gzip')) {
3757                  if (function_exists('gzencode')) {
3758                      if (isset($this->debug_flag) && $this->debug_flag) {
3759                          $payload .= "<!-- Content being gzipped -->";
3760                      }
3761                      $this->outgoing_headers[] = "Content-Encoding: gzip";
3762                      $payload = gzencode($payload);
3763                  } else {
3764                      if (isset($this->debug_flag) && $this->debug_flag) {
3765                          $payload .= "<!-- Content will not be gzipped: no gzencode -->";
3766                      }
3767                  }
3768              } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
3769                  // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
3770                  // instead of gzcompress output,
3771                  // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
3772                  if (function_exists('gzdeflate')) {
3773                      if (isset($this->debug_flag) && $this->debug_flag) {
3774                          $payload .= "<!-- Content being deflated -->";
3775                      }
3776                      $this->outgoing_headers[] = "Content-Encoding: deflate";
3777                      $payload = gzdeflate($payload);
3778                  } else {
3779                      if (isset($this->debug_flag) && $this->debug_flag) {
3780                          $payload .= "<!-- Content will not be deflated: no gzcompress -->";
3781                      }
3782                  }
3783              }
3784          }
3785          //end code
3786          $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
3787          reset($this->outgoing_headers);
3788          foreach($this->outgoing_headers as $hdr){
3789              header($hdr, false);
3790          }
3791          print $payload;
3792          $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
3793      }
3794  
3795      /**
3796      * takes the value that was created by parsing the request
3797      * and compares to the method's signature, if available.
3798      *
3799      * @param    string    $operation    The operation to be invoked
3800      * @param    array    $request    The array of parameter values
3801      * @return    boolean    Whether the operation was found
3802      * @access   private
3803      */
3804  	function verify_method($operation,$request){
3805          if(isset($this->wsdl) && is_object($this->wsdl)){
3806              if($this->wsdl->getOperationData($operation)){
3807                  return true;
3808              }
3809          } elseif(isset($this->operations[$operation])){
3810              return true;
3811          }
3812          return false;
3813      }
3814  
3815      /**
3816      * processes SOAP message received from client
3817      *
3818      * @param    array    $headers    The HTTP headers
3819      * @param    string    $data        unprocessed request data from client
3820      * @return    mixed    value of the message, decoded into a PHP type
3821      * @access   private
3822      */
3823      function parseRequest($headers, $data) {
3824          $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
3825          if (!strstr($headers['content-type'], 'text/xml')) {
3826              $this->setError('Request not of type text/xml');
3827              return false;
3828          }
3829          if (strpos($headers['content-type'], '=')) {
3830              $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
3831              $this->debug('Got response encoding: ' . $enc);
3832              if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
3833                  $this->xml_encoding = strtoupper($enc);
3834              } else {
3835                  $this->xml_encoding = 'US-ASCII';
3836              }
3837          } else {
3838              // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
3839              $this->xml_encoding = 'ISO-8859-1';
3840          }
3841          $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
3842          // parse response, get soap parser obj
3843          $parser = new soap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
3844          // parser debug
3845          $this->debug("parser debug: \n".$parser->getDebug());
3846          // if fault occurred during message parsing
3847          if($err = $parser->getError()){
3848              $this->result = 'fault: error in msg parsing: '.$err;
3849              $this->fault('Client',"error in msg parsing:\n".$err);
3850          // else successfully parsed request into soapval object
3851          } else {
3852              // get/set methodname
3853              $this->methodURI = $parser->root_struct_namespace;
3854              $this->methodname = $parser->root_struct_name;
3855              $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
3856              $this->debug('calling parser->get_response()');
3857              $this->methodparams = $parser->get_response();
3858              // get SOAP headers
3859              $this->requestHeaders = $parser->getHeaders();
3860              // add document for doclit support
3861              $this->document = $parser->document;
3862          }
3863       }
3864  
3865      /**
3866      * gets the HTTP body for the current response.
3867      *
3868      * @param string $soapmsg The SOAP payload
3869      * @return string The HTTP body, which includes the SOAP payload
3870      * @access private
3871      */
3872  	function getHTTPBody($soapmsg) {
3873          return $soapmsg;
3874      }
3875      
3876      /**
3877      * gets the HTTP content type for the current response.
3878      *
3879      * Note: getHTTPBody must be called before this.
3880      *
3881      * @return string the HTTP content type for the current response.
3882      * @access private
3883      */
3884  	function getHTTPContentType() {
3885          return 'text/xml';
3886      }
3887      
3888      /**
3889      * gets the HTTP content type charset for the current response.
3890      * returns false for non-text content types.
3891      *
3892      * Note: getHTTPBody must be called before this.
3893      *
3894      * @return string the HTTP content type charset for the current response.
3895      * @access private
3896      */
3897  	function getHTTPContentTypeCharset() {
3898          return $this->soap_defencoding;
3899      }
3900  
3901      /**
3902      * add a method to the dispatch map (this has been replaced by the register method)
3903      *
3904      * @param    string $methodname
3905      * @param    string $in array of input values
3906      * @param    string $out array of output values
3907      * @access   public
3908      * @deprecated
3909      */
3910  	function add_to_map($methodname,$in,$out){
3911              $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
3912      }
3913  
3914      /**
3915      * register a service function with the server
3916      *
3917      * @param    string $name the name of the PHP function, class.method or class..method
3918      * @param    array $in assoc array of input values: key = param name, value = param type
3919      * @param    array $out assoc array of output values: key = param name, value = param type
3920      * @param    mixed $namespace the element namespace for the method or false
3921      * @param    mixed $soapaction the soapaction for the method or false
3922      * @param    mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
3923      * @param    mixed $use optional (encoded|literal) or false
3924      * @param    string $documentation optional Description to include in WSDL
3925      * @param    string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
3926      * @access   public
3927      */
3928  	function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
3929          global $HTTP_SERVER_VARS;
3930  
3931          if($this->externalWSDLURL){
3932              die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
3933          }
3934          if (! $name) {
3935              die('You must specify a name when you register an operation');
3936          }
3937          if (!is_array($in)) {
3938              die('You must provide an array for operation inputs');
3939          }
3940          if (!is_array($out)) {
3941              die('You must provide an array for operation outputs');
3942          }
3943          if(false == $namespace) {
3944          }
3945          if(false == $soapaction) {
3946              if (isset($_SERVER)) {
3947                  $SERVER_NAME = $_SERVER['SERVER_NAME'];
3948                  $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
3949              } elseif (isset($HTTP_SERVER_VARS)) {
3950                  $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
3951                  $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
3952              } else {
3953                  $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
3954              }
3955              $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name";
3956          }
3957          if(false == $style) {
3958              $style = "rpc";
3959          }
3960          if(false == $use) {
3961              $use = "encoded";
3962          }
3963          if ($use == 'encoded' && $encodingStyle = '') {
3964              $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
3965          }
3966  
3967          $this->operations[$name] = array(
3968          'name' => $name,
3969          'in' => $in,
3970          'out' => $out,
3971          'namespace' => $namespace,
3972          'soapaction' => $soapaction,
3973          'style' => $style);
3974          if($this->wsdl){
3975              $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
3976          }
3977          return true;
3978      }
3979  
3980      /**
3981      * Specify a fault to be returned to the client.
3982      * This also acts as a flag to the server that a fault has occured.
3983      *
3984      * @param    string $faultcode
3985      * @param    string $faultstring
3986      * @param    string $faultactor
3987      * @param    string $faultdetail
3988      * @access   public
3989      */
3990  	function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
3991          if ($faultdetail == '' && $this->debug_flag) {
3992              $faultdetail = $this->getDebug();
3993          }
3994          $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
3995          $this->fault->soap_defencoding = $this->soap_defencoding;
3996      }
3997  
3998      /**
3999      * Sets up wsdl object.
4000      * Acts as a flag to enable internal WSDL generation
4001      *
4002      * @param string $serviceName, name of the service
4003      * @param mixed $namespace optional 'tns' service namespace or false
4004      * @param mixed $endpoint optional URL of service endpoint or false
4005      * @param string $style optional (rpc|document) WSDL style (also specified by operation)
4006      * @param string $transport optional SOAP transport
4007      * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
4008      */
4009      function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
4010      {
4011          global $HTTP_SERVER_VARS;
4012  
4013          if (isset($_SERVER)) {
4014              $SERVER_NAME = $_SERVER['SERVER_NAME'];
4015              $SERVER_PORT = $_SERVER['SERVER_PORT'];
4016              $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4017              $HTTPS = $_SERVER['HTTPS'];
4018          } elseif (isset($HTTP_SERVER_VARS)) {
4019              $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4020              $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4021              $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4022              $HTTPS = $HTTP_SERVER_VARS['HTTPS'];
4023          } else {
4024              $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4025          }
4026          if ($SERVER_PORT == 80) {
4027              $SERVER_PORT = '';
4028          } else {
4029              $SERVER_PORT = ':' . $SERVER_PORT;
4030          }
4031          if(false == $namespace) {
4032              $namespace = "http://$SERVER_NAME/soap/$serviceName";
4033          }
4034          
4035          if(false == $endpoint) {
4036              if ($HTTPS == '1' || $HTTPS == 'on') {
4037                  $SCHEME = 'https';
4038              } else {
4039                  $SCHEME = 'http';
4040              }
4041              $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
4042          }
4043          
4044          if(false == $schemaTargetNamespace) {
4045              $schemaTargetNamespace = $namespace;
4046          }
4047          
4048          $this->wsdl = new wsdl;
4049          $this->wsdl->serviceName = $serviceName;
4050          $this->wsdl->endpoint = $endpoint;
4051          $this->wsdl->namespaces['tns'] = $namespace;
4052          $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4053          $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4054          if ($schemaTargetNamespace != $namespace) {
4055              $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4056          }
4057          $this->wsdl->schemas[$schemaTargetNamespace][0] = new xmlschema('', '', $this->wsdl->namespaces);
4058          $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
4059          $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
4060          $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
4061          $this->wsdl->bindings[$serviceName.'Binding'] = array(
4062              'name'=>$serviceName.'Binding',
4063              'style'=>$style,
4064              'transport'=>$transport,
4065              'portType'=>$serviceName.'PortType');
4066          $this->wsdl->ports[$serviceName.'Port'] = array(
4067              'binding'=>$serviceName.'Binding',
4068              'location'=>$endpoint,
4069              'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
4070      }
4071  }
4072  
4073  
4074  
4075  ?><?php
4076  
4077  
4078  
4079  /**
4080  * parses a WSDL file, allows access to it's data, other utility methods
4081  * 
4082  * @author   Dietrich Ayala <dietrich@ganx4.com>
4083  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
4084  * @access public 
4085  */
4086  class wsdl extends nusoap_base {
4087      // URL or filename of the root of this WSDL
4088      var $wsdl; 
4089      // define internal arrays of bindings, ports, operations, messages, etc.
4090      var $schemas = array();
4091      var $currentSchema;
4092      var $message = array();
4093      var $complexTypes = array();
4094      var $messages = array();
4095      var $currentMessage;
4096      var $currentOperation;
4097      var $portTypes = array();
4098      var $currentPortType;
4099      var $bindings = array();
4100      var $currentBinding;
4101      var $ports = array();
4102      var $currentPort;
4103      var $opData = array();
4104      var $status = '';
4105      var $documentation = false;
4106      var $endpoint = ''; 
4107      // array of wsdl docs to import
4108      var $import = array(); 
4109      // parser vars
4110      var $parser;
4111      var $position = 0;
4112      var $depth = 0;
4113      var $depth_array = array();
4114      // for getting wsdl
4115      var $proxyhost = '';
4116      var $proxyport = '';
4117      var $proxyusername = '';
4118      var $proxypassword = '';
4119      var $timeout = 0;
4120      var $response_timeout = 30;
4121  
4122      /**
4123       * constructor
4124       * 
4125       * @param string $wsdl WSDL document URL
4126       * @param string $proxyhost
4127       * @param string $proxyport
4128       * @param string $proxyusername
4129       * @param string $proxypassword
4130       * @param integer $timeout set the connection timeout
4131       * @param integer $response_timeout set the response timeout
4132       * @access public 
4133       */
4134      function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){
4135          parent::nusoap_base();
4136          $this->wsdl = $wsdl;
4137          $this->proxyhost = $proxyhost;
4138          $this->proxyport = $proxyport;
4139          $this->proxyusername = $proxyusername;
4140          $this->proxypassword = $proxypassword;
4141          $this->timeout = $timeout;
4142          $this->response_timeout = $response_timeout;
4143          
4144          // parse wsdl file
4145          if ($wsdl != "") {
4146              $this->debug('initial wsdl URL: ' . $wsdl);
4147              $this->parseWSDL($wsdl);
4148          }
4149          // imports
4150          // TODO: handle imports more properly, grabbing them in-line and nesting them
4151              $imported_urls = array();
4152              $imported = 1;
4153              while ($imported > 0) {
4154                  $imported = 0;
4155                  // Schema imports
4156                  foreach ($this->schemas as $ns => $list) {
4157                      foreach ($list as $xs) {
4158                          $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
4159                          foreach ($xs->imports as $ns2 => $list2) {
4160                              for ($ii = 0; $ii < count($list2); $ii++) {
4161                                  if (! $list2[$ii]['loaded']) {
4162                                      $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
4163                                      $url = $list2[$ii]['location'];
4164                                      if ($url != '') {
4165                                          $urlparts = parse_url($url);
4166                                          if (!isset($urlparts['host'])) {
4167                                              $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
4168                                                      substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4169                                          }
4170                                          if (! in_array($url, $imported_urls)) {
4171                                              $this->parseWSDL($url);
4172                                              $imported++;
4173                                              $imported_urls[] = $url;
4174                                          }
4175                                      } else {
4176                                          $this->debug("Unexpected scenario: empty URL for unloaded import");
4177                                      }
4178                                  }
4179                              }
4180                          } 
4181                      }
4182                  }
4183                  // WSDL imports
4184                  $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
4185                  foreach ($this->import as $ns => $list) {
4186                      for ($ii = 0; $ii < count($list); $ii++) {
4187                          if (! $list[$ii]['loaded']) {
4188                              $this->import[$ns][$ii]['loaded'] = true;
4189                              $url = $list[$ii]['location'];
4190                              if ($url != '') {
4191                                  $urlparts = parse_url($url);
4192                                  if (!isset($urlparts['host'])) {
4193                                      $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
4194                                              substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
4195                                  }
4196                                  if (! in_array($url, $imported_urls)) {
4197                                      $this->parseWSDL($url);
4198                                      $imported++;
4199                                      $imported_urls[] = $url;
4200                                  }
4201                              } else {
4202                                  $this->debug("Unexpected scenario: empty URL for unloaded import");
4203                              }
4204                          }
4205                      }
4206                  } 
4207              }
4208          // add new data to operation data
4209          foreach($this->bindings as $binding => $bindingData) {
4210              if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
4211                  foreach($bindingData['operations'] as $operation => $data) {
4212                      $this->debug('post-parse data gathering for ' . $operation);
4213                      $this->bindings[$binding]['operations'][$operation]['input'] = 
4214                          isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
4215                          array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
4216                          $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
4217                      $this->bindings[$binding]['operations'][$operation]['output'] = 
4218                          isset($this->bindings[$binding]['operations'][$operation]['output']) ?
4219                          array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
4220                          $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
4221                      if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
4222                          $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
4223                      }
4224                      if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
4225                             $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
4226                      }
4227                      if (isset($bindingData['style'])) {
4228                          $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
4229                      }
4230                      $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
4231                      $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
4232                      $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
4233                  } 
4234              } 
4235          }
4236      }
4237  
4238      /**
4239       * parses the wsdl document
4240       * 
4241       * @param string $wsdl path or URL
4242       * @access private 
4243       */
4244      function parseWSDL($wsdl = '')
4245      {
4246          if ($wsdl == '') {
4247              $this->debug('no wsdl passed to parseWSDL()!!');
4248              $this->setError('no wsdl passed to parseWSDL()!!');
4249              return false;
4250          }
4251          
4252          // parse $wsdl for url format
4253          $wsdl_props = parse_url($wsdl);
4254  
4255          if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
4256              $this->debug('getting WSDL http(s) URL ' . $wsdl);
4257              // get wsdl
4258              $tr = new soap_transport_http($wsdl);
4259              $tr->request_method = 'GET';
4260              $tr->useSOAPAction = false;
4261              if($this->proxyhost && $this->proxyport){
4262                  $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
4263              }
4264              $tr->setEncoding('gzip, deflate');
4265              $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
4266              //$this->debug("WSDL request\n" . $tr->outgoing_payload);
4267              //$this->debug("WSDL response\n" . $tr->incoming_payload);
4268              $this->appendDebug($tr->getDebug());
4269              // catch errors
4270              if($err = $tr->getError() ){
4271                  $errstr = 'HTTP ERROR: '.$err;
4272                  $this->debug($errstr);
4273                  $this->setError($errstr);
4274                  unset($tr);
4275                  return false;
4276              }
4277              unset($tr);
4278              $this->debug("got WSDL URL");
4279          } else {
4280              // $wsdl is not http(s), so treat it as a file URL or plain file path
4281              if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
4282                  $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
4283              } else {
4284                  $path = $wsdl;
4285              }
4286              $this->debug('getting WSDL file ' . $path);
4287              if ($fp = @fopen($path, 'r')) {
4288                  $wsdl_string = '';
4289                  while ($data = fread($fp, 32768)) {
4290                      $wsdl_string .= $data;
4291                  } 
4292                  fclose($fp);
4293              } else {
4294                  $errstr = "Bad path to WSDL file $path";
4295                  $this->debug($errstr);
4296                  $this->setError($errstr);
4297                  return false;
4298              } 
4299          }
4300          $this->debug('Parse WSDL');
4301          // end new code added
4302          // Create an XML parser.
4303          $this->parser = xml_parser_create(); 
4304          // Set the options for parsing the XML data.
4305          // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
4306          xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
4307          // Set the object for the parser.
4308          xml_set_object($this->parser, $this); 
4309          // Set the element handlers for the parser.
4310          xml_set_element_handler($this->parser, 'start_element', 'end_element');
4311          xml_set_character_data_handler($this->parser, 'character_data');
4312          // Parse the XML file.
4313          if (!xml_parse($this->parser, $wsdl_string, true)) {
4314              // Display an error message.
4315              $errstr = sprintf(
4316                  'XML error parsing WSDL from %s on line %d: %s',
4317                  $wsdl,
4318                  xml_get_current_line_number($this->parser),
4319                  xml_error_string(xml_get_error_code($this->parser))
4320                  );
4321              $this->debug($errstr);
4322              $this->debug("XML payload:\n" . $wsdl_string);
4323              $this->setError($errstr);
4324              return false;
4325          } 
4326          // free the parser
4327          xml_parser_free($this->parser);
4328          $this->debug('Parsing WSDL done');
4329          // catch wsdl parse errors
4330          if($this->getError()){
4331              return false;
4332          }
4333          return true;
4334      } 
4335  
4336      /**
4337       * start-element handler
4338       * 
4339       * @param string $parser XML parser object
4340       * @param string $name element name
4341       * @param string $attrs associative array of attributes
4342       * @access private 
4343       */
4344      function start_element($parser, $name, $attrs)
4345      {
4346          if ($this->status == 'schema') {
4347              $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4348              $this->appendDebug($this->currentSchema->getDebug());
4349              $this->currentSchema->clearDebug();
4350          } elseif (ereg('schema$', $name)) {
4351              $this->debug('Parsing WSDL schema');
4352              // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
4353              $this->status = 'schema';
4354              $this->currentSchema = new xmlschema('', '', $this->namespaces);
4355              $this->currentSchema->schemaStartElement($parser, $name, $attrs);
4356              $this->appendDebug($this->currentSchema->getDebug());
4357              $this->currentSchema->clearDebug();
4358          } else {
4359              // position in the total number of elements, starting from 0
4360              $pos = $this->position++;
4361              $depth = $this->depth++; 
4362              // set self as current value for this depth
4363              $this->depth_array[$depth] = $pos;
4364              $this->message[$pos] = array('cdata' => ''); 
4365              // process attributes
4366              if (count($attrs) > 0) {
4367                  // register namespace declarations
4368                  foreach($attrs as $k => $v) {
4369                      if (ereg("^xmlns", $k)) {
4370                          if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
4371                              $this->namespaces[$ns_prefix] = $v;
4372                          } else {
4373                              $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
4374                          } 
4375                          if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
4376                              $this->XMLSchemaVersion = $v;
4377                              $this->namespaces['xsi'] = $v . '-instance';
4378                          } 
4379                      }
4380                  }
4381                  // expand each attribute prefix to its namespace
4382                  foreach($attrs as $k => $v) {
4383                      $k = strpos($k, ':') ? $this->expandQname($k) : $k;
4384                      if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
4385                          $v = strpos($v, ':') ? $this->expandQname($v) : $v;
4386                      } 
4387                      $eAttrs[$k] = $v;
4388                  } 
4389                  $attrs = $eAttrs;
4390              } else {
4391                  $attrs = array();
4392              } 
4393              // get element prefix, namespace and name
4394              if (ereg(':', $name)) {
4395                  // get ns prefix
4396                  $prefix = substr($name, 0, strpos($name, ':')); 
4397                  // get ns
4398                  $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 
4399                  // get unqualified name
4400                  $name = substr(strstr($name, ':'), 1);
4401              } 
4402              // process attributes, expanding any prefixes to namespaces
4403              // find status, register data
4404              switch ($this->status) {
4405                  case 'message':
4406                      if ($name == 'part') {
4407                          if (isset($attrs['type'])) {
4408                              $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
4409                              $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
4410                          } 
4411                          if (isset($attrs['element'])) {
4412                              $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
4413                              $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
4414                          } 
4415                      } 
4416                      break;
4417                  case 'portType':
4418                      switch ($name) {
4419                          case 'operation':
4420                              $this->currentPortOperation = $attrs['name'];
4421                              $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
4422                              if (isset($attrs['parameterOrder'])) {
4423                                  $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
4424                              } 
4425                              break;
4426                          case 'documentation':
4427                              $this->documentation = true;
4428                              break; 
4429                          // merge input/output data
4430                          default:
4431                              $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
4432                              $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
4433                              break;
4434                      } 
4435                      break;
4436                  case 'binding':
4437                      switch ($name) {
4438                          case 'binding': 
4439                              // get ns prefix
4440                              if (isset($attrs['style'])) {
4441                              $this->bindings[$this->currentBinding]['prefix'] = $prefix;
4442                              } 
4443                              $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
4444                              break;
4445                          case 'header':
4446                              $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
4447                              break;
4448                          case 'operation':
4449                              if (isset($attrs['soapAction'])) {
4450                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
4451                              } 
4452                              if (isset($attrs['style'])) {
4453                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
4454                              } 
4455                              if (isset($attrs['name'])) {
4456                                  $this->currentOperation = $attrs['name'];
4457                                  $this->debug("current binding operation: $this->currentOperation");
4458                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
4459                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
4460                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
4461                              } 
4462                              break;
4463                          case 'input':
4464                              $this->opStatus = 'input';
4465                              break;
4466                          case 'output':
4467                              $this->opStatus = 'output';
4468                              break;
4469                          case 'body':
4470                              if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
4471                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
4472                              } else {
4473                                  $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
4474                              } 
4475                              break;
4476                      } 
4477                      break;
4478                  case 'service':
4479                      switch ($name) {
4480                          case 'port':
4481                              $this->currentPort = $attrs['name'];
4482                              $this->debug('current port: ' . $this->currentPort);
4483                              $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
4484                      
4485                              break;
4486                          case 'address':
4487                              $this->ports[$this->currentPort]['location'] = $attrs['location'];
4488                              $this->ports[$this->currentPort]['bindingType'] = $namespace;
4489                              $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
4490                              $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
4491                              break;
4492                      } 
4493                      break;
4494              } 
4495          // set status
4496          switch ($name) {
4497              case 'import':
4498                  if (isset($attrs['location'])) {
4499                      $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
4500                      $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
4501                  } else {
4502                      $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
4503                      if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
4504                          $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
4505                      }
4506                      $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
4507                  }
4508                  break;
4509              //wait for schema
4510              //case 'types':
4511              //    $this->status = 'schema';
4512              //    break;
4513              case 'message':
4514                  $this->status = 'message';
4515                  $this->messages[$attrs['name']] = array();
4516                  $this->currentMessage = $attrs['name'];
4517                  break;
4518              case 'portType':
4519                  $this->status = 'portType';
4520                  $this->portTypes[$attrs['name']] = array();
4521                  $this->currentPortType = $attrs['name'];
4522                  break;
4523              case "binding":
4524                  if (isset($attrs['name'])) {
4525                  // get binding name
4526                      if (strpos($attrs['name'], ':')) {
4527                          $this->currentBinding = $this->getLocalPart($attrs['name']);
4528                      } else {
4529                          $this->currentBinding = $attrs['name'];
4530                      } 
4531                      $this->status = 'binding';
4532                      $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
4533                      $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
4534                  } 
4535                  break;
4536              case 'service':
4537                  $this->serviceName = $attrs['name'];
4538                  $this->status = 'service';
4539                  $this->debug('current service: ' . $this->serviceName);
4540                  break;
4541              case 'definitions':
4542                  foreach ($attrs as $name => $value) {
4543                      $this->wsdl_info[$name] = $value;
4544                  } 
4545                  break;
4546              } 
4547          } 
4548      } 
4549  
4550      /**
4551      * end-element handler
4552      * 
4553      * @param string $parser XML parser object
4554      * @param string $name element name
4555      * @access private 
4556      */
4557  	function end_element($parser, $name){ 
4558          // unset schema status
4559          if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
4560              $this->status = "";
4561              $this->appendDebug($this->currentSchema->getDebug());
4562              $this->currentSchema->clearDebug();
4563              $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
4564              $this->debug('Parsing WSDL schema done');
4565          } 
4566          if ($this->status == 'schema') {
4567              $this->currentSchema->schemaEndElement($parser, $name);
4568          } else {
4569              // bring depth down a notch
4570              $this->depth--;
4571          } 
4572          // end documentation
4573          if ($this->documentation) {
4574              //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
4575              //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
4576              $this->documentation = false;
4577          } 
4578      } 
4579  
4580      /**
4581       * element content handler
4582       * 
4583       * @param string $parser XML parser object
4584       * @param string $data element content
4585       * @access private 
4586       */
4587  	function character_data($parser, $data)
4588      {
4589          $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
4590          if (isset($this->message[$pos]['cdata'])) {
4591              $this->message[$pos]['cdata'] .= $data;
4592          } 
4593          if ($this->documentation) {
4594              $this->documentation .= $data;
4595          } 
4596      } 
4597      
4598  	function getBindingData($binding)
4599      {
4600          if (is_array($this->bindings[$binding])) {
4601              return $this->bindings[$binding];
4602          } 
4603      }
4604      
4605      /**
4606       * returns an assoc array of operation names => operation data
4607       * 
4608       * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported)
4609       * @return array 
4610       * @access public 
4611       */
4612  	function getOperations($bindingType = 'soap')
4613      {
4614          $ops = array();
4615          if ($bindingType == 'soap') {
4616              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
4617          }
4618          // loop thru ports
4619          foreach($this->ports as $port => $portData) {
4620              // binding type of port matches parameter
4621              if ($portData['bindingType'] == $bindingType) {
4622                  //$this->debug("getOperations for port $port");
4623                  //$this->debug("port data: " . $this->varDump($portData));
4624                  //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
4625                  // merge bindings
4626                  if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
4627                      $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
4628                  }
4629              }
4630          } 
4631          return $ops;
4632      } 
4633      
4634      /**
4635       * returns an associative array of data necessary for calling an operation
4636       * 
4637       * @param string $operation , name of operation
4638       * @param string $bindingType , type of binding eg: soap
4639       * @return array 
4640       * @access public 
4641       */
4642  	function getOperationData($operation, $bindingType = 'soap')
4643      {
4644          if ($bindingType == 'soap') {
4645              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
4646          }
4647          // loop thru ports
4648          foreach($this->ports as $port => $portData) {
4649              // binding type of port matches parameter
4650              if ($portData['bindingType'] == $bindingType) {
4651                  // get binding
4652                  //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
4653                  foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
4654                      // note that we could/should also check the namespace here
4655                      if ($operation == $bOperation) {
4656                          $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
4657                          return $opData;
4658                      } 
4659                  } 
4660              }
4661          } 
4662      }
4663      
4664      /**
4665       * returns an associative array of data necessary for calling an operation
4666       * 
4667       * @param string $soapAction soapAction for operation
4668       * @param string $bindingType type of binding eg: soap
4669       * @return array 
4670       * @access public 
4671       */
4672  	function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
4673          if ($bindingType == 'soap') {
4674              $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
4675          }
4676          // loop thru ports
4677          foreach($this->ports as $port => $portData) {
4678              // binding type of port matches parameter
4679              if ($portData['bindingType'] == $bindingType) {
4680                  // loop through operations for the binding
4681                  foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
4682                      if ($opData['soapAction'] == $soapAction) {
4683                          return $opData;
4684                      } 
4685                  } 
4686              }
4687          } 
4688      }
4689      
4690      /**
4691      * returns an array of information about a given type
4692      * returns false if no type exists by the given name
4693      *
4694      *     typeDef = array(
4695      *     'elements' => array(), // refs to elements array
4696      *    'restrictionBase' => '',
4697      *    'phpType' => '',
4698      *    'order' => '(sequence|all)',
4699      *    'attrs' => array() // refs to attributes array
4700      *    )
4701      *
4702      * @param $type string the type
4703      * @param $ns string namespace (not prefix) of the type
4704      * @return mixed
4705      * @access public
4706      * @see xmlschema
4707      */
4708  	function getTypeDef($type, $ns) {
4709          $this->debug("in getTypeDef: type=$type, ns=$ns");
4710          if ((! $ns) && isset($this->namespaces['tns'])) {
4711              $ns = $this->namespaces['tns'];
4712              $this->debug("in getTypeDef: type namespace forced to $ns");
4713          }
4714          if (isset($this->schemas[$ns])) {
4715              $this->debug("in getTypeDef: have schema for namespace $ns");
4716              for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
4717                  $xs = &$this->schemas[$ns][$i];
4718                  $t = $xs->getTypeDef($type);
4719                  $this->appendDebug($xs->getDebug());
4720                  $xs->clearDebug();
4721                  if ($t) {
4722                      if (!isset($t['phpType'])) {
4723                          // get info for type to tack onto the element
4724                          $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
4725                          $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
4726                          $etype = $this->getTypeDef($uqType, $ns);
4727                          if ($etype) {
4728                              $this->debug("found type for [element] $type:");
4729                              $this->debug($this->varDump($etype));
4730                              if (isset($etype['phpType'])) {
4731                                  $t['phpType'] = $etype['phpType'];
4732                              }
4733                              if (isset($etype['elements'])) {
4734                                  $t['elements'] = $etype['elements'];
4735                              }
4736                              if (isset($etype['attrs'])) {
4737                                  $t['attrs'] = $etype['attrs'];
4738                              }
4739                          }
4740                      }
4741                      return $t;
4742                  }
4743              }
4744          } else {
4745              $this->debug("in getTypeDef: do not have schema for namespace $ns");
4746          }
4747          return false;
4748      }
4749  
4750      /**
4751      * prints html description of services
4752      *
4753      * @access private
4754      */
4755      function webDescription(){
4756          global $HTTP_SERVER_VARS;
4757  
4758          if (isset($_SERVER)) {
4759              $PHP_SELF = $_SERVER['PHP_SELF'];
4760          } elseif (isset($HTTP_SERVER_VARS)) {
4761              $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
4762          } else {
4763              $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
4764          }
4765  
4766          $b = '
4767          <html><head><title>NuSOAP: '.$this->serviceName.'</title>
4768          <style type="text/css">
4769              body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
4770              p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
4771              pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
4772              ul      { margin-top: 10px; margin-left: 20px; }
4773              li      { list-style-type: none; margin-top: 10px; color: #000000; }
4774              .content{
4775              margin-left: 0px; padding-bottom: 2em; }
4776              .nav {
4777              padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
4778              margin-top: 10px; margin-left: 0px; color: #000000;
4779              background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
4780              .title {
4781              font-family: arial; font-size: 26px; color: #ffffff;
4782              background-color: #999999; width: 105%; margin-left: 0px;
4783              padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
4784              .hidden {
4785              position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
4786              font-family: arial; overflow: hidden; width: 600;
4787              padding: 20px; font-size: 10px; background-color: #999999;
4788              layer-background-color:#FFFFFF; }
4789              a,a:active  { color: charcoal; font-weight: bold; }
4790              a:visited   { color: #666666; font-weight: bold; }
4791              a:hover     { color: cc3300; font-weight: bold; }
4792          </style>
4793          <script language="JavaScript" type="text/javascript">
4794          <!--
4795          // POP-UP CAPTIONS...
4796  		function lib_bwcheck(){ //Browsercheck (needed)
4797              this.ver=navigator.appVersion
4798              this.agent=navigator.userAgent
4799              this.dom=document.getElementById?1:0
4800              this.opera5=this.agent.indexOf("Opera 5")>-1
4801              this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
4802              this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
4803              this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
4804              this.ie=this.ie4||this.ie5||this.ie6
4805              this.mac=this.agent.indexOf("Mac")>-1
4806              this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
4807              this.ns4=(document.layers && !this.dom)?1:0;
4808              this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
4809              return this
4810          }
4811          var bw = new lib_bwcheck()
4812          //Makes crossbrowser object.
4813  		function makeObj(obj){
4814              this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
4815              if(!this.evnt) return false
4816              this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
4817              this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
4818              this.writeIt=b_writeIt;
4819              return this
4820          }
4821          // A unit of measure that will be added when setting the position of a layer.
4822          //var px = bw.ns4||window.opera?"":"px";
4823  		function b_writeIt(text){
4824              if (bw.ns4){this.wref.write(text);this.wref.close()}
4825              else this.wref.innerHTML = text
4826          }
4827          //Shows the messages
4828          var oDesc;
4829  		function popup(divid){
4830              if(oDesc = new makeObj(divid)){
4831              oDesc.css.visibility = "visible"
4832              }
4833          }
4834  		function popout(){ // Hides message
4835              if(oDesc) oDesc.css.visibility = "hidden"
4836          }
4837          //-->
4838          </script>
4839          </head>
4840          <body>
4841          <div class=content>
4842              <br><br>
4843              <div class=title>'.$this->serviceName.'</div>
4844              <div class=nav>
4845                  <p>View the <a href="'.$PHP_SELF.'?service='.$_REQUEST[service].'&wsdl">WSDL</a> for the service.
4846                  Click on an operation name to view it&apos;s details.</p>
4847                  <ul>';
4848                  foreach($this->getOperations() as $op => $data){
4849                      $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
4850                      // create hidden div
4851                      $b .= "<div id='$op' class='hidden'>
4852                      <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
4853                      foreach($data as $donnie => $marie){ // loop through opdata
4854                          if($donnie == 'input' || $donnie == 'output'){ // show input/output data
4855                              $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
4856                              foreach($marie as $captain => $tenille){ // loop through data
4857                                  if($captain == 'parts'){ // loop thru parts
4858                                      $b .= "&nbsp;&nbsp;$captain:<br>";
4859                                      //if(is_array($tenille)){
4860                                          foreach($tenille as $joanie => $chachi){
4861                                              $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
4862                                          }
4863                                      //}
4864                                  } else {
4865                                      $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
4866                                  }
4867                              }
4868                          } else {
4869                              $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
4870                          }
4871                      }
4872                      $b .= '</div>';
4873                  }
4874                  $b .= '
4875                  <ul>
4876              </div>
4877          </div></body></html>';
4878          return $b;
4879      }
4880  
4881      /**
4882      * serialize the parsed wsdl
4883      *
4884      * @param mixed $debug whether to put debug=1 in endpoint URL
4885      * @return string serialization of WSDL
4886      * @access public 
4887      */
4888  	function serialize($debug = 0)
4889      {
4890          $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
4891          $xml .= "\n<definitions";
4892          foreach($this->namespaces as $k => $v) {
4893              $xml .= " xmlns:$k=\"$v\"";
4894          } 
4895          // 10.9.02 - add poulter fix for wsdl and tns declarations
4896          if (isset($this->namespaces['wsdl'])) {
4897              $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
4898          } 
4899          if (isset($this->namespaces['tns'])) {
4900              $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
4901          } 
4902          $xml .= '>'; 
4903          // imports
4904          if (sizeof($this->import) > 0) {
4905              foreach($this->import as $ns => $list) {
4906                  foreach ($list as $ii) {
4907                      if ($ii['location'] != '') {
4908                          $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
4909                      } else {
4910                          $xml .= '<import namespace="' . $ns . '" />';
4911                      }
4912                  }
4913              } 
4914          } 
4915          // types
4916          if (count($this->schemas)>=1) {
4917              $xml .= "\n<types>";
4918              foreach ($this->schemas as $ns => $list) {
4919                  foreach ($list as $xs) {
4920                      $xml .= $xs->serializeSchema();
4921                  }
4922              }
4923              $xml .= '</types>';
4924          } 
4925          // messages
4926          if (count($this->messages) >= 1) {
4927              foreach($this->messages as $msgName => $msgParts) {
4928                  $xml .= "\n<message name=\"" . $msgName . '">';
4929                  if(is_array($msgParts)){
4930                      foreach($msgParts as $partName => $partType) {
4931                          // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
4932                          if (strpos($partType, ':')) {
4933                              $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
4934                          } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
4935                              // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
4936                              $typePrefix = 'xsd';
4937                          } else {
4938                              foreach($this->typemap as $ns => $types) {
4939                                  if (isset($types[$partType])) {
4940                                      $typePrefix = $this->getPrefixFromNamespace($ns);
4941                                  } 
4942                              } 
4943                              if (!isset($typePrefix)) {
4944                                  die("$partType has no namespace!");
4945                              } 
4946                          }
4947                          $ns = $this->getNamespaceFromPrefix($typePrefix);
4948                          $typeDef = $this->getTypeDef($this->getLocalPart($partType), $ns);
4949                          if ($typeDef['typeClass'] == 'element') {
4950                              $elementortype = 'element';
4951                          } else {
4952                              $elementortype = 'type';
4953                          }
4954                          $xml .= '<part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
4955                      }
4956                  }
4957                  $xml .= '</message>';
4958              } 
4959          } 
4960          // bindings & porttypes
4961          if (count($this->bindings) >= 1) {
4962              $binding_xml = '';
4963              $portType_xml = '';
4964              foreach($this->bindings as $bindingName => $attrs) {
4965                  $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
4966                  $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
4967                  $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
4968                  foreach($attrs['operations'] as $opName => $opParts) {
4969                      $binding_xml .= '<operation name="' . $opName . '">';
4970                      $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
4971                      if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
4972                          $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
4973                      } else {
4974                          $enc_style = '';
4975                      }
4976                      $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
4977                      if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
4978                          $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
4979                      } else {
4980                          $enc_style = '';
4981                      }
4982                      $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
4983                      $binding_xml .= '</operation>';
4984                      $portType_xml .= '<operation name="' . $opParts['name'] . '"';
4985                      if (isset($opParts['parameterOrder'])) {
4986                          $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
4987                      } 
4988                      $portType_xml .= '>';
4989                      if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
4990                          $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
4991                      }
4992                      $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
4993                      $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
4994                      $portType_xml .= '</operation>';
4995                  } 
4996                  $portType_xml .= '</portType>';
4997                  $binding_xml .= '</binding>';
4998              } 
4999              $xml .= $portType_xml . $binding_xml;
5000          } 
5001          // services
5002          $xml .= "\n<service name=\"" . $this->serviceName . '">';
5003          if (count($this->ports) >= 1) {
5004              foreach($this->ports as $pName => $attrs) {
5005                  $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5006                  $xml .= '<soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5007                  $xml .= '</port>';
5008              } 
5009          } 
5010          $xml .= '</service>';
5011          return $xml . "\n</definitions>";
5012      } 
5013      
5014      /**
5015       * serialize PHP values according to a WSDL message definition
5016       *
5017       * TODO
5018       * - multi-ref serialization
5019       * - validate PHP values against type definitions, return errors if invalid
5020       * 
5021       * @param string $operation operation name
5022       * @param string $direction (input|output)
5023       * @param mixed $parameters parameter value(s)
5024       * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
5025       * @access public
5026       */
5027  	function serializeRPCParameters($operation, $direction, $parameters)
5028      {
5029          $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 
5030          $this->appendDebug('parameters=' . $this->varDump($parameters));
5031          
5032          if ($direction != 'input' && $direction != 'output') {
5033              $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5034              $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5035              return false;
5036          } 
5037          if (!$opData = $this->getOperationData($operation)) {
5038              $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5039              $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5040              return false;
5041          }
5042          $this->debug('opData:');
5043          $this->appendDebug($this->varDump($opData));
5044  
5045          // Get encoding style for output and set to current
5046          $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5047          if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5048              $encodingStyle = $opData['output']['encodingStyle'];
5049              $enc_style = $encodingStyle;
5050          }
5051  
5052          // set input params
5053          $xml = '';
5054          if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5055              
5056              $use = $opData[$direction]['use'];
5057              $this->debug('have ' . count($opData[$direction]['parts']) . ' part(s) to serialize');
5058              if (is_array($parameters)) {
5059                  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5060                  $this->debug('have ' . count($parameters) . ' parameter(s) provided as ' . $parametersArrayType . ' to serialize');
5061                  foreach($opData[$direction]['parts'] as $name => $type) {
5062                      $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5063                      // Track encoding style
5064                      if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5065                          $encodingStyle = $opData[$direction]['encodingStyle'];            
5066                          $enc_style = $encodingStyle;
5067                      } else {
5068                          $enc_style = false;
5069                      }
5070                      // NOTE: add error handling here
5071                      // if serializeType returns false, then catch global error and fault
5072                      if ($parametersArrayType == 'arraySimple') {
5073                          $p = array_shift($parameters);
5074                          $this->debug('calling serializeType w/indexed param');
5075                          $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5076                      } elseif (isset($parameters[$name])) {
5077                          $this->debug('calling serializeType w/named param');
5078                          $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5079                      } else {
5080                          // TODO: only send nillable
5081                          $this->debug('calling serializeType w/null param');
5082                          $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5083                      }
5084                  }
5085              } else {
5086                  $this->debug('no parameters passed.');
5087              }
5088          }
5089          $this->debug("serializeRPCParameters returning: $xml");
5090          return $xml;
5091      } 
5092      
5093      /**
5094       * serialize a PHP value according to a WSDL message definition
5095       * 
5096       * TODO
5097       * - multi-ref serialization
5098       * - validate PHP values against type definitions, return errors if invalid
5099       * 
5100       * @param string $ type name
5101       * @param mixed $ param value
5102       * @return mixed new param or false if initial value didn't validate
5103       * @access public
5104       * @deprecated
5105       */
5106  	function serializeParameters($operation, $direction, $parameters)
5107      {
5108          $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 
5109          $this->appendDebug('parameters=' . $this->varDump($parameters));
5110          
5111          if ($direction != 'input' && $direction != 'output') {
5112              $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
5113              $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
5114              return false;
5115          } 
5116          if (!$opData = $this->getOperationData($operation)) {
5117              $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
5118              $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
5119              return false;
5120          }
5121          $this->debug('opData:');
5122          $this->appendDebug($this->varDump($opData));
5123          
5124          // Get encoding style for output and set to current
5125          $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5126          if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
5127              $encodingStyle = $opData['output']['encodingStyle'];
5128              $enc_style = $encodingStyle;
5129          }
5130          
5131          // set input params
5132          $xml = '';
5133          if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
5134              
5135              $use = $opData[$direction]['use'];
5136              $this->debug("use=$use");
5137              $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
5138              if (is_array($parameters)) {
5139                  $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
5140                  $this->debug('have ' . $parametersArrayType . ' parameters');
5141                  foreach($opData[$direction]['parts'] as $name => $type) {
5142                      $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
5143                      // Track encoding style
5144                      if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
5145                          $encodingStyle = $opData[$direction]['encodingStyle'];            
5146                          $enc_style = $encodingStyle;
5147                      } else {
5148                          $enc_style = false;
5149                      }
5150                      // NOTE: add error handling here
5151                      // if serializeType returns false, then catch global error and fault
5152                      if ($parametersArrayType == 'arraySimple') {
5153                          $p = array_shift($parameters);
5154                          $this->debug('calling serializeType w/indexed param');
5155                          $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
5156                      } elseif (isset($parameters[$name])) {
5157                          $this->debug('calling serializeType w/named param');
5158                          $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
5159                      } else {
5160                          // TODO: only send nillable
5161                          $this->debug('calling serializeType w/null param');
5162                          $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
5163                      }
5164                  }
5165              } else {
5166                  $this->debug('no parameters passed.');
5167              }
5168          }
5169          $this->debug("serializeParameters returning: $xml");
5170          return $xml;
5171      } 
5172      
5173      /**
5174       * serializes a PHP value according a given type definition
5175       * 
5176       * @param string $name name of value (part or element)
5177       * @param string $type XML schema type of value (type or element)
5178       * @param mixed $value a native PHP value (parameter value)
5179       * @param string $use use for part (encoded|literal)
5180       * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
5181       * @param boolean $unqualified a kludge for what should be XML namespace form handling
5182       * @return string value serialized as an XML string
5183       * @access private
5184       */
5185  	function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
5186      {
5187          $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
5188          $this->appendDebug("value=" . $this->varDump($value));
5189          if($use == 'encoded' && $encodingStyle) {
5190              $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
5191          }
5192  
5193          // if a soapval has been supplied, let its type override the WSDL
5194          if (is_object($value) && get_class($value) == 'soapval') {
5195              if ($value->type_ns) {
5196                  $type = $value->type_ns . ':' . $value->type;
5197                  $forceType = true;
5198                  $this->debug("in serializeType: soapval overrides type to $type");
5199              } elseif ($value->type) {
5200                  $type = $value->type;
5201                  $forceType = true;
5202                  $this->debug("in serializeType: soapval overrides type to $type");
5203              } else {
5204                  $forceType = false;
5205                  $this->debug("in serializeType: soapval does not override type");
5206              }
5207              $attrs = $value->attributes;
5208              $value = $value->value;
5209              $this->debug("in serializeType: soapval overrides value to $value");
5210              if ($attrs) {
5211                  if (!is_array($value)) {
5212                      $value['!'] = $value;
5213                  }
5214                  foreach ($attrs as $n => $v) {
5215                      $value['!' . $n] = $v;
5216                  }
5217                  $this->debug("in serializeType: soapval provides attributes");
5218              }
5219          } else {
5220              $forceType = false;
5221          }
5222  
5223          $xml = '';
5224          if (strpos($type, ':')) {
5225              $uqType = substr($type, strrpos($type, ':') + 1);
5226              $ns = substr($type, 0, strrpos($type, ':'));
5227              $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
5228              if ($this->getNamespaceFromPrefix($ns)) {
5229                  $ns = $this->getNamespaceFromPrefix($ns);
5230                  $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
5231              }
5232  
5233              if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
5234                  $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
5235                  if ($unqualified  && $use == 'literal') {
5236                      $elementNS = " xmlns=\"\"";
5237                  } else {
5238                      $elementNS = '';
5239                  }
5240                  if (is_null($value)) {
5241                      if ($use == 'literal') {
5242                          // TODO: depends on minOccurs
5243                          $xml = "<$name$elementNS/>";
5244                      } else {
5245                          // TODO: depends on nillable, which should be checked before calling this method
5246                          $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5247                      }
5248                      $this->debug("in serializeType: returning: $xml");
5249                      return $xml;
5250                  }
5251                  if ($uqType == 'boolean') {
5252                      if ((is_string($value) && $value == 'false') || (! $value)) {
5253                          $value = 'false';
5254                      } else {
5255                          $value = 'true';
5256                      }
5257                  } 
5258                  if ($uqType == 'string' && gettype($value) == 'string') {
5259                      $value = $this->expandEntities($value);
5260                  }
5261                  if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
5262                      $value = sprintf("%.0lf", $value);
5263                  }
5264                  // it's a scalar
5265                  // TODO: what about null/nil values?
5266                  // check type isn't a custom type extending xmlschema namespace
5267                  if (!$this->getTypeDef($uqType, $ns)) {
5268                      if ($use == 'literal') {
5269                          if ($forceType) {
5270                              $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5271                          } else {
5272                              $xml = "<$name$elementNS>$value</$name>";
5273                          }
5274                      } else {
5275                          $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5276                      }
5277                      $this->debug("in serializeType: returning: $xml");
5278                      return $xml;
5279                  }
5280                  $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
5281              } else if ($ns == 'http://xml.apache.org/xml-soap') {
5282                  $this->debug('in serializeType: appears to be Apache SOAP type');
5283                  if ($uqType == 'Map') {
5284                      $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5285                      if (! $tt_prefix) {
5286                          $this->debug('in serializeType: Add namespace for Apache SOAP type');
5287                          $tt_prefix = 'ns' . rand(1000, 9999);
5288                          $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
5289                          // force this to be added to usedNamespaces
5290                          $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
5291                      }
5292                      $contents = '';
5293                      foreach($value as $k => $v) {
5294                          $this->debug("serializing map element: key $k, value $v");
5295                          $contents .= '<item>';
5296                          $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
5297                          $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
5298                          $contents .= '</item>';
5299                      }
5300                      if ($use == 'literal') {
5301                          if ($forceType) {
5302                              $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
5303                          } else {
5304                              $xml = "<$name>$contents</$name>";
5305                          }
5306                      } else {
5307                          $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
5308                      }
5309                      $this->debug("in serializeType: returning: $xml");
5310                      return $xml;
5311                  }
5312                  $this->debug('in serializeType: Apache SOAP type, but only support Map');
5313              }
5314          } else {
5315              // TODO: should the type be compared to types in XSD, and the namespace
5316              // set to XSD if the type matches?
5317              $this->debug("in serializeType: No namespace for type $type");
5318              $ns = '';
5319              $uqType = $type;
5320          }
5321          if(!$typeDef = $this->getTypeDef($uqType, $ns)){
5322              $this->setError("$type ($uqType) is not a supported type.");
5323              $this->debug("in serializeType: $type ($uqType) is not a supported type.");
5324              return false;
5325          } else {
5326              $this->debug("in serializeType: found typeDef");
5327              $this->appendDebug('typeDef=' . $this->varDump($typeDef));
5328          }
5329          $phpType = $typeDef['phpType'];
5330          $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 
5331          // if php type == struct, map value to the <all> element names
5332          if ($phpType == 'struct') {
5333              if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
5334                  $elementName = $uqType;
5335                  if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5336                      $elementNS = " xmlns=\"$ns\"";
5337                  } else {
5338                      $elementNS = " xmlns=\"\"";
5339                  }
5340              } else {
5341                  $elementName = $name;
5342                  if ($unqualified) {
5343                      $elementNS = " xmlns=\"\"";
5344                  } else {
5345                      $elementNS = '';
5346                  }
5347              }
5348              if (is_null($value)) {
5349                  if ($use == 'literal') {
5350                      // TODO: depends on minOccurs
5351                      $xml = "<$elementName$elementNS/>";
5352                  } else {
5353                      $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
5354                  }
5355                  $this->debug("in serializeType: returning: $xml");
5356                  return $xml;
5357              }
5358              if (is_object($value)) {
5359                  $value = get_object_vars($value);
5360              }
5361              if (is_array($value)) {
5362                  $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
5363                  if ($use == 'literal') {
5364                      if ($forceType) {
5365                          $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
5366                      } else {
5367                          $xml = "<$elementName$elementNS$elementAttrs>";
5368                      }
5369                  } else {
5370                      $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
5371                  }
5372      
5373                  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
5374                  $xml .= "</$elementName>";
5375              } else {
5376                  $this->debug("in serializeType: phpType is struct, but value is not an array");
5377                  $this->setError("phpType is struct, but value is not an array: see debug output for details");
5378                  $xml = '';
5379              }
5380          } elseif ($phpType == 'array') {
5381              if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5382                  $elementNS = " xmlns=\"$ns\"";
5383              } else {
5384                  if ($unqualified) {
5385                      $elementNS = " xmlns=\"\"";
5386                  } else {
5387                      $elementNS = '';
5388                  }
5389              }
5390              if (is_null($value)) {
5391                  if ($use == 'literal') {
5392                      // TODO: depends on minOccurs
5393                      $xml = "<$name$elementNS/>";
5394                  } else {
5395                      $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
5396                          $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5397                          ":Array\" " .
5398                          $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
5399                          ':arrayType="' .
5400                          $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
5401                          ':' .
5402                          $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
5403                  }
5404                  $this->debug("in serializeType: returning: $xml");
5405                  return $xml;
5406              }
5407              if (isset($typeDef['multidimensional'])) {
5408                  $nv = array();
5409                  foreach($value as $v) {
5410                      $cols = ',' . sizeof($v);
5411                      $nv = array_merge($nv, $v);
5412                  } 
5413                  $value = $nv;
5414              } else {
5415                  $cols = '';
5416              } 
5417              if (is_array($value) && sizeof($value) >= 1) {
5418                  $rows = sizeof($value);
5419                  $contents = '';
5420                  foreach($value as $k => $v) {
5421                      $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
5422                      //if (strpos($typeDef['arrayType'], ':') ) {
5423                      if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
5424                          $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
5425                      } else {
5426                          $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
5427                      } 
5428                  }
5429              } else {
5430                  $rows = 0;
5431                  $contents = null;
5432              }
5433              // TODO: for now, an empty value will be serialized as a zero element
5434              // array.  Revisit this when coding the handling of null/nil values.
5435              if ($use == 'literal') {
5436                  $xml = "<$name$elementNS>"
5437                      .$contents
5438                      ."</$name>";
5439              } else {
5440                  $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
5441                      $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
5442                      .':arrayType="'
5443                      .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
5444                      .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
5445                      .$contents
5446                      ."</$name>";
5447              }
5448          } elseif ($phpType == 'scalar') {
5449              if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
5450                  $elementNS = " xmlns=\"$ns\"";
5451              } else {
5452                  if ($unqualified) {
5453                      $elementNS = " xmlns=\"\"";
5454                  } else {
5455                      $elementNS = '';
5456                  }
5457              }
5458              if ($use == 'literal') {
5459                  if ($forceType) {
5460                      $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
5461                  } else {
5462                      $xml = "<$name$elementNS>$value</$name>";
5463                  }
5464              } else {
5465                  $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
5466              }
5467          }
5468          $this->debug("in serializeType: returning: $xml");
5469          return $xml;
5470      }
5471      
5472      /**
5473       * serializes the attributes for a complexType
5474       *
5475       * @param array $typeDef our internal representation of an XML schema type (or element)
5476       * @param mixed $value a native PHP value (parameter value)
5477       * @param string $ns the namespace of the type
5478       * @param string $uqType the local part of the type
5479       * @return string value serialized as an XML string
5480       * @access private
5481       */
5482  	function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
5483          $xml = '';
5484          if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
5485              $this->debug("serialize attributes for XML Schema type $ns:$uqType");
5486              if (is_array($value)) {
5487                  $xvalue = $value;
5488              } elseif (is_object($value)) {
5489                  $xvalue = get_object_vars($value);
5490              } else {
5491                  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
5492                  $xvalue = array();
5493              }
5494              foreach ($typeDef['attrs'] as $aName => $attrs) {
5495                  if (isset($xvalue['!' . $aName])) {
5496                      $xname = '!' . $aName;
5497                      $this->debug("value provided for attribute $aName with key $xname");
5498                  } elseif (isset($xvalue[$aName])) {
5499                      $xname = $aName;
5500                      $this->debug("value provided for attribute $aName with key $xname");
5501                  } elseif (isset($attrs['default'])) {
5502                      $xname = '!' . $aName;
5503                      $xvalue[$xname] = $attrs['default'];
5504                      $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
5505                  } else {
5506                      $xname = '';
5507                      $this->debug("no value provided for attribute $aName");
5508                  }
5509                  if ($xname) {
5510                      $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
5511                  }
5512              } 
5513          } else {
5514              $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
5515          }
5516          if (isset($typeDef['extensionBase'])) {
5517              $ns = $this->getPrefix($typeDef['extensionBase']);
5518              $uqType = $this->getLocalPart($typeDef['extensionBase']);
5519              if ($this->getNamespaceFromPrefix($ns)) {
5520                  $ns = $this->getNamespaceFromPrefix($ns);
5521              }
5522              if ($typeDef = $this->getTypeDef($uqType, $ns)) {
5523                  $this->debug("serialize attributes for extension base $ns:$uqType");
5524                  $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
5525              } else {
5526                  $this->debug("extension base $ns:$uqType is not a supported type");
5527              }
5528          }
5529          return $xml;
5530      }
5531  
5532      /**
5533       * serializes the elements for a complexType
5534       *
5535       * @param array $typeDef our internal representation of an XML schema type (or element)
5536       * @param mixed $value a native PHP value (parameter value)
5537       * @param string $ns the namespace of the type
5538       * @param string $uqType the local part of the type
5539       * @param string $use use for part (encoded|literal)
5540       * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
5541       * @return string value serialized as an XML string
5542       * @access private
5543       */
5544  	function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
5545          $xml = '';
5546          if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
5547              $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
5548              if (is_array($value)) {
5549                  $xvalue = $value;
5550              } elseif (is_object($value)) {
5551                  $xvalue = get_object_vars($value);
5552              } else {
5553                  $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
5554                  $xvalue = array();
5555              }
5556              // toggle whether all elements are present - ideally should validate against schema
5557              if (count($typeDef['elements']) != count($xvalue)){
5558                  $optionals = true;
5559              }
5560              foreach ($typeDef['elements'] as $eName => $attrs) {
5561                  if (!isset($xvalue[$eName])) {
5562                      if (isset($attrs['default'])) {
5563                          $xvalue[$eName] = $attrs['default'];
5564                          $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
5565                      }
5566                  }
5567                  // if user took advantage of a minOccurs=0, then only serialize named parameters
5568                  if (isset($optionals)
5569                      && (!isset($xvalue[$eName])) 
5570                      && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
5571                      ){
5572                      if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
5573                          $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
5574                      }
5575                      // do nothing
5576                      $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
5577                  } else {
5578                      // get value
5579                      if (isset($xvalue[$eName])) {
5580                          $v = $xvalue[$eName];
5581                      } else {
5582                          $v = null;
5583                      }
5584                      if (isset($attrs['form'])) {
5585                          $unqualified = ($attrs['form'] == 'unqualified');
5586                      } else {
5587                          $unqualified = false;
5588                      }
5589                      if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
5590                          $vv = $v;
5591                          foreach ($vv as $k => $v) {
5592                              if (isset($attrs['type']) || isset($attrs['ref'])) {
5593                                  // serialize schema-defined type
5594                                  $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
5595                              } else {
5596                                  // serialize generic type (can this ever really happen?)
5597                                  $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
5598                                  $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
5599                              }
5600                          }
5601                      } else {
5602                          if (isset($attrs['type']) || isset($attrs['ref'])) {
5603                              // serialize schema-defined type
5604                              $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
5605                          } else {
5606                              // serialize generic type (can this ever really happen?)
5607                              $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
5608                              $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
5609                          }
5610                      }
5611                  }
5612              } 
5613          } else {
5614              $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
5615          }
5616          if (isset($typeDef['extensionBase'])) {
5617              $ns = $this->getPrefix($typeDef['extensionBase']);
5618              $uqType = $this->getLocalPart($typeDef['extensionBase']);
5619              if ($this->getNamespaceFromPrefix($ns)) {
5620                  $ns = $this->getNamespaceFromPrefix($ns);
5621              }
5622              if ($typeDef = $this->getTypeDef($uqType, $ns)) {
5623                  $this->debug("serialize elements for extension base $ns:$uqType");
5624                  $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
5625              } else {
5626                  $this->debug("extension base $ns:$uqType is not a supported type");
5627              }
5628          }
5629          return $xml;
5630      }
5631  
5632      /**
5633      * adds an XML Schema complex type to the WSDL types
5634      *
5635      * @param string    name
5636      * @param string typeClass (complexType|simpleType|attribute)
5637      * @param string phpType: currently supported are array and struct (php assoc array)
5638      * @param string compositor (all|sequence|choice)
5639      * @param string restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
5640      * @param array elements = array ( name => array(name=>'',type=>'') )
5641      * @param array attrs =     array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
5642      * @param string arrayType: namespace:name (xsd:string)
5643      * @see xmlschema
5644      * @access public
5645      */
5646  	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
5647          if (count($elements) > 0) {
5648              foreach($elements as $n => $e){
5649                  // expand each element
5650                  foreach ($e as $k => $v) {
5651                      $k = strpos($k,':') ? $this->expandQname($k) : $k;
5652                      $v = strpos($v,':') ? $this->expandQname($v) : $v;
5653                      $ee[$k] = $v;
5654                  }
5655                  $eElements[$n] = $ee;
5656              }
5657              $elements = $eElements;
5658          }
5659          
5660          if (count($attrs) > 0) {
5661              foreach($attrs as $n => $a){
5662                  // expand each attribute
5663                  foreach ($a as $k => $v) {
5664                      $k = strpos($k,':') ? $this->expandQname($k) : $k;
5665                      $v = strpos($v,':') ? $this->expandQname($v) : $v;
5666                      $aa[$k] = $v;
5667                  }
5668                  $eAttrs[$n] = $aa;
5669              }
5670              $attrs = $eAttrs;
5671          }
5672  
5673          $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
5674          $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
5675  
5676          $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
5677          $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
5678      }
5679  
5680      /**
5681      * adds an XML Schema simple type to the WSDL types
5682      *
5683      * @param string $name
5684      * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
5685      * @param string $typeClass (should always be simpleType)
5686      * @param string $phpType (should always be scalar)
5687      * @param array $enumeration array of values
5688      * @see xmlschema
5689      * @access public
5690      */
5691  	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
5692          $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
5693  
5694          $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
5695          $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
5696      }
5697  
5698      /**
5699      * adds an element to the WSDL types
5700      *
5701      * @param array $attrs attributes that must include name and type
5702      * @see xmlschema
5703      * @access public
5704      */
5705  	function addElement($attrs) {
5706          $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
5707          $this->schemas[$typens][0]->addElement($attrs);
5708      }
5709  
5710      /**
5711      * register an operation with the server
5712      * 
5713      * @param string $name operation (method) name
5714      * @param array $in assoc array of input values: key = param name, value = param type
5715      * @param array $out assoc array of output values: key = param name, value = param type
5716      * @param string $namespace optional The namespace for the operation
5717      * @param string $soapaction optional The soapaction for the operation
5718      * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically
5719      * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
5720      * @param string $documentation optional The description to include in the WSDL
5721      * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
5722      * @access public 
5723      */
5724  	function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
5725          if ($use == 'encoded' && $encodingStyle == '') {
5726              $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5727          }
5728  
5729          if ($style == 'document') {
5730              $elements = array();
5731              foreach ($in as $n => $t) {
5732                  $elements[$n] = array('name' => $n, 'type' => $t);
5733              }
5734              $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
5735              $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
5736              $in = array('parameters' => 'tns:' . $name);
5737  
5738              $elements = array();
5739              foreach ($out as $n => $t) {
5740                  $elements[$n] = array('name' => $n, 'type' => $t);
5741              }
5742              $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
5743              $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType'));
5744              $out = array('parameters' => 'tns:' . $name . 'Response');
5745          }
5746  
5747          // get binding
5748          $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
5749          array(
5750          'name' => $name,
5751          'binding' => $this->serviceName . 'Binding',
5752          'endpoint' => $this->endpoint,
5753          'soapAction' => $soapaction,
5754          'style' => $style,
5755          'input' => array(
5756              'use' => $use,
5757              'namespace' => $namespace,
5758              'encodingStyle' => $encodingStyle,
5759              'message' => $name . 'Request',
5760              'parts' => $in),
5761          'output' => array(
5762              'use' => $use,
5763              'namespace' => $namespace,
5764              'encodingStyle' => $encodingStyle,
5765              'message' => $name . 'Response',
5766              'parts' => $out),
5767          'namespace' => $namespace,
5768          'transport' => 'http://schemas.xmlsoap.org/soap/http',
5769          'documentation' => $documentation); 
5770          // add portTypes
5771          // add messages
5772          if($in)
5773          {
5774              foreach($in as $pName => $pType)
5775              {
5776                  if(strpos($pType,':')) {
5777                      $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
5778                  }
5779                  $this->messages[$name.'Request'][$pName] = $pType;
5780              }
5781          } else {
5782              $this->messages[$name.'Request']= '0';
5783          }
5784          if($out)
5785          {
5786              foreach($out as $pName => $pType)
5787              {
5788                  if(strpos($pType,':')) {
5789                      $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
5790                  }
5791                  $this->messages[$name.'Response'][$pName] = $pType;
5792              }
5793          } else {
5794              $this->messages[$name.'Response']= '0';
5795          }
5796          return true;
5797      } 
5798  }
5799  ?><?php
5800  
5801  
5802  
5803  /**
5804  *
5805  * soap_parser class parses SOAP XML messages into native PHP values
5806  *
5807  * @author   Dietrich Ayala <dietrich@ganx4.com>
5808  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
5809  * @access   public
5810  */
5811  class soap_parser extends nusoap_base {
5812  
5813      var $xml = '';
5814      var $xml_encoding = '';
5815      var $method = '';
5816      var $root_struct = '';
5817      var $root_struct_name = '';
5818      var $root_struct_namespace = '';
5819      var $root_header = '';
5820      var $document = '';            // incoming SOAP body (text)
5821      // determines where in the message we are (envelope,header,body,method)
5822      var $status = '';
5823      var $position = 0;
5824      var $depth = 0;
5825      var $default_namespace = '';
5826      var $namespaces = array();
5827      var $message = array();
5828      var $parent = '';
5829      var $fault = false;
5830      var $fault_code = '';
5831      var $fault_str = '';
5832      var $fault_detail = '';
5833      var $depth_array = array();
5834      var $debug_flag = true;
5835      var $soapresponse = NULL;
5836      var $responseHeaders = '';    // incoming SOAP headers (text)
5837      var $body_position = 0;
5838      // for multiref parsing:
5839      // array of id => pos
5840      var $ids = array();
5841      // array of id => hrefs => pos
5842      var $multirefs = array();
5843      // toggle for auto-decoding element content
5844      var $decode_utf8 = true;
5845  
5846      /**
5847      * constructor that actually does the parsing
5848      *
5849      * @param    string $xml SOAP message
5850      * @param    string $encoding character encoding scheme of message
5851      * @param    string $method method for which XML is parsed (unused?)
5852      * @param    string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
5853      * @access   public
5854      */
5855  	function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
5856          parent::nusoap_base();
5857          $this->xml = $xml;
5858          $this->xml_encoding = $encoding;
5859          $this->method = $method;
5860          $this->decode_utf8 = $decode_utf8;
5861  
5862          // Check whether content has been read.
5863          if(!empty($xml)){
5864              // Check XML encoding
5865              $pos_xml = strpos($xml, '<?xml');
5866              if ($pos_xml !== FALSE) {
5867                  $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
5868                  if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
5869                      $xml_encoding = $res[1];
5870                      if (strtoupper($xml_encoding) != $encoding) {
5871                          $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
5872                          $this->debug($err);
5873                          if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
5874                              $this->setError($err);
5875                              return;
5876                          }
5877                          // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
5878                      } else {
5879                          $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
5880                      }
5881                  } else {
5882                      $this->debug('No encoding specified in XML declaration');
5883                  }
5884              } else {
5885                  $this->debug('No XML declaration');
5886              }
5887              $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding);
5888              // Create an XML parser - why not xml_parser_create_ns?
5889              $this->parser = xml_parser_create($this->xml_encoding);
5890              // Set the options for parsing the XML data.
5891              //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
5892              xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
5893              xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
5894              // Set the object for the parser.
5895              xml_set_object($this->parser, $this);
5896              // Set the element handlers for the parser.
5897              xml_set_element_handler($this->parser, 'start_element','end_element');
5898              xml_set_character_data_handler($this->parser,'character_data');
5899  
5900              // Parse the XML file.
5901              if(!xml_parse($this->parser,$xml,true)){
5902                  // Display an error message.
5903                  $err = sprintf('XML error parsing SOAP payload on line %d: %s',
5904                  xml_get_current_line_number($this->parser),
5905                  xml_error_string(xml_get_error_code($this->parser)));
5906                  $this->debug($err);
5907                  $this->debug("XML payload:\n" . $xml);
5908                  $this->setError($err);
5909              } else {
5910                  $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
5911                  // get final value
5912                  $this->soapresponse = $this->message[$this->root_struct]['result'];
5913                  // get header value: no, because this is documented as XML string
5914  //                if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
5915  //                    $this->responseHeaders = $this->message[$this->root_header]['result'];
5916  //                }
5917                  // resolve hrefs/ids
5918                  if(sizeof($this->multirefs) > 0){
5919                      foreach($this->multirefs as $id => $hrefs){
5920                          $this->debug('resolving multirefs for id: '.$id);
5921                          $idVal = $this->buildVal($this->ids[$id]);
5922                          if (is_array($idVal) && isset($idVal['!id'])) {
5923                              unset($idVal['!id']);
5924                          }
5925                          foreach($hrefs as $refPos => $ref){
5926                              $this->debug('resolving href at pos '.$refPos);
5927                              $this->multirefs[$id][$refPos] = $idVal;
5928                          }
5929                      }
5930                  }
5931              }
5932              xml_parser_free($this->parser);
5933          } else {
5934              $this->debug('xml was empty, didn\'t parse!');
5935              $this->setError('xml was empty, didn\'t parse!');
5936          }
5937      }
5938  
5939      /**
5940      * start-element handler
5941      *
5942      * @param    resource $parser XML parser object
5943      * @param    string $name element name
5944      * @param    array $attrs associative array of attributes
5945      * @access   private
5946      */
5947  	function start_element($parser, $name, $attrs) {
5948          // position in a total number of elements, starting from 0
5949          // update class level pos
5950          $pos = $this->position++;
5951          // and set mine
5952          $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
5953          // depth = how many levels removed from root?
5954          // set mine as current global depth and increment global depth value
5955          $this->message[$pos]['depth'] = $this->depth++;
5956  
5957          // else add self as child to whoever the current parent is
5958          if($pos != 0){
5959              $this->message[$this->parent]['children'] .= '|'.$pos;
5960          }
5961          // set my parent
5962          $this->message[$pos]['parent'] = $this->parent;
5963          // set self as current parent
5964          $this->parent = $pos;
5965          // set self as current value for this depth
5966          $this->depth_array[$this->depth] = $pos;
5967          // get element prefix
5968          if(strpos($name,':')){
5969              // get ns prefix
5970              $prefix = substr($name,0,strpos($name,':'));
5971              // get unqualified name
5972              $name = substr(strstr($name,':'),1);
5973          }
5974          // set status
5975          if($name == 'Envelope'){
5976              $this->status = 'envelope';
5977          } elseif($name == 'Header'){
5978              $this->root_header = $pos;
5979              $this->status = 'header';
5980          } elseif($name == 'Body'){
5981              $this->status = 'body';
5982              $this->body_position = $pos;
5983          // set method
5984          } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
5985              $this->status = 'method';
5986              $this->root_struct_name = $name;
5987              $this->root_struct = $pos;
5988              $this->message[$pos]['type'] = 'struct';
5989              $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
5990          }
5991          // set my status
5992          $this->message[$pos]['status'] = $this->status;
5993          // set name
5994          $this->message[$pos]['name'] = htmlspecialchars($name);
5995          // set attrs
5996          $this->message[$pos]['attrs'] = $attrs;
5997  
5998          // loop through atts, logging ns and type declarations
5999          $attstr = '';
6000          foreach($attrs as $key => $value){
6001              $key_prefix = $this->getPrefix($key);
6002              $key_localpart = $this->getLocalPart($key);
6003              // if ns declarations, add to class level array of valid namespaces
6004              if($key_prefix == 'xmlns'){
6005                  if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
6006                      $this->XMLSchemaVersion = $value;
6007                      $this->namespaces['xsd'] = $this->XMLSchemaVersion;
6008                      $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
6009                  }
6010                  $this->namespaces[$key_localpart] = $value;
6011                  // set method namespace
6012                  if($name == $this->root_struct_name){
6013                      $this->methodNamespace = $value;
6014                  }
6015              // if it's a type declaration, set type
6016              } elseif($key_localpart == 'type'){
6017                  $value_prefix = $this->getPrefix($value);
6018                  $value_localpart = $this->getLocalPart($value);
6019                  $this->message[$pos]['type'] = $value_localpart;
6020                  $this->message[$pos]['typePrefix'] = $value_prefix;
6021                  if(isset($this->namespaces[$value_prefix])){
6022                      $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
6023                  } else if(isset($attrs['xmlns:'.$value_prefix])) {
6024                      $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
6025                  }
6026                  // should do something here with the namespace of specified type?
6027              } elseif($key_localpart == 'arrayType'){
6028                  $this->message[$pos]['type'] = 'array';
6029                  /* do arrayType ereg here
6030                  [1]    arrayTypeValue    ::=    atype asize
6031                  [2]    atype    ::=    QName rank*
6032                  [3]    rank    ::=    '[' (',')* ']'
6033                  [4]    asize    ::=    '[' length~ ']'
6034                  [5]    length    ::=    nextDimension* Digit+
6035                  [6]    nextDimension    ::=    Digit+ ','
6036                  */
6037                  $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
6038                  if(ereg($expr,$value,$regs)){
6039                      $this->message[$pos]['typePrefix'] = $regs[1];
6040                      $this->message[$pos]['arrayTypePrefix'] = $regs[1];
6041                      if (isset($this->namespaces[$regs[1]])) {
6042                          $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
6043                      } else if (isset($attrs['xmlns:'.$regs[1]])) {
6044                          $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
6045                      }
6046                      $this->message[$pos]['arrayType'] = $regs[2];
6047                      $this->message[$pos]['arraySize'] = $regs[3];
6048                      $this->message[$pos]['arrayCols'] = $regs[4];
6049                  }
6050              // specifies nil value (or not)
6051              } elseif ($key_localpart == 'nil'){
6052                  $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
6053              // some other attribute
6054              } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
6055                  $this->message[$pos]['xattrs']['!' . $key] = $value;
6056              }
6057  
6058              if ($key == 'xmlns') {
6059                  $this->default_namespace = $value;
6060              }
6061              // log id
6062              if($key == 'id'){
6063                  $this->ids[$value] = $pos;
6064              }
6065              // root
6066              if($key_localpart == 'root' && $value == 1){
6067                  $this->status = 'method';
6068                  $this->root_struct_name = $name;
6069                  $this->root_struct = $pos;
6070                  $this->debug("found root struct $this->root_struct_name, pos $pos");
6071              }
6072              // for doclit
6073              $attstr .= " $key=\"$value\"";
6074          }
6075          // get namespace - must be done after namespace atts are processed
6076          if(isset($prefix)){
6077              $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
6078              $this->default_namespace = $this->namespaces[$prefix];
6079          } else {
6080              $this->message[$pos]['namespace'] = $this->default_namespace;
6081          }
6082          if($this->status == 'header'){
6083              if ($this->root_header != $pos) {
6084                  $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6085              }
6086          } elseif($this->root_struct_name != ''){
6087              $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
6088          }
6089      }
6090  
6091      /**
6092      * end-element handler
6093      *
6094      * @param    resource $parser XML parser object
6095      * @param    string $name element name
6096      * @access   private
6097      */
6098  	function end_element($parser, $name) {
6099          // position of current element is equal to the last value left in depth_array for my depth
6100          $pos = $this->depth_array[$this->depth--];
6101  
6102          // get element prefix
6103          if(strpos($name,':')){
6104              // get ns prefix
6105              $prefix = substr($name,0,strpos($name,':'));
6106              // get unqualified name
6107              $name = substr(strstr($name,':'),1);
6108          }
6109          
6110          // build to native type
6111          if(isset($this->body_position) && $pos > $this->body_position){
6112              // deal w/ multirefs
6113              if(isset($this->message[$pos]['attrs']['href'])){
6114                  // get id
6115                  $id = substr($this->message[$pos]['attrs']['href'],1);
6116                  // add placeholder to href array
6117                  $this->multirefs[$id][$pos] = 'placeholder';
6118                  // add set a reference to it as the result value
6119                  $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
6120              // build complexType values
6121              } elseif($this->message[$pos]['children'] != ''){
6122                  // if result has already been generated (struct/array)
6123                  if(!isset($this->message[$pos]['result'])){
6124                      $this->message[$pos]['result'] = $this->buildVal($pos);
6125                  }
6126              // build complexType values of attributes and possibly simpleContent
6127              } elseif (isset($this->message[$pos]['xattrs'])) {
6128                  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6129                      $this->message[$pos]['xattrs']['!'] = null;
6130                  } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6131                      if (isset($this->message[$pos]['type'])) {
6132                          $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6133                      } else {
6134                          $parent = $this->message[$pos]['parent'];
6135                          if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6136                              $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6137                          } else {
6138                              $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
6139                          }
6140                      }
6141                  }
6142                  $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
6143              // set value of simpleType (or nil complexType)
6144              } else {
6145                  //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
6146                  if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
6147                      $this->message[$pos]['xattrs']['!'] = null;
6148                  } elseif (isset($this->message[$pos]['type'])) {
6149                      $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6150                  } else {
6151                      $parent = $this->message[$pos]['parent'];
6152                      if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6153                          $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6154                      } else {
6155                          $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
6156                      }
6157                  }
6158  
6159                  /* add value to parent's result, if parent is struct/array
6160                  $parent = $this->message[$pos]['parent'];
6161                  if($this->message[$parent]['type'] != 'map'){
6162                      if(strtolower($this->message[$parent]['type']) == 'array'){
6163                          $this->message[$parent]['result'][] = $this->message[$pos]['result'];
6164                      } else {
6165                          $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
6166                      }
6167                  }
6168                  */
6169              }
6170          }
6171          
6172          // for doclit
6173          if($this->status == 'header'){
6174              if ($this->root_header != $pos) {
6175                  $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6176              }
6177          } elseif($pos >= $this->root_struct){
6178              $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
6179          }
6180          // switch status
6181          if($pos == $this->root_struct){
6182              $this->status = 'body';
6183              $this->root_struct_namespace = $this->message[$pos]['namespace'];
6184          } elseif($name == 'Body'){
6185              $this->status = 'envelope';
6186           } elseif($name == 'Header'){
6187              $this->status = 'envelope';
6188          } elseif($name == 'Envelope'){
6189              //
6190          }
6191          // set parent back to my parent
6192          $this->parent = $this->message[$pos]['parent'];
6193      }
6194  
6195      /**
6196      * element content handler
6197      *
6198      * @param    resource $parser XML parser object
6199      * @param    string $data element content
6200      * @access   private
6201      */
6202  	function character_data($parser, $data){
6203          $pos = $this->depth_array[$this->depth];
6204          if ($this->xml_encoding=='UTF-8'){
6205              // TODO: add an option to disable this for folks who want
6206              // raw UTF-8 that, e.g., might not map to iso-8859-1
6207              // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
6208              if($this->decode_utf8){
6209                  $data = utf8_decode($data);
6210              }
6211          }
6212          $this->message[$pos]['cdata'] .= $data;
6213          // for doclit
6214          if($this->status == 'header'){
6215              $this->responseHeaders .= $data;
6216          } else {
6217              $this->document .= $data;
6218          }
6219      }
6220  
6221      /**
6222      * get the parsed message
6223      *
6224      * @return    mixed
6225      * @access   public
6226      */
6227  	function get_response(){
6228          return $this->soapresponse;
6229      }
6230  
6231      /**
6232      * get the parsed headers
6233      *
6234      * @return    string XML or empty if no headers
6235      * @access   public
6236      */
6237  	function getHeaders(){
6238          return $this->responseHeaders;
6239      }
6240  
6241      /**
6242      * decodes simple types into PHP variables
6243      *
6244      * @param    string $value value to decode
6245      * @param    string $type XML type to decode
6246      * @param    string $typens XML type namespace to decode
6247      * @return    mixed PHP value
6248      * @access   private
6249      */
6250  	function decodeSimple($value, $type, $typens) {
6251          // TODO: use the namespace!
6252          if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
6253              return (string) $value;
6254          }
6255          if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
6256              return (int) $value;
6257          }
6258          if ($type == 'float' || $type == 'double' || $type == 'decimal') {
6259              return (double) $value;
6260          }
6261          if ($type == 'boolean') {
6262              if (strtolower($value) == 'false' || strtolower($value) == 'f') {
6263                  return false;
6264              }
6265              return (boolean) $value;
6266          }
6267          if ($type == 'base64' || $type == 'base64Binary') {
6268              $this->debug('Decode base64 value');
6269              return base64_decode($value);
6270          }
6271          // obscure numeric types
6272          if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
6273              || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
6274              || $type == 'unsignedInt'
6275              || $type == 'unsignedShort' || $type == 'unsignedByte') {
6276              return (int) $value;
6277          }
6278          // bogus: parser treats array with no elements as a simple type
6279          if ($type == 'array') {
6280              return array();
6281          }
6282          // everything else
6283          return (string) $value;
6284      }
6285  
6286      /**
6287      * builds response structures for compound values (arrays/structs)
6288      * and scalars
6289      *
6290      * @param    integer $pos position in node tree
6291      * @return    mixed    PHP value
6292      * @access   private
6293      */
6294  	function buildVal($pos){
6295          if(!isset($this->message[$pos]['type'])){
6296              $this->message[$pos]['type'] = '';
6297          }
6298          $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
6299          // if there are children...
6300          if($this->message[$pos]['children'] != ''){
6301              $this->debug('in buildVal, there are children');
6302              $children = explode('|',$this->message[$pos]['children']);
6303              array_shift($children); // knock off empty
6304              // md array
6305              if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
6306                  $r=0; // rowcount
6307                  $c=0; // colcount
6308                  foreach($children as $child_pos){
6309                      $this->debug("in buildVal, got an MD array element: $r, $c");
6310                      $params[$r][] = $this->message[$child_pos]['result'];
6311                      $c++;
6312                      if($c == $this->message[$pos]['arrayCols']){
6313                          $c = 0;
6314                          $r++;
6315                      }
6316                  }
6317              // array
6318              } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
6319                  $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
6320                  foreach($children as $child_pos){
6321                      $params[] = &$this->message[$child_pos]['result'];
6322                  }
6323              // apache Map type: java hashtable
6324              } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
6325                  $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
6326                  foreach($children as $child_pos){
6327                      $kv = explode("|",$this->message[$child_pos]['children']);
6328                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
6329                  }
6330              // generic compound type
6331              //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
6332              } else {
6333                  // Apache Vector type: treat as an array
6334                  $this->debug('in buildVal, adding Java Vector '.$this->message[$pos]['name']);
6335                  if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
6336                      $notstruct = 1;
6337                  } else {
6338                      $notstruct = 0;
6339                  }
6340                  //
6341                  foreach($children as $child_pos){
6342                      if($notstruct){
6343                          $params[] = &$this->message[$child_pos]['result'];
6344                      } else {
6345                          if (isset($params[$this->message[$child_pos]['name']])) {
6346                              // de-serialize repeated element name into an array
6347                              if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
6348                                  $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
6349                              }
6350                              $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
6351                          } else {
6352                              $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
6353                          }
6354                      }
6355                  }
6356              }
6357              if (isset($this->message[$pos]['xattrs'])) {
6358                  $this->debug('in buildVal, handling attributes');
6359                  foreach ($this->message[$pos]['xattrs'] as $n => $v) {
6360                      $params[$n] = $v;
6361                  }
6362              }
6363              // handle simpleContent
6364              if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
6365                  $this->debug('in buildVal, handling simpleContent');
6366                  if (isset($this->message[$pos]['type'])) {
6367                      $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6368                  } else {
6369                      $parent = $this->message[$pos]['parent'];
6370                      if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6371                          $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6372                      } else {
6373                          $params['!'] = $this->message[$pos]['cdata'];
6374                      }
6375                  }
6376              }
6377              return is_array($params) ? $params : array();
6378          } else {
6379              $this->debug('in buildVal, no children, building scalar');
6380              $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
6381              if (isset($this->message[$pos]['type'])) {
6382                  return $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
6383              }
6384              $parent = $this->message[$pos]['parent'];
6385              if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
6386                  return $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
6387              }
6388                 return $this->message[$pos]['cdata'];
6389          }
6390      }
6391  }
6392  
6393  
6394  
6395  ?><?php
6396  
6397  
6398  
6399  /**
6400  *
6401  * soapclient2 higher level class for easy usage.
6402  *
6403  * usage:
6404  *
6405  * // instantiate client with server info
6406  * $soapclient2 = new soapclient2( string path [ ,boolean wsdl] );
6407  *
6408  * // call method, get results
6409  * echo $soapclient2->call( string methodname [ ,array parameters] );
6410  *
6411  * // bye bye client
6412  * unset($soapclient2);
6413  *
6414  * @author   Dietrich Ayala <dietrich@ganx4.com>
6415  * @version  $Id: nusoap.php,v 1.94 2005/08/04 01:27:42 snichol Exp $
6416  * @access   public
6417  */
6418  class soapclient2 extends nusoap_base  {
6419  
6420      var $username = '';
6421      var $password = '';
6422      var $authtype = '';
6423      var $certRequest = array();
6424      var $requestHeaders = false;    // SOAP headers in request (text)
6425      var $responseHeaders = '';        // SOAP headers from response (incomplete namespace resolution) (text)
6426      var $document = '';                // SOAP body response portion (incomplete namespace resolution) (text)
6427      var $endpoint;
6428      var $forceEndpoint = '';        // overrides WSDL endpoint
6429      var $proxyhost = '';
6430      var $proxyport = '';
6431      var $proxyusername = '';
6432      var $proxypassword = '';
6433      var $xml_encoding = '';            // character set encoding of incoming (response) messages
6434      var $http_encoding = false;
6435      var $timeout = 0;                // HTTP connection timeout
6436      var $response_timeout = 30;        // HTTP response timeout
6437      var $endpointType = '';            // soap|wsdl, empty for WSDL initialization error
6438      var $persistentConnection = false;
6439      var $defaultRpcParams = false;    // This is no longer used
6440      var $request = '';                // HTTP request
6441      var $response = '';                // HTTP response
6442      var $responseData = '';            // SOAP payload of response
6443      var $cookies = array();            // Cookies from response or for request
6444      var $decode_utf8 = true;        // toggles whether the parser decodes element content w/ utf8_decode()
6445      var $operations = array();        // WSDL operations, empty for WSDL initialization error
6446      
6447      /*
6448       * fault related variables
6449       */
6450      /**
6451       * @var      fault
6452       * @access   public
6453       */
6454      var $fault;
6455      /**
6456       * @var      faultcode
6457       * @access   public
6458       */
6459      var $faultcode;
6460      /**
6461       * @var      faultstring
6462       * @access   public
6463       */
6464      var $faultstring;
6465      /**
6466       * @var      faultdetail
6467       * @access   public
6468       */
6469      var $faultdetail;
6470  
6471      /**
6472      * constructor
6473      *
6474      * @param    mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
6475      * @param    bool $wsdl optional, set to true if using WSDL
6476      * @param    int $portName optional portName in WSDL document
6477      * @param    string $proxyhost
6478      * @param    string $proxyport
6479      * @param    string $proxyusername
6480      * @param    string $proxypassword
6481      * @param    integer $timeout set the connection timeout
6482      * @param    integer $response_timeout set the response timeout
6483      * @access   public
6484      */
6485  	function soapclient2($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
6486          parent::nusoap_base();
6487          $this->endpoint = $endpoint;
6488          $this->proxyhost = $proxyhost;
6489          $this->proxyport = $proxyport;
6490          $this->proxyusername = $proxyusername;
6491          $this->proxypassword = $proxypassword;
6492          $this->timeout = $timeout;
6493          $this->response_timeout = $response_timeout;
6494  
6495          // make values
6496          if($wsdl){
6497              if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
6498                  $this->wsdl = $endpoint;
6499                  $this->endpoint = $this->wsdl->wsdl;
6500                  $this->wsdlFile = $this->endpoint;
6501                  $this->debug('existing wsdl instance created from ' . $this->endpoint);
6502              } else {
6503                  $this->wsdlFile = $this->endpoint;
6504                  
6505                  // instantiate wsdl object and parse wsdl file
6506                  $this->debug('instantiating wsdl class with doc: '.$endpoint);
6507                  $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
6508              }
6509              $this->appendDebug($this->wsdl->getDebug());
6510              $this->wsdl->clearDebug();
6511              // catch errors
6512              if($errstr = $this->wsdl->getError()){
6513                  $this->debug('got wsdl error: '.$errstr);
6514                  $this->setError('wsdl error: '.$errstr);
6515              } elseif($this->operations = $this->wsdl->getOperations()){
6516                  $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
6517                  $this->endpointType = 'wsdl';
6518              } else {
6519                  $this->debug( 'getOperations returned false');
6520                  $this->setError('no operations defined in the WSDL document!');
6521              }
6522          } else {
6523              $this->debug("instantiate SOAP with endpoint at $endpoint");
6524              $this->endpointType = 'soap';
6525          }
6526      }
6527  
6528      /**
6529      * calls method, returns PHP native type
6530      *
6531      * @param    string $method SOAP server URL or path
6532      * @param    mixed $params An array, associative or simple, of the parameters
6533      *                          for the method call, or a string that is the XML
6534      *                          for the call.  For rpc style, this call will
6535      *                          wrap the XML in a tag named after the method, as
6536      *                          well as the SOAP Envelope and Body.  For document
6537      *                          style, this will only wrap with the Envelope and Body.
6538      *                          IMPORTANT: when using an array with document style,
6539      *                          in which case there
6540      *                         is really one parameter, the root of the fragment
6541      *                         used in the call, which encloses what programmers
6542      *                         normally think of parameters.  A parameter array
6543      *                         *must* include the wrapper.
6544      * @param    string $namespace optional method namespace (WSDL can override)
6545      * @param    string $soapAction optional SOAPAction value (WSDL can override)
6546      * @param    mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers
6547      * @param    boolean $rpcParams optional (no longer used)
6548      * @param    string    $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
6549      * @param    string    $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
6550      * @return    mixed    response from SOAP call
6551      * @access   public
6552      */
6553  	function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
6554          $this->operation = $operation;
6555          $this->fault = false;
6556          $this->setError('');
6557          $this->request = '';
6558          $this->response = '';
6559          $this->responseData = '';
6560          $this->faultstring = '';
6561          $this->faultcode = '';
6562          $this->opData = array();
6563          
6564          $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
6565          $this->appendDebug('params=' . $this->varDump($params));
6566          $this->appendDebug('headers=' . $this->varDump($headers));
6567          if ($headers) {
6568              $this->requestHeaders = $headers;
6569          }
6570          // serialize parameters
6571          if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
6572              // use WSDL for operation
6573              $this->opData = $opData;
6574              $this->debug("found operation");
6575              $this->appendDebug('opData=' . $this->varDump($opData));
6576              if (isset($opData['soapAction'])) {
6577                  $soapAction = $opData['soapAction'];
6578              }
6579              if (! $this->forceEndpoint) {
6580                  $this->endpoint = $opData['endpoint'];
6581              } else {
6582                  $this->endpoint = $this->forceEndpoint;
6583              }
6584              $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :    $namespace;
6585              $style = $opData['style'];
6586              $use = $opData['input']['use'];
6587              // add ns to ns array
6588              if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
6589                  $nsPrefix = 'ns' . rand(1000, 9999);
6590                  $this->wsdl->namespaces[$nsPrefix] = $namespace;
6591              }
6592              $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
6593              // serialize payload
6594              if (is_string($params)) {
6595                  $this->debug("serializing param string for WSDL operation $operation");
6596                  $payload = $params;
6597              } elseif (is_array($params)) {
6598                  $this->debug("serializing param array for WSDL operation $operation");
6599                  $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
6600              } else {
6601                  $this->debug('params must be array or string');
6602                  $this->setError('params must be array or string');
6603                  return false;
6604              }
6605              $usedNamespaces = $this->wsdl->usedNamespaces;
6606              if (isset($opData['input']['encodingStyle'])) {
6607                  $encodingStyle = $opData['input']['encodingStyle'];
6608              } else {
6609                  $encodingStyle = '';
6610              }
6611              $this->appendDebug($this->wsdl->getDebug());
6612              $this->wsdl->clearDebug();
6613              if ($errstr = $this->wsdl->getError()) {
6614                  $this->debug('got wsdl error: '.$errstr);
6615                  $this->setError('wsdl error: '.$errstr);
6616                  return false;
6617              }
6618          } elseif($this->endpointType == 'wsdl') {
6619              // operation not in WSDL
6620              $this->appendDebug($this->wsdl->getDebug());
6621              $this->wsdl->clearDebug();
6622              $this->setError( 'operation '.$operation.' not present.');
6623              $this->debug("operation '$operation' not present.");
6624              return false;
6625          } else {
6626              // no WSDL
6627              //$this->namespaces['ns1'] = $namespace;
6628              $nsPrefix = 'ns' . rand(1000, 9999);
6629              // serialize 
6630              $payload = '';
6631              if (is_string($params)) {
6632                  $this->debug("serializing param string for operation $operation");
6633                  $payload = $params;
6634              } elseif (is_array($params)) {
6635                  $this->debug("serializing param array for operation $operation");
6636                  foreach($params as $k => $v){
6637                      $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
6638                  }
6639              } else {
6640                  $this->debug('params must be array or string');
6641                  $this->setError('params must be array or string');
6642                  return false;
6643              }
6644              $usedNamespaces = array();
6645              if ($use == 'encoded') {
6646                  $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6647              } else {
6648                  $encodingStyle = '';
6649              }
6650          }
6651          // wrap RPC calls with method element
6652          if ($style == 'rpc') {
6653              if ($use == 'literal') {
6654                  $this->debug("wrapping RPC request with literal method element");
6655                  if ($namespace) {
6656                      $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>";
6657                  } else {
6658                      $payload = "<$operation>" . $payload . "</$operation>";
6659                  }
6660              } else {
6661                  $this->debug("wrapping RPC request with encoded method element");
6662                  if ($namespace) {
6663                      $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
6664                                  $payload .
6665                                  "</$nsPrefix:$operation>";
6666                  } else {
6667                      $payload = "<$operation>" .
6668                                  $payload .
6669                                  "</$operation>";
6670                  }
6671              }
6672          }
6673          // serialize envelope
6674          $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
6675          $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
6676          $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
6677          // send
6678          $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
6679          if($errstr = $this->getError()){
6680              $this->debug('Error: '.$errstr);
6681              return false;
6682          } else {
6683              $this->return = $return;
6684              $this->debug('sent message successfully and got a(n) '.gettype($return));
6685                 $this->appendDebug('return=' . $this->varDump($return));
6686              
6687              // fault?
6688              if(is_array($return) && isset($return['faultcode'])){
6689                  $this->debug('got fault');
6690                  $this->setError($return['faultcode'].': '.$return['faultstring']);
6691                  $this->fault = true;
6692                  foreach($return as $k => $v){
6693                      $this->$k = $v;
6694                      $this->debug("$k = $v<br>");
6695                  }
6696                  return $return;
6697              } elseif ($style == 'document') {
6698                  // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
6699                  // we are only going to return the first part here...sorry about that
6700                  return $return;
6701              } else {
6702                  // array of return values
6703                  if(is_array($return)){
6704                      // multiple 'out' parameters, which we return wrapped up
6705                      // in the array
6706                      if(sizeof($return) > 1){
6707                          return $return;
6708                      }
6709                      // single 'out' parameter (normally the return value)
6710                      $return = array_shift($return);
6711                      $this->debug('return shifted value: ');
6712                      $this->appendDebug($this->varDump($return));
6713                         return $return;
6714                  // nothing returned (ie, echoVoid)
6715                  } else {
6716                      return "";
6717                  }
6718              }
6719          }
6720      }
6721  
6722      /**
6723      * get available data pertaining to an operation
6724      *
6725      * @param    string $operation operation name
6726      * @return    array array of data pertaining to the operation
6727      * @access   public
6728      */
6729  	function getOperationData($operation){
6730          if(isset($this->operations[$operation])){
6731              return $this->operations[$operation];
6732          }
6733          $this->debug("No data for operation: $operation");
6734      }
6735  
6736      /**
6737      * send the SOAP message
6738      *
6739      * Note: if the operation has multiple return values
6740      * the return value of this method will be an array
6741      * of those values.
6742      *
6743      * @param    string $msg a SOAPx4 soapmsg object
6744      * @param    string $soapaction SOAPAction value
6745      * @param    integer $timeout set connection timeout in seconds
6746      * @param    integer $response_timeout set response timeout in seconds
6747      * @return    mixed native PHP types.
6748      * @access   private
6749      */
6750  	function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
6751          $this->checkCookies();
6752          // detect transport
6753          switch(true){
6754              // http(s)
6755              case ereg('^http',$this->endpoint):
6756                  $this->debug('transporting via HTTP');
6757                  if($this->persistentConnection == true && is_object($this->persistentConnection)){
6758                      $http =& $this->persistentConnection;
6759                  } else {
6760                      $http = new soap_transport_http($this->endpoint);
6761                      if ($this->persistentConnection) {
6762                          $http->usePersistentConnection();
6763                      }
6764                  }
6765                  $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
6766                  $http->setSOAPAction($soapaction);
6767                  if($this->proxyhost && $this->proxyport){
6768                      $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
6769                  }
6770                  if($this->authtype != '') {
6771                      $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
6772                  }
6773                  if($this->http_encoding != ''){
6774                      $http->setEncoding($this->http_encoding);
6775                  }
6776                  $this->debug('sending message, length='.strlen($msg));
6777                  if(ereg('^http:',$this->endpoint)){
6778                  //if(strpos($this->endpoint,'http:')){
6779                      $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
6780                  } elseif(ereg('^https',$this->endpoint)){
6781                  //} elseif(strpos($this->endpoint,'https:')){
6782                      //if(phpversion() == '4.3.0-dev'){
6783                          //$response = $http->send($msg,$timeout,$response_timeout);
6784                             //$this->request = $http->outgoing_payload;
6785                          //$this->response = $http->incoming_payload;
6786                      //} else
6787                      $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
6788                  } else {
6789                      $this->setError('no http/s in endpoint url');
6790                  }
6791                  $this->request = $http->outgoing_payload;
6792                  $this->response = $http->incoming_payload;
6793                  $this->appendDebug($http->getDebug());
6794                  $this->UpdateCookies($http->incoming_cookies);
6795  
6796                  // save transport object if using persistent connections
6797                  if ($this->persistentConnection) {
6798                      $http->clearDebug();
6799                      if (!is_object($this->persistentConnection)) {
6800                          $this->persistentConnection = $http;
6801                      }
6802                  }
6803                  
6804                  if($err = $http->getError()){
6805                      $this->setError('HTTP Error: '.$err);
6806                      return false;
6807                  } elseif($this->getError()){
6808                      return false;
6809                  } else {
6810                      $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
6811                      return $this->parseResponse($http->incoming_headers, $this->responseData);
6812                  }
6813              break;
6814              default:
6815                  $this->setError('no transport found, or selected transport is not yet supported!');
6816              return false;
6817              break;
6818          }
6819      }
6820  
6821      /**
6822      * processes SOAP message returned from server
6823      *
6824      * @param    array    $headers    The HTTP headers
6825      * @param    string    $data        unprocessed response data from server
6826      * @return    mixed    value of the message, decoded into a PHP type
6827      * @access   private
6828      */
6829      function parseResponse($headers, $data) {
6830          $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
6831          if (!strstr($headers['content-type'], 'text/xml')) {
6832              $this->setError('Response not of type text/xml');
6833              return false;
6834          }
6835          if (strpos($headers['content-type'], '=')) {
6836              $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
6837              $this->debug('Got response encoding: ' . $enc);
6838              if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
6839                  $this->xml_encoding = strtoupper($enc);
6840              } else {
6841                  $this->xml_encoding = 'US-ASCII';
6842              }
6843          } else {
6844              // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
6845              $this->xml_encoding = 'ISO-8859-1';
6846          }
6847          $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
6848          $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
6849          // add parser debug data to our debug
6850          $this->appendDebug($parser->getDebug());
6851          // if parse errors
6852          if($errstr = $parser->getError()){
6853              $this->setError( $errstr);
6854              // destroy the parser object
6855              unset($parser);
6856              return false;
6857          } else {
6858              // get SOAP headers
6859              $this->responseHeaders = $parser->getHeaders();
6860              // get decoded message
6861              $return = $parser->get_response();
6862              // add document for doclit support
6863              $this->document = $parser->document;
6864              // destroy the parser object
6865              unset($parser);
6866              // return decode message
6867              return $return;
6868          }
6869       }
6870  
6871      /**
6872      * sets the SOAP endpoint, which can override WSDL
6873      *
6874      * @param    $endpoint string The endpoint URL to use, or empty string or false to prevent override
6875      * @access   public
6876      */
6877  	function setEndpoint($endpoint) {
6878          $this->forceEndpoint = $endpoint;
6879      }
6880  
6881      /**
6882      * set the SOAP headers
6883      *
6884      * @param    $headers mixed String of XML with SOAP header content, or array of soapval objects for SOAP headers
6885      * @access   public
6886      */
6887  	function setHeaders($headers){
6888          $this->requestHeaders = $headers;
6889      }
6890  
6891      /**
6892      * get the SOAP response headers (namespace resolution incomplete)
6893      *
6894      * @return    string
6895      * @access   public
6896      */
6897  	function getHeaders(){
6898          return $this->responseHeaders;
6899      }
6900  
6901      /**
6902      * set proxy info here
6903      *
6904      * @param    string $proxyhost
6905      * @param    string $proxyport
6906      * @param    string $proxyusername
6907      * @param    string $proxypassword
6908      * @access   public
6909      */
6910  	function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
6911          $this->proxyhost = $proxyhost;
6912          $this->proxyport = $proxyport;
6913          $this->proxyusername = $proxyusername;
6914          $this->proxypassword = $proxypassword;
6915      }
6916  
6917      /**
6918      * if authenticating, set user credentials here
6919      *
6920      * @param    string $username
6921      * @param    string $password
6922      * @param    string $authtype (basic|digest|certificate)
6923      * @param    array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
6924      * @access   public
6925      */
6926  	function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
6927          $this->username = $username;
6928          $this->password = $password;
6929          $this->authtype = $authtype;
6930          $this->certRequest = $certRequest;
6931      }
6932      
6933      /**
6934      * use HTTP encoding
6935      *
6936      * @param    string $enc
6937      * @access   public
6938      */
6939  	function setHTTPEncoding($enc='gzip, deflate'){
6940          $this->http_encoding = $enc;
6941      }
6942      
6943      /**
6944      * use HTTP persistent connections if possible
6945      *
6946      * @access   public
6947      */
6948  	function useHTTPPersistentConnection(){
6949          $this->persistentConnection = true;
6950      }
6951      
6952      /**
6953      * gets the default RPC parameter setting.
6954      * If true, default is that call params are like RPC even for document style.
6955      * Each call() can override this value.
6956      *
6957      * This is no longer used.
6958      *
6959      * @return boolean
6960      * @access public
6961      * @deprecated
6962      */
6963  	function getDefaultRpcParams() {
6964          return $this->defaultRpcParams;
6965      }
6966  
6967      /**
6968      * sets the default RPC parameter setting.
6969      * If true, default is that call params are like RPC even for document style
6970      * Each call() can override this value.
6971      *
6972      * This is no longer used.
6973      *
6974      * @param    boolean $rpcParams
6975      * @access public
6976      * @deprecated
6977      */
6978  	function setDefaultRpcParams($rpcParams) {
6979          $this->defaultRpcParams = $rpcParams;
6980      }
6981      
6982      /**
6983      * dynamically creates an instance of a proxy class,
6984      * allowing user to directly call methods from wsdl
6985      *
6986      * @return   object soap_proxy object
6987      * @access   public
6988      */
6989  	function getProxy(){
6990          $r = rand();
6991          $evalStr = $this->_getProxyClassCode($r);
6992          //$this->debug("proxy class: $evalStr";
6993          // eval the class
6994          eval($evalStr);
6995          // instantiate proxy object
6996          eval("\$proxy = new soap_proxy_$r('');");
6997          // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
6998          $proxy->endpointType = 'wsdl';
6999          $proxy->wsdlFile = $this->wsdlFile;
7000          $proxy->wsdl = $this->wsdl;
7001          $proxy->operations = $this->operations;
7002          $proxy->defaultRpcParams = $this->defaultRpcParams;
7003          // transfer other state
7004          $proxy->username = $this->username;
7005          $proxy->password = $this->password;
7006          $proxy->authtype = $this->authtype;
7007          $proxy->proxyhost = $this->proxyhost;
7008          $proxy->proxyport = $this->proxyport;
7009          $proxy->proxyusername = $this->proxyusername;
7010          $proxy->proxypassword = $this->proxypassword;
7011          $proxy->timeout = $this->timeout;
7012          $proxy->response_timeout = $this->response_timeout;
7013          $proxy->http_encoding = $this->http_encoding;
7014          $proxy->persistentConnection = $this->persistentConnection;
7015          $proxy->requestHeaders = $this->requestHeaders;
7016          $proxy->soap_defencoding = $this->soap_defencoding;
7017          $proxy->endpoint = $this->endpoint;
7018          $proxy->forceEndpoint = $this->forceEndpoint;
7019          return $proxy;
7020      }
7021  
7022      /**
7023      * dynamically creates proxy class code
7024      *
7025      * @return   string PHP/NuSOAP code for the proxy class
7026      * @access   private
7027      */
7028  	function _getProxyClassCode($r) {
7029          if ($this->endpointType != 'wsdl') {
7030              $evalStr = 'A proxy can only be created for a WSDL client';
7031              $this->setError($evalStr);
7032              return $evalStr;
7033          }
7034          $evalStr = '';
7035          foreach ($this->operations as $operation => $opData) {
7036              if ($operation != '') {
7037                  // create param string and param comment string
7038                  if (sizeof($opData['input']['parts']) > 0) {
7039                      $paramStr = '';
7040                      $paramArrayStr = '';
7041                      $paramCommentStr = '';
7042                      foreach ($opData['input']['parts'] as $name => $type) {
7043                          $paramStr .= "\$$name, ";
7044                          $paramArrayStr .= "'$name' => \$$name, ";
7045                          $paramCommentStr .= "$type \$$name, ";
7046                      }
7047                      $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
7048                      $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
7049                      $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
7050                  } else {
7051                      $paramStr = '';
7052                      $paramCommentStr = 'void';
7053                  }
7054                  $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
7055                  $evalStr .= "// $paramCommentStr
7056      function " . str_replace('.', '__', $operation) . "($paramStr) {
7057          \$params = array($paramArrayStr);
7058          return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
7059      }
7060      ";
7061                  unset($paramStr);
7062                  unset($paramCommentStr);
7063              }
7064          }
7065          $evalStr = 'class soap_proxy_'.$r.' extends soapclient2 {
7066      '.$evalStr.'
7067  }';
7068          return $evalStr;
7069      }
7070  
7071      /**
7072      * dynamically creates proxy class code
7073      *
7074      * @return   string PHP/NuSOAP code for the proxy class
7075      * @access   public
7076      */
7077  	function getProxyClassCode() {
7078          $r = rand();
7079          return $this->_getProxyClassCode($r);
7080      }
7081  
7082      /**
7083      * gets the HTTP body for the current request.
7084      *
7085      * @param string $soapmsg The SOAP payload
7086      * @return string The HTTP body, which includes the SOAP payload
7087      * @access private
7088      */
7089  	function getHTTPBody($soapmsg) {
7090          return $soapmsg;
7091      }
7092      
7093      /**
7094      * gets the HTTP content type for the current request.
7095      *
7096      * Note: getHTTPBody must be called before this.
7097      *
7098      * @return string the HTTP content type for the current request.
7099      * @access private
7100      */
7101  	function getHTTPContentType() {
7102          return 'text/xml';
7103      }
7104      
7105      /**
7106      * gets the HTTP content type charset for the current request.
7107      * returns false for non-text content types.
7108      *
7109      * Note: getHTTPBody must be called before this.
7110      *
7111      * @return string the HTTP content type charset for the current request.
7112      * @access private
7113      */
7114  	function getHTTPContentTypeCharset() {
7115          return $this->soap_defencoding;
7116      }
7117  
7118      /*
7119      * whether or not parser should decode utf8 element content
7120      *
7121      * @return   always returns true
7122      * @access   public
7123      */
7124      function decodeUTF8($bool){
7125          $this->decode_utf8 = $bool;
7126          return true;
7127      }
7128  
7129      /**
7130       * adds a new Cookie into $this->cookies array
7131       *
7132       * @param    string $name Cookie Name
7133       * @param    string $value Cookie Value
7134       * @return    if cookie-set was successful returns true, else false
7135       * @access    public
7136       */
7137  	function setCookie($name, $value) {
7138          if (strlen($name) == 0) {
7139              return false;
7140          }
7141          $this->cookies[] = array('name' => $name, 'value' => $value);
7142          return true;
7143      }
7144  
7145      /**
7146       * gets all Cookies
7147       *
7148       * @return   array with all internal cookies
7149       * @access   public
7150       */
7151  	function getCookies() {
7152          return $this->cookies;
7153      }
7154  
7155      /**
7156       * checks all Cookies and delete those which are expired
7157       *
7158       * @return   always return true
7159       * @access   private
7160       */
7161  	function checkCookies() {
7162          if (sizeof($this->cookies) == 0) {
7163              return true;
7164          }
7165          $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
7166          $curr_cookies = $this->cookies;
7167          $this->cookies = array();
7168          foreach ($curr_cookies as $cookie) {
7169              if (! is_array($cookie)) {
7170                  $this->debug('Remove cookie that is not an array');
7171                  continue;
7172              }
7173              if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
7174                  if (strtotime($cookie['expires']) > time()) {
7175                      $this->cookies[] = $cookie;
7176                  } else {
7177                      $this->debug('Remove expired cookie ' . $cookie['name']);
7178                  }
7179              } else {
7180                  $this->cookies[] = $cookie;
7181              }
7182          }
7183          $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
7184          return true;
7185      }
7186  
7187      /**
7188       * updates the current cookies with a new set
7189       *
7190       * @param    array $cookies new cookies with which to update current ones
7191       * @return    always return true
7192       * @access    private
7193       */
7194  	function UpdateCookies($cookies) {
7195          if (sizeof($this->cookies) == 0) {
7196              // no existing cookies: take whatever is new
7197              if (sizeof($cookies) > 0) {
7198                  $this->debug('Setting new cookie(s)');
7199                  $this->cookies = $cookies;
7200              }
7201              return true;
7202          }
7203          if (sizeof($cookies) == 0) {
7204              // no new cookies: keep what we've got
7205              return true;
7206          }
7207          // merge
7208          foreach ($cookies as $newCookie) {
7209              if (!is_array($newCookie)) {
7210                  continue;
7211              }
7212              if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
7213                  continue;
7214              }
7215              $newName = $newCookie['name'];
7216  
7217              $found = false;
7218              for ($i = 0; $i < count($this->cookies); $i++) {
7219                  $cookie = $this->cookies[$i];
7220                  if (!is_array($cookie)) {
7221                      continue;
7222                  }
7223                  if (!isset($cookie['name'])) {
7224                      continue;
7225                  }
7226                  if ($newName != $cookie['name']) {
7227                      continue;
7228                  }
7229                  $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
7230                  $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
7231                  if ($newDomain != $domain) {
7232                      continue;
7233                  }
7234                  $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
7235                  $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
7236                  if ($newPath != $path) {
7237                      continue;
7238                  }
7239                  $this->cookies[$i] = $newCookie;
7240                  $found = true;
7241                  $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
7242                  break;
7243              }
7244              if (! $found) {
7245                  $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
7246                  $this->cookies[] = $newCookie;
7247              }
7248          }
7249          return true;
7250      }
7251  }
7252  ?>


Généré le : Sun Feb 25 10:22:19 2007 par Balluche grâce à PHPXref 0.7