[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

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


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1