• Hauptseite
  • Zusätzliche Informationen
  • Klassen
  • Dateien
  • Auflistung der Dateien
  • Datei-Elemente

/nusoap/lib/nusoap.php

gehe zur Dokumentation dieser Datei
00001 <?php
00002 
00003 /*
00004 $Id: nusoap.php,v 1.121 2008/03/14 20:52:11 snichol Exp $
00005 
00006 NuSOAP - Web Services Toolkit for PHP
00007 
00008 Copyright (c) 2002 NuSphere Corporation
00009 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU Lesser General Public
00012 License as published by the Free Software Foundation; either
00013 version 2.1 of the License, or (at your option) any later version.
00014 
00015 This library is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 Lesser General Public License for more details.
00019 
00020 You should have received a copy of the GNU Lesser General Public
00021 License along with this library; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 
00024 The NuSOAP project home is:
00025 http://sourceforge.net/projects/nusoap/
00026 
00027 The primary support for NuSOAP is the Help forum on the project home page.
00028 
00029 If you have any questions or comments, please email:
00030 
00031 Dietrich Ayala
00032 dietrich@ganx4.com
00033 http://dietrich.ganx4.com/nusoap
00034 
00035 NuSphere Corporation
00036 http://www.nusphere.com
00037 
00038 */
00039 
00040 /*
00041  *      Some of the standards implmented in whole or part by NuSOAP:
00042  *
00043  *      SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
00044  *      WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
00045  *      SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
00046  *      XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
00047  *      Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
00048  *      XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
00049  *      RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
00050  *      RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
00051  *      RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
00052  */
00053 
00054 /* load classes
00055 
00056 // necessary classes
00057 require_once('class.soapclient.php');
00058 require_once('class.soap_val.php');
00059 require_once('class.soap_parser.php');
00060 require_once('class.soap_fault.php');
00061 
00062 // transport classes
00063 require_once('class.soap_transport_http.php');
00064 
00065 // optional add-on classes
00066 require_once('class.xmlschema.php');
00067 require_once('class.wsdl.php');
00068 
00069 // server class
00070 require_once('class.soap_server.php');*/
00071 
00072 // class variable emulation
00073 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
00074 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
00075 
00085 class nusoap_base {
00092         var $title = 'NuSOAP';
00099         var $version = '1.0rc1';
00106         var $revision = '$Revision: 1.121 $';
00113         var $error_str = '';
00120     var $debug_str = '';
00128         var $charencoding = true;
00135         var $debugLevel;
00136 
00143         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
00144         
00151     var $soap_defencoding = 'ISO-8859-1';
00152         //var $soap_defencoding = 'UTF-8';
00153 
00162         var $namespaces = array(
00163                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
00164                 'xsd' => 'http://www.w3.org/2001/XMLSchema',
00165                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
00166                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
00167                 );
00168 
00175         var $usedNamespaces = array();
00176 
00184         var $typemap = array(
00185         'http://www.w3.org/2001/XMLSchema' => array(
00186                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
00187                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
00188                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
00189                 // abstract "any" types
00190                 'anyType'=>'string','anySimpleType'=>'string',
00191                 // derived datatypes
00192                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
00193                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
00194                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
00195                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
00196         'http://www.w3.org/2000/10/XMLSchema' => array(
00197                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00198                 'float'=>'double','dateTime'=>'string',
00199                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00200         'http://www.w3.org/1999/XMLSchema' => array(
00201                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00202                 'float'=>'double','dateTime'=>'string',
00203                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00204         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
00205         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
00206     'http://xml.apache.org/xml-soap' => array('Map')
00207         );
00208 
00217         var $xmlEntities = array('quot' => '"','amp' => '&',
00218                 'lt' => '<','gt' => '>','apos' => "'");
00219 
00225         function nusoap_base() {
00226                 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
00227         }
00228 
00235         function getGlobalDebugLevel() {
00236                 return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
00237         }
00238 
00245         function setGlobalDebugLevel($level) {
00246                 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
00247         }
00248 
00255         function getDebugLevel() {
00256                 return $this->debugLevel;
00257         }
00258 
00265         function setDebugLevel($level) {
00266                 $this->debugLevel = $level;
00267         }
00268 
00275         function debug($string){
00276                 if ($this->debugLevel > 0) {
00277                         $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
00278                 }
00279         }
00280 
00287         function appendDebug($string){
00288                 if ($this->debugLevel > 0) {
00289                         // it would be nice to use a memory stream here to use
00290                         // memory more efficiently
00291                         $this->debug_str .= $string;
00292                 }
00293         }
00294 
00300         function clearDebug() {
00301                 // it would be nice to use a memory stream here to use
00302                 // memory more efficiently
00303                 $this->debug_str = '';
00304         }
00305 
00312         function &getDebug() {
00313                 // it would be nice to use a memory stream here to use
00314                 // memory more efficiently
00315                 return $this->debug_str;
00316         }
00317 
00325         function &getDebugAsXMLComment() {
00326                 // it would be nice to use a memory stream here to use
00327                 // memory more efficiently
00328                 while (strpos($this->debug_str, '--')) {
00329                         $this->debug_str = str_replace('--', '- -', $this->debug_str);
00330                 }
00331                 $ret = "<!--\n" . $this->debug_str . "\n-->";
00332         return $ret;
00333         }
00334 
00341         function expandEntities($val) {
00342                 if ($this->charencoding) {
00343                 $val = str_replace('&', '&amp;', $val);
00344                 $val = str_replace("'", '&apos;', $val);
00345                 $val = str_replace('"', '&quot;', $val);
00346                 $val = str_replace('<', '&lt;', $val);
00347                 $val = str_replace('>', '&gt;', $val);
00348             }
00349             return $val;
00350         }
00351 
00358         function getError(){
00359                 if($this->error_str != ''){
00360                         return $this->error_str;
00361                 }
00362                 return false;
00363         }
00364 
00371         function setError($str){
00372                 $this->error_str = $str;
00373         }
00374 
00382         function isArraySimpleOrStruct($val) {
00383         $keyList = array_keys($val);
00384                 foreach ($keyList as $keyListValue) {
00385                         if (!is_int($keyListValue)) {
00386                                 return 'arrayStruct';
00387                         }
00388                 }
00389                 return 'arraySimple';
00390         }
00391 
00407         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
00408                 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
00409                 $this->appendDebug('value=' . $this->varDump($val));
00410                 $this->appendDebug('attributes=' . $this->varDump($attributes));
00411                 
00412         if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
00413                 $this->debug("serialize_val: serialize soapval");
00414                 $xml = $val->serialize($use);
00415                         $this->appendDebug($val->getDebug());
00416                         $val->clearDebug();
00417                         $this->debug("serialize_val of soapval returning $xml");
00418                         return $xml;
00419         }
00420                 // force valid name if necessary
00421                 if (is_numeric($name)) {
00422                         $name = '__numeric_' . $name;
00423                 } elseif (! $name) {
00424                         $name = 'noname';
00425                 }
00426                 // if name has ns, add ns prefix to name
00427                 $xmlns = '';
00428         if($name_ns){
00429                         $prefix = 'nu'.rand(1000,9999);
00430                         $name = $prefix.':'.$name;
00431                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";
00432                 }
00433                 // if type is prefixed, create type prefix
00434                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
00435                         // need to fix this. shouldn't default to xsd if no ns specified
00436                     // w/o checking against typemap
00437                         $type_prefix = 'xsd';
00438                 } elseif($type_ns){
00439                         $type_prefix = 'ns'.rand(1000,9999);
00440                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
00441                 }
00442                 // serialize attributes if present
00443                 $atts = '';
00444                 if($attributes){
00445                         foreach($attributes as $k => $v){
00446                                 $atts .= " $k=\"".$this->expandEntities($v).'"';
00447                         }
00448                 }
00449                 // serialize null value
00450                 if (is_null($val)) {
00451                 $this->debug("serialize_val: serialize null");
00452                         if ($use == 'literal') {
00453                                 // TODO: depends on minOccurs
00454                                 $xml = "<$name$xmlns$atts/>";
00455                                 $this->debug("serialize_val returning $xml");
00456                         return $xml;
00457                 } else {
00458                                 if (isset($type) && isset($type_prefix)) {
00459                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00460                                 } else {
00461                                         $type_str = '';
00462                                 }
00463                                 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
00464                                 $this->debug("serialize_val returning $xml");
00465                         return $xml;
00466                 }
00467                 }
00468         // serialize if an xsd built-in primitive type
00469         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
00470                 $this->debug("serialize_val: serialize xsd built-in primitive type");
00471                 if (is_bool($val)) {
00472                         if ($type == 'boolean') {
00473                                 $val = $val ? 'true' : 'false';
00474                         } elseif (! $val) {
00475                                 $val = 0;
00476                         }
00477                         } else if (is_string($val)) {
00478                                 $val = $this->expandEntities($val);
00479                         }
00480                         if ($use == 'literal') {
00481                                 $xml = "<$name$xmlns$atts>$val</$name>";
00482                                 $this->debug("serialize_val returning $xml");
00483                         return $xml;
00484                 } else {
00485                                 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
00486                                 $this->debug("serialize_val returning $xml");
00487                         return $xml;
00488                 }
00489         }
00490                 // detect type and serialize
00491                 $xml = '';
00492                 switch(true) {
00493                         case (is_bool($val) || $type == 'boolean'):
00494                                 $this->debug("serialize_val: serialize boolean");
00495                         if ($type == 'boolean') {
00496                                 $val = $val ? 'true' : 'false';
00497                         } elseif (! $val) {
00498                                 $val = 0;
00499                         }
00500                                 if ($use == 'literal') {
00501                                         $xml .= "<$name$xmlns$atts>$val</$name>";
00502                                 } else {
00503                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
00504                                 }
00505                                 break;
00506                         case (is_int($val) || is_long($val) || $type == 'int'):
00507                                 $this->debug("serialize_val: serialize int");
00508                                 if ($use == 'literal') {
00509                                         $xml .= "<$name$xmlns$atts>$val</$name>";
00510                                 } else {
00511                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
00512                                 }
00513                                 break;
00514                         case (is_float($val)|| is_double($val) || $type == 'float'):
00515                                 $this->debug("serialize_val: serialize float");
00516                                 if ($use == 'literal') {
00517                                         $xml .= "<$name$xmlns$atts>$val</$name>";
00518                                 } else {
00519                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
00520                                 }
00521                                 break;
00522                         case (is_string($val) || $type == 'string'):
00523                                 $this->debug("serialize_val: serialize string");
00524                                 $val = $this->expandEntities($val);
00525                                 if ($use == 'literal') {
00526                                         $xml .= "<$name$xmlns$atts>$val</$name>";
00527                                 } else {
00528                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
00529                                 }
00530                                 break;
00531                         case is_object($val):
00532                                 $this->debug("serialize_val: serialize object");
00533                         if (get_class($val) == 'soapval') {
00534                                 $this->debug("serialize_val: serialize soapval object");
00535                                 $pXml = $val->serialize($use);
00536                                         $this->appendDebug($val->getDebug());
00537                                         $val->clearDebug();
00538                         } else {
00539                                         if (! $name) {
00540                                                 $name = get_class($val);
00541                                                 $this->debug("In serialize_val, used class name $name as element name");
00542                                         } else {
00543                                                 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
00544                                         }
00545                                         foreach(get_object_vars($val) as $k => $v){
00546                                                 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
00547                                         }
00548                                 }
00549                                 if(isset($type) && isset($type_prefix)){
00550                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00551                                 } else {
00552                                         $type_str = '';
00553                                 }
00554                                 if ($use == 'literal') {
00555                                         $xml .= "<$name$xmlns$atts>$pXml</$name>";
00556                                 } else {
00557                                         $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
00558                                 }
00559                                 break;
00560                         break;
00561                         case (is_array($val) || $type):
00562                                 // detect if struct or array
00563                                 $valueType = $this->isArraySimpleOrStruct($val);
00564                 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
00565                                         $this->debug("serialize_val: serialize array");
00566                                         $i = 0;
00567                                         if(is_array($val) && count($val)> 0){
00568                                                 foreach($val as $v){
00569                                 if(is_object($v) && get_class($v) ==  'soapval'){
00570                                                                 $tt_ns = $v->type_ns;
00571                                                                 $tt = $v->type;
00572                                                         } elseif (is_array($v)) {
00573                                                                 $tt = $this->isArraySimpleOrStruct($v);
00574                                                         } else {
00575                                                                 $tt = gettype($v);
00576                                 }
00577                                                         $array_types[$tt] = 1;
00578                                                         // TODO: for literal, the name should be $name
00579                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
00580                                                         ++$i;
00581                                                 }
00582                                                 if(count($array_types) > 1){
00583                                                         $array_typename = 'xsd:anyType';
00584                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
00585                                                         if ($tt == 'integer') {
00586                                                                 $tt = 'int';
00587                                                         }
00588                                                         $array_typename = 'xsd:'.$tt;
00589                                                 } elseif(isset($tt) && $tt == 'arraySimple'){
00590                                                         $array_typename = 'SOAP-ENC:Array';
00591                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){
00592                                                         $array_typename = 'unnamed_struct_use_soapval';
00593                                                 } else {
00594                                                         // if type is prefixed, create type prefix
00595                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
00596                                                                  $array_typename = 'xsd:' . $tt;
00597                                                         } elseif ($tt_ns) {
00598                                                                 $tt_prefix = 'ns' . rand(1000, 9999);
00599                                                                 $array_typename = "$tt_prefix:$tt";
00600                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
00601                                                         } else {
00602                                                                 $array_typename = $tt;
00603                                                         }
00604                                                 }
00605                                                 $array_type = $i;
00606                                                 if ($use == 'literal') {
00607                                                         $type_str = '';
00608                                                 } else if (isset($type) && isset($type_prefix)) {
00609                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00610                                                 } else {
00611                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
00612                                                 }
00613                                         // empty array
00614                                         } else {
00615                                                 if ($use == 'literal') {
00616                                                         $type_str = '';
00617                                                 } else if (isset($type) && isset($type_prefix)) {
00618                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00619                                                 } else {
00620                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
00621                                                 }
00622                                         }
00623                                         // TODO: for array in literal, there is no wrapper here
00624                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
00625                                 } else {
00626                                         // got a struct
00627                                         $this->debug("serialize_val: serialize struct");
00628                                         if(isset($type) && isset($type_prefix)){
00629                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";
00630                                         } else {
00631                                                 $type_str = '';
00632                                         }
00633                                         if ($use == 'literal') {
00634                                                 $xml .= "<$name$xmlns$atts>";
00635                                         } else {
00636                                                 $xml .= "<$name$xmlns$type_str$atts>";
00637                                         }
00638                                         foreach($val as $k => $v){
00639                                                 // Apache Map
00640                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
00641                                                         $xml .= '<item>';
00642                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
00643                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
00644                                                         $xml .= '</item>';
00645                                                 } else {
00646                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
00647                                                 }
00648                                         }
00649                                         $xml .= "</$name>";
00650                                 }
00651                                 break;
00652                         default:
00653                                 $this->debug("serialize_val: serialize unknown");
00654                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
00655                                 break;
00656                 }
00657                 $this->debug("serialize_val returning $xml");
00658                 return $xml;
00659         }
00660 
00673     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
00674     // TODO: add an option to automatically run utf8_encode on $body and $headers
00675     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
00676     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
00677 
00678         $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
00679         $this->debug("headers:");
00680         $this->appendDebug($this->varDump($headers));
00681         $this->debug("namespaces:");
00682         $this->appendDebug($this->varDump($namespaces));
00683 
00684         // serialize namespaces
00685     $ns_string = '';
00686         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
00687                 $ns_string .= " xmlns:$k=\"$v\"";
00688         }
00689         if($encodingStyle) {
00690                 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
00691         }
00692 
00693         // serialize headers
00694         if($headers){
00695                 if (is_array($headers)) {
00696                         $xml = '';
00697                         foreach ($headers as $k => $v) {
00698                                 if (is_object($v) && get_class($v) == 'soapval') {
00699                                         $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
00700                                 } else {
00701                                         $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
00702                                 }
00703                         }
00704                         $headers = $xml;
00705                         $this->debug("In serializeEnvelope, serialized array of headers to $headers");
00706                 }
00707                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
00708         }
00709         // serialize envelope
00710         return
00711         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
00712         '<SOAP-ENV:Envelope'.$ns_string.">".
00713         $headers.
00714         "<SOAP-ENV:Body>".
00715                 $body.
00716         "</SOAP-ENV:Body>".
00717         "</SOAP-ENV:Envelope>";
00718     }
00719 
00728     function formatDump($str){
00729                 $str = htmlspecialchars($str);
00730                 return nl2br($str);
00731     }
00732 
00740         function contractQname($qname){
00741                 // get element namespace
00742                 //$this->xdebug("Contract $qname");
00743                 if (strrpos($qname, ':')) {
00744                         // get unqualified name
00745                         $name = substr($qname, strrpos($qname, ':') + 1);
00746                         // get ns
00747                         $ns = substr($qname, 0, strrpos($qname, ':'));
00748                         $p = $this->getPrefixFromNamespace($ns);
00749                         if ($p) {
00750                                 return $p . ':' . $name;
00751                         }
00752                         return $qname;
00753                 } else {
00754                         return $qname;
00755                 }
00756         }
00757 
00765         function expandQname($qname){
00766                 // get element prefix
00767                 if(strpos($qname,':') && !ereg('^http://',$qname)){
00768                         // get unqualified name
00769                         $name = substr(strstr($qname,':'),1);
00770                         // get ns prefix
00771                         $prefix = substr($qname,0,strpos($qname,':'));
00772                         if(isset($this->namespaces[$prefix])){
00773                                 return $this->namespaces[$prefix].':'.$name;
00774                         } else {
00775                                 return $qname;
00776                         }
00777                 } else {
00778                         return $qname;
00779                 }
00780         }
00781 
00790         function getLocalPart($str){
00791                 if($sstr = strrchr($str,':')){
00792                         // get unqualified name
00793                         return substr( $sstr, 1 );
00794                 } else {
00795                         return $str;
00796                 }
00797         }
00798 
00807         function getPrefix($str){
00808                 if($pos = strrpos($str,':')){
00809                         // get prefix
00810                         return substr($str,0,$pos);
00811                 }
00812                 return false;
00813         }
00814 
00822         function getNamespaceFromPrefix($prefix){
00823                 if (isset($this->namespaces[$prefix])) {
00824                         return $this->namespaces[$prefix];
00825                 }
00826                 //$this->setError("No namespace registered for prefix '$prefix'");
00827                 return false;
00828         }
00829 
00838         function getPrefixFromNamespace($ns) {
00839                 foreach ($this->namespaces as $p => $n) {
00840                         if ($ns == $n || $ns == $p) {
00841                             $this->usedNamespaces[$p] = $n;
00842                                 return $p;
00843                         }
00844                 }
00845                 return false;
00846         }
00847 
00854         function getmicrotime() {
00855                 if (function_exists('gettimeofday')) {
00856                         $tod = gettimeofday();
00857                         $sec = $tod['sec'];
00858                         $usec = $tod['usec'];
00859                 } else {
00860                         $sec = time();
00861                         $usec = 0;
00862                 }
00863                 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
00864         }
00865 
00873     function varDump($data) {
00874                 ob_start();
00875                 var_dump($data);
00876                 $ret_val = ob_get_contents();
00877                 ob_end_clean();
00878                 return $ret_val;
00879         }
00880 
00887         function __toString() {
00888                 return $this->varDump($this);
00889         }
00890 }
00891 
00892 // XML Schema Datatype Helper Functions
00893 
00894 //xsd:dateTime helpers
00895 
00904 function timestamp_to_iso8601($timestamp,$utc=true){
00905         $datestr = date('Y-m-d\TH:i:sO',$timestamp);
00906         $pos = strrpos($datestr, "+");
00907         if ($pos === FALSE) {
00908                 $pos = strrpos($datestr, "-");
00909         }
00910         if ($pos !== FALSE) {
00911                 if (strlen($datestr) == $pos + 5) {
00912                         $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
00913                 }
00914         }
00915         if($utc){
00916                 $eregStr =
00917                 '([0-9]{4})-'.  // centuries & years CCYY-
00918                 '([0-9]{2})-'.  // months MM-
00919                 '([0-9]{2})'.   // days DD
00920                 'T'.                    // separator T
00921                 '([0-9]{2}):'.  // hours hh:
00922                 '([0-9]{2}):'.  // minutes mm:
00923                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
00924                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00925 
00926                 if(ereg($eregStr,$datestr,$regs)){
00927                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
00928                 }
00929                 return false;
00930         } else {
00931                 return $datestr;
00932         }
00933 }
00934 
00942 function iso8601_to_timestamp($datestr){
00943         $eregStr =
00944         '([0-9]{4})-'.  // centuries & years CCYY-
00945         '([0-9]{2})-'.  // months MM-
00946         '([0-9]{2})'.   // days DD
00947         'T'.                    // separator T
00948         '([0-9]{2}):'.  // hours hh:
00949         '([0-9]{2}):'.  // minutes mm:
00950         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
00951         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00952         if(ereg($eregStr,$datestr,$regs)){
00953                 // not utc
00954                 if($regs[8] != 'Z'){
00955                         $op = substr($regs[8],0,1);
00956                         $h = substr($regs[8],1,2);
00957                         $m = substr($regs[8],strlen($regs[8])-2,2);
00958                         if($op == '-'){
00959                                 $regs[4] = $regs[4] + $h;
00960                                 $regs[5] = $regs[5] + $m;
00961                         } elseif($op == '+'){
00962                                 $regs[4] = $regs[4] - $h;
00963                                 $regs[5] = $regs[5] - $m;
00964                         }
00965                 }
00966                 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
00967 //              return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
00968         } else {
00969                 return false;
00970         }
00971 }
00972 
00980 function usleepWindows($usec)
00981 {
00982         $start = gettimeofday();
00983         
00984         do
00985         {
00986                 $stop = gettimeofday();
00987                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
00988                 + $stop['usec'] - $start['usec'];
00989         }
00990         while ($timePassed < $usec);
00991 }
00992 
00993 ?><?php
00994 
00995 
00996 
01005 class nusoap_fault extends nusoap_base {
01011         var $faultcode;
01017         var $faultactor;
01023         var $faultstring;
01029         var $faultdetail;
01030 
01039         function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
01040                 parent::nusoap_base();
01041                 $this->faultcode = $faultcode;
01042                 $this->faultactor = $faultactor;
01043                 $this->faultstring = $faultstring;
01044                 $this->faultdetail = $faultdetail;
01045         }
01046 
01053         function serialize(){
01054                 $ns_string = '';
01055                 foreach($this->namespaces as $k => $v){
01056                         $ns_string .= "\n  xmlns:$k=\"$v\"";
01057                 }
01058                 $return_msg =
01059                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
01060                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
01061                                 '<SOAP-ENV:Body>'.
01062                                 '<SOAP-ENV:Fault>'.
01063                                         $this->serialize_val($this->faultcode, 'faultcode').
01064                                         $this->serialize_val($this->faultactor, 'faultactor').
01065                                         $this->serialize_val($this->faultstring, 'faultstring').
01066                                         $this->serialize_val($this->faultdetail, 'detail').
01067                                 '</SOAP-ENV:Fault>'.
01068                                 '</SOAP-ENV:Body>'.
01069                         '</SOAP-ENV:Envelope>';
01070                 return $return_msg;
01071         }
01072 }
01073 
01077 class soap_fault extends nusoap_fault {
01078 }
01079 
01080 ?><?php
01081 
01082 
01083 
01093 class nusoap_xmlschema extends nusoap_base  {
01094         
01095         // files
01096         var $schema = '';
01097         var $xml = '';
01098         // namespaces
01099         var $enclosingNamespaces;
01100         // schema info
01101         var $schemaInfo = array();
01102         var $schemaTargetNamespace = '';
01103         // types, elements, attributes defined by the schema
01104         var $attributes = array();
01105         var $complexTypes = array();
01106         var $complexTypeStack = array();
01107         var $currentComplexType = null;
01108         var $elements = array();
01109         var $elementStack = array();
01110         var $currentElement = null;
01111         var $simpleTypes = array();
01112         var $simpleTypeStack = array();
01113         var $currentSimpleType = null;
01114         // imports
01115         var $imports = array();
01116         // parser vars
01117         var $parser;
01118         var $position = 0;
01119         var $depth = 0;
01120         var $depth_array = array();
01121         var $message = array();
01122         var $defaultNamespace = array();
01123     
01132         function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
01133                 parent::nusoap_base();
01134                 $this->debug('nusoap_xmlschema class instantiated, inside constructor');
01135                 // files
01136                 $this->schema = $schema;
01137                 $this->xml = $xml;
01138 
01139                 // namespaces
01140                 $this->enclosingNamespaces = $namespaces;
01141                 $this->namespaces = array_merge($this->namespaces, $namespaces);
01142 
01143                 // parse schema file
01144                 if($schema != ''){
01145                         $this->debug('initial schema file: '.$schema);
01146                         $this->parseFile($schema, 'schema');
01147                 }
01148 
01149                 // parse xml file
01150                 if($xml != ''){
01151                         $this->debug('initial xml file: '.$xml);
01152                         $this->parseFile($xml, 'xml');
01153                 }
01154 
01155         }
01156 
01165         function parseFile($xml,$type){
01166                 // parse xml file
01167                 if($xml != ""){
01168                         $xmlStr = @join("",@file($xml));
01169                         if($xmlStr == ""){
01170                                 $msg = 'Error reading XML from '.$xml;
01171                                 $this->setError($msg);
01172                                 $this->debug($msg);
01173                         return false;
01174                         } else {
01175                                 $this->debug("parsing $xml");
01176                                 $this->parseString($xmlStr,$type);
01177                                 $this->debug("done parsing $xml");
01178                         return true;
01179                         }
01180                 }
01181                 return false;
01182         }
01183 
01191         function parseString($xml,$type){
01192                 // parse xml string
01193                 if($xml != ""){
01194 
01195                 // Create an XML parser.
01196                 $this->parser = xml_parser_create();
01197                 // Set the options for parsing the XML data.
01198                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
01199 
01200                 // Set the object for the parser.
01201                 xml_set_object($this->parser, $this);
01202 
01203                 // Set the element handlers for the parser.
01204                         if($type == "schema"){
01205                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
01206                         xml_set_character_data_handler($this->parser,'schemaCharacterData');
01207                         } elseif($type == "xml"){
01208                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
01209                         xml_set_character_data_handler($this->parser,'xmlCharacterData');
01210                         }
01211 
01212                     // Parse the XML file.
01213                     if(!xml_parse($this->parser,$xml,true)){
01214                         // Display an error message.
01215                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
01216                                 xml_get_current_line_number($this->parser),
01217                                 xml_error_string(xml_get_error_code($this->parser))
01218                                 );
01219                                 $this->debug($errstr);
01220                                 $this->debug("XML payload:\n" . $xml);
01221                                 $this->setError($errstr);
01222                 }
01223             
01224                         xml_parser_free($this->parser);
01225                 } else{
01226                         $this->debug('no xml passed to parseString()!!');
01227                         $this->setError('no xml passed to parseString()!!');
01228                 }
01229         }
01230 
01238         function CreateTypeName($ename) {
01239                 $scope = '';
01240                 for ($i = 0; $i < count($this->complexTypeStack); $i++) {
01241                         $scope .= $this->complexTypeStack[$i] . '_';
01242                 }
01243                 return $scope . $ename . '_ContainedType';
01244         }
01245         
01254         function schemaStartElement($parser, $name, $attrs) {
01255                 
01256                 // position in the total number of elements, starting from 0
01257                 $pos = $this->position++;
01258                 $depth = $this->depth++;
01259                 // set self as current value for this depth
01260                 $this->depth_array[$depth] = $pos;
01261                 $this->message[$pos] = array('cdata' => ''); 
01262                 if ($depth > 0) {
01263                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
01264                 } else {
01265                         $this->defaultNamespace[$pos] = false;
01266                 }
01267 
01268                 // get element prefix
01269                 if($prefix = $this->getPrefix($name)){
01270                         // get unqualified name
01271                         $name = $this->getLocalPart($name);
01272                 } else {
01273                 $prefix = '';
01274         }
01275                 
01276         // loop thru attributes, expanding, and registering namespace declarations
01277         if(count($attrs) > 0){
01278                 foreach($attrs as $k => $v){
01279                 // if ns declarations, add to class level array of valid namespaces
01280                                 if(ereg("^xmlns",$k)){
01281                         //$this->xdebug("$k: $v");
01282                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
01283                         if($ns_prefix = substr(strrchr($k,':'),1)){
01284                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");
01285                                                 $this->namespaces[$ns_prefix] = $v;
01286                                         } else {
01287                                                 $this->defaultNamespace[$pos] = $v;
01288                                                 if (! $this->getPrefixFromNamespace($v)) {
01289                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
01290                                                 }
01291                                         }
01292                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
01293                                                 $this->XMLSchemaVersion = $v;
01294                                                 $this->namespaces['xsi'] = $v.'-instance';
01295                                         }
01296                                 }
01297                 }
01298                 foreach($attrs as $k => $v){
01299                 // expand each attribute
01300                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
01301                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
01302                         $eAttrs[$k] = $v;
01303                 }
01304                 $attrs = $eAttrs;
01305         } else {
01306                 $attrs = array();
01307         }
01308                 // find status, register data
01309                 switch($name){
01310                         case 'all':                     // (optional) compositor content for a complexType
01311                         case 'choice':
01312                         case 'group':
01313                         case 'sequence':
01314                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
01315                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
01316                                 //if($name == 'all' || $name == 'sequence'){
01317                                 //      $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01318                                 //}
01319                         break;
01320                         case 'attribute':       // complexType attribute
01321                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
01322                 $this->xdebug("parsing attribute:");
01323                 $this->appendDebug($this->varDump($attrs));
01324                                 if (!isset($attrs['form'])) {
01325                                         // TODO: handle globals
01326                                         $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
01327                                 }
01328                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01329                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01330                                         if (!strpos($v, ':')) {
01331                                                 // no namespace in arrayType attribute value...
01332                                                 if ($this->defaultNamespace[$pos]) {
01333                                                         // ...so use the default
01334                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01335                                                 }
01336                                         }
01337                 }
01338                 if(isset($attrs['name'])){
01339                                         $this->attributes[$attrs['name']] = $attrs;
01340                                         $aname = $attrs['name'];
01341                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
01342                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01343                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01344                         } else {
01345                                 $aname = '';
01346                         }
01347                                 } elseif(isset($attrs['ref'])){
01348                                         $aname = $attrs['ref'];
01349                     $this->attributes[$attrs['ref']] = $attrs;
01350                                 }
01351                 
01352                                 if($this->currentComplexType){  // This should *always* be
01353                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
01354                                 }
01355                                 // arrayType attribute
01356                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
01357                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01358                         $prefix = $this->getPrefix($aname);
01359                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
01360                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01361                                         } else {
01362                                                 $v = '';
01363                                         }
01364                     if(strpos($v,'[,]')){
01365                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
01366                     }
01367                     $v = substr($v,0,strpos($v,'[')); // clip the []
01368                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
01369                         $v = $this->XMLSchemaVersion.':'.$v;
01370                     }
01371                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
01372                                 }
01373                         break;
01374                         case 'complexContent':  // (optional) content for a complexType
01375                                 $this->xdebug("do nothing for element $name");
01376                         break;
01377                         case 'complexType':
01378                                 array_push($this->complexTypeStack, $this->currentComplexType);
01379                                 if(isset($attrs['name'])){
01380                                         // TODO: what is the scope of named complexTypes that appear
01381                                         //       nested within other c complexTypes?
01382                                         $this->xdebug('processing named complexType '.$attrs['name']);
01383                                         //$this->currentElement = false;
01384                                         $this->currentComplexType = $attrs['name'];
01385                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01386                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01387                                         // This is for constructs like
01388                                         //           <complexType name="ListOfString" base="soap:Array">
01389                                         //                <sequence>
01390                                         //                    <element name="string" type="xsd:string"
01391                                         //                        minOccurs="0" maxOccurs="unbounded" />
01392                                         //                </sequence>
01393                                         //            </complexType>
01394                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01395                                                 $this->xdebug('complexType is unusual array');
01396                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01397                                         } else {
01398                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01399                                         }
01400                                 } else {
01401                                         $name = $this->CreateTypeName($this->currentElement);
01402                                         $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
01403                                         $this->currentComplexType = $name;
01404                                         //$this->currentElement = false;
01405                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01406                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01407                                         // This is for constructs like
01408                                         //           <complexType name="ListOfString" base="soap:Array">
01409                                         //                <sequence>
01410                                         //                    <element name="string" type="xsd:string"
01411                                         //                        minOccurs="0" maxOccurs="unbounded" />
01412                                         //                </sequence>
01413                                         //            </complexType>
01414                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01415                                                 $this->xdebug('complexType is unusual array');
01416                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01417                                         } else {
01418                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01419                                         }
01420                                 }
01421                         break;
01422                         case 'element':
01423                                 array_push($this->elementStack, $this->currentElement);
01424                                 if (!isset($attrs['form'])) {
01425                                         if ($this->currentComplexType) {
01426                                                 $attrs['form'] = $this->schemaInfo['elementFormDefault'];
01427                                         } else {
01428                                                 // global
01429                                                 $attrs['form'] = 'qualified';
01430                                         }
01431                                 }
01432                                 if(isset($attrs['type'])){
01433                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
01434                                         if (! $this->getPrefix($attrs['type'])) {
01435                                                 if ($this->defaultNamespace[$pos]) {
01436                                                         $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
01437                                                         $this->xdebug('used default namespace to make type ' . $attrs['type']);
01438                                                 }
01439                                         }
01440                                         // This is for constructs like
01441                                         //           <complexType name="ListOfString" base="soap:Array">
01442                                         //                <sequence>
01443                                         //                    <element name="string" type="xsd:string"
01444                                         //                        minOccurs="0" maxOccurs="unbounded" />
01445                                         //                </sequence>
01446                                         //            </complexType>
01447                                         if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
01448                                                 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
01449                                                 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
01450                                         }
01451                                         $this->currentElement = $attrs['name'];
01452                                         $ename = $attrs['name'];
01453                                 } elseif(isset($attrs['ref'])){
01454                                         $this->xdebug("processing element as ref to ".$attrs['ref']);
01455                                         $this->currentElement = "ref to ".$attrs['ref'];
01456                                         $ename = $this->getLocalPart($attrs['ref']);
01457                                 } else {
01458                                         $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
01459                                         $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
01460                                         $this->currentElement = $attrs['name'];
01461                                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
01462                                         $ename = $attrs['name'];
01463                                 }
01464                                 if (isset($ename) && $this->currentComplexType) {
01465                                         $this->xdebug("add element $ename to complexType $this->currentComplexType");
01466                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
01467                                 } elseif (!isset($attrs['ref'])) {
01468                                         $this->xdebug("add element $ename to elements array");
01469                                         $this->elements[ $attrs['name'] ] = $attrs;
01470                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01471                                 }
01472                         break;
01473                         case 'enumeration':     //      restriction value list member
01474                                 $this->xdebug('enumeration ' . $attrs['value']);
01475                                 if ($this->currentSimpleType) {
01476                                         $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
01477                                 } elseif ($this->currentComplexType) {
01478                                         $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
01479                                 }
01480                         break;
01481                         case 'extension':       // simpleContent or complexContent type extension
01482                                 $this->xdebug('extension ' . $attrs['base']);
01483                                 if ($this->currentComplexType) {
01484                                         $ns = $this->getPrefix($attrs['base']);
01485                                         if ($ns == '') {
01486                                                 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
01487                                         } elseif ($this->getNamespaceFromPrefix($ns)) {
01488                                                 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
01489                                         }
01490                                 }
01491                         break;
01492                         case 'import':
01493                             if (isset($attrs['schemaLocation'])) {
01494                                         $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
01495                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
01496                                 } else {
01497                                         $this->xdebug('import namespace ' . $attrs['namespace']);
01498                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
01499                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
01500                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
01501                                         }
01502                                 }
01503                         break;
01504                         case 'include':
01505                             if (isset($attrs['schemaLocation'])) {
01506                                         $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
01507                     $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
01508                                 } else {
01509                                         $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
01510                                 }
01511                         break;
01512                         case 'list':    // simpleType value list
01513                                 $this->xdebug("do nothing for element $name");
01514                         break;
01515                         case 'restriction':     // simpleType, simpleContent or complexContent value restriction
01516                                 $this->xdebug('restriction ' . $attrs['base']);
01517                                 if($this->currentSimpleType){
01518                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
01519                                 } elseif($this->currentComplexType){
01520                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
01521                                         if(strstr($attrs['base'],':') == ':Array'){
01522                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01523                                         }
01524                                 }
01525                         break;
01526                         case 'schema':
01527                                 $this->schemaInfo = $attrs;
01528                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
01529                                 if (isset($attrs['targetNamespace'])) {
01530                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];
01531                                 }
01532                                 if (!isset($attrs['elementFormDefault'])) {
01533                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';
01534                                 }
01535                                 if (!isset($attrs['attributeFormDefault'])) {
01536                                         $this->schemaInfo['attributeFormDefault'] = 'unqualified';
01537                                 }
01538                         break;
01539                         case 'simpleContent':   // (optional) content for a complexType
01540                                 $this->xdebug("do nothing for element $name");
01541                         break;
01542                         case 'simpleType':
01543                                 array_push($this->simpleTypeStack, $this->currentSimpleType);
01544                                 if(isset($attrs['name'])){
01545                                         $this->xdebug("processing simpleType for name " . $attrs['name']);
01546                                         $this->currentSimpleType = $attrs['name'];
01547                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;
01548                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
01549                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
01550                                 } else {
01551                                         $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
01552                                         $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
01553                                         $this->currentSimpleType = $name;
01554                                         //$this->currentElement = false;
01555                                         $this->simpleTypes[$this->currentSimpleType] = $attrs;
01556                                         $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
01557                                 }
01558                         break;
01559                         case 'union':   // simpleType type list
01560                                 $this->xdebug("do nothing for element $name");
01561                         break;
01562                         default:
01563                                 $this->xdebug("do not have any logic to process element $name");
01564                 }
01565         }
01566 
01574         function schemaEndElement($parser, $name) {
01575                 // bring depth down a notch
01576                 $this->depth--;
01577                 // position of current element is equal to the last value left in depth_array for my depth
01578                 if(isset($this->depth_array[$this->depth])){
01579                 $pos = $this->depth_array[$this->depth];
01580         }
01581                 // get element prefix
01582                 if ($prefix = $this->getPrefix($name)){
01583                         // get unqualified name
01584                         $name = $this->getLocalPart($name);
01585                 } else {
01586                 $prefix = '';
01587         }
01588                 // move on...
01589                 if($name == 'complexType'){
01590                         $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
01591                         $this->currentComplexType = array_pop($this->complexTypeStack);
01592                         //$this->currentElement = false;
01593                 }
01594                 if($name == 'element'){
01595                         $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
01596                         $this->currentElement = array_pop($this->elementStack);
01597                 }
01598                 if($name == 'simpleType'){
01599                         $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
01600                         $this->currentSimpleType = array_pop($this->simpleTypeStack);
01601                 }
01602         }
01603 
01611         function schemaCharacterData($parser, $data){
01612                 $pos = $this->depth_array[$this->depth - 1];
01613                 $this->message[$pos]['cdata'] .= $data;
01614         }
01615 
01621         function serializeSchema(){
01622 
01623                 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
01624                 $xml = '';
01625                 // imports
01626                 if (sizeof($this->imports) > 0) {
01627                         foreach($this->imports as $ns => $list) {
01628                                 foreach ($list as $ii) {
01629                                         if ($ii['location'] != '') {
01630                                                 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
01631                                         } else {
01632                                                 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
01633                                         }
01634                                 }
01635                         } 
01636                 } 
01637                 // complex types
01638                 foreach($this->complexTypes as $typeName => $attrs){
01639                         $contentStr = '';
01640                         // serialize child elements
01641                         if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
01642                                 foreach($attrs['elements'] as $element => $eParts){
01643                                         if(isset($eParts['ref'])){
01644                                                 $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
01645                                         } else {
01646                                                 $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
01647                                                 foreach ($eParts as $aName => $aValue) {
01648                                                         // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
01649                                                         if ($aName != 'name' && $aName != 'type') {
01650                                                                 $contentStr .= " $aName=\"$aValue\"";
01651                                                         }
01652                                                 }
01653                                                 $contentStr .= "/>\n";
01654                                         }
01655                                 }
01656                                 // compositor wraps elements
01657                                 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
01658                                         $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
01659                                 }
01660                         }
01661                         // attributes
01662                         if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
01663                                 foreach($attrs['attrs'] as $attr => $aParts){
01664                                         $contentStr .= "    <$schemaPrefix:attribute";
01665                                         foreach ($aParts as $a => $v) {
01666                                                 if ($a == 'ref' || $a == 'type') {
01667                                                         $contentStr .= " $a=\"".$this->contractQName($v).'"';
01668                                                 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
01669                                                         $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
01670                                                         $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
01671                                                 } else {
01672                                                         $contentStr .= " $a=\"$v\"";
01673                                                 }
01674                                         }
01675                                         $contentStr .= "/>\n";
01676                                 }
01677                         }
01678                         // if restriction
01679                         if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
01680                                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
01681                                 // complex or simple content
01682                                 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
01683                                         $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
01684                                 }
01685                         }
01686                         // finalize complex type
01687                         if($contentStr != ''){
01688                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
01689                         } else {
01690                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
01691                         }
01692                         $xml .= $contentStr;
01693                 }
01694                 // simple types
01695                 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
01696                         foreach($this->simpleTypes as $typeName => $eParts){
01697                                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
01698                                 if (isset($eParts['enumeration'])) {
01699                                         foreach ($eParts['enumeration'] as $e) {
01700                                                 $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
01701                                         }
01702                                 }
01703                                 $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
01704                         }
01705                 }
01706                 // elements
01707                 if(isset($this->elements) && count($this->elements) > 0){
01708                         foreach($this->elements as $element => $eParts){
01709                                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
01710                         }
01711                 }
01712                 // attributes
01713                 if(isset($this->attributes) && count($this->attributes) > 0){
01714                         foreach($this->attributes as $attr => $aParts){
01715                                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
01716                         }
01717                 }
01718                 // finish 'er up
01719                 $attr = '';
01720                 foreach ($this->schemaInfo as $k => $v) {
01721                         if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
01722                                 $attr .= " $k=\"$v\"";
01723                         }
01724                 }
01725                 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
01726                 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
01727                         $el .= " xmlns:$nsp=\"$ns\"";
01728                 }
01729                 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
01730                 return $xml;
01731         }
01732 
01739         function xdebug($string){
01740                 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
01741         }
01742 
01755         function getPHPType($type,$ns){
01756                 if(isset($this->typemap[$ns][$type])){
01757                         //print "found type '$type' and ns $ns in typemap<br>";
01758                         return $this->typemap[$ns][$type];
01759                 } elseif(isset($this->complexTypes[$type])){
01760                         //print "getting type '$type' and ns $ns from complexTypes array<br>";
01761                         return $this->complexTypes[$type]['phpType'];
01762                 }
01763                 return false;
01764         }
01765 
01788         function getTypeDef($type){
01789                 //$this->debug("in getTypeDef for type $type");
01790                 if (substr($type, -1) == '^') {
01791                         $is_element = 1;
01792                         $type = substr($type, 0, -1);
01793                 } else {
01794                         $is_element = 0;
01795                 }
01796 
01797                 if((! $is_element) && isset($this->complexTypes[$type])){
01798                         $this->xdebug("in getTypeDef, found complexType $type");
01799                         return $this->complexTypes[$type];
01800                 } elseif((! $is_element) && isset($this->simpleTypes[$type])){
01801                         $this->xdebug("in getTypeDef, found simpleType $type");
01802                         if (!isset($this->simpleTypes[$type]['phpType'])) {
01803                                 // get info for type to tack onto the simple type
01804                                 // TODO: can this ever really apply (i.e. what is a simpleType really?)
01805                                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
01806                                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
01807                                 $etype = $this->getTypeDef($uqType);
01808                                 if ($etype) {
01809                                         $this->xdebug("in getTypeDef, found type for simpleType $type:");
01810                                         $this->xdebug($this->varDump($etype));
01811                                         if (isset($etype['phpType'])) {
01812                                                 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
01813                                         }
01814                                         if (isset($etype['elements'])) {
01815                                                 $this->simpleTypes[$type]['elements'] = $etype['elements'];
01816                                         }
01817                                 }
01818                         }
01819                         return $this->simpleTypes[$type];
01820                 } elseif(isset($this->elements[$type])){
01821                         $this->xdebug("in getTypeDef, found element $type");
01822                         if (!isset($this->elements[$type]['phpType'])) {
01823                                 // get info for type to tack onto the element
01824                                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
01825                                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
01826                                 $etype = $this->getTypeDef($uqType);
01827                                 if ($etype) {
01828                                         $this->xdebug("in getTypeDef, found type for element $type:");
01829                                         $this->xdebug($this->varDump($etype));
01830                                         if (isset($etype['phpType'])) {
01831                                                 $this->elements[$type]['phpType'] = $etype['phpType'];
01832                                         }
01833                                         if (isset($etype['elements'])) {
01834                                                 $this->elements[$type]['elements'] = $etype['elements'];
01835                                         }
01836                                         if (isset($etype['extensionBase'])) {
01837                                                 $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
01838                                         }
01839                                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
01840                                         $this->xdebug("in getTypeDef, element $type is an XSD type");
01841                                         $this->elements[$type]['phpType'] = 'scalar';
01842                                 }
01843                         }
01844                         return $this->elements[$type];
01845                 } elseif(isset($this->attributes[$type])){
01846                         $this->xdebug("in getTypeDef, found attribute $type");
01847                         return $this->attributes[$type];
01848                 } elseif (ereg('_ContainedType$', $type)) {
01849                         $this->xdebug("in getTypeDef, have an untyped element $type");
01850                         $typeDef['typeClass'] = 'simpleType';
01851                         $typeDef['phpType'] = 'scalar';
01852                         $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
01853                         return $typeDef;
01854                 }
01855                 $this->xdebug("in getTypeDef, did not find $type");
01856                 return false;
01857         }
01858 
01867     function serializeTypeDef($type){
01868         //print "in sTD() for type $type<br>";
01869         if($typeDef = $this->getTypeDef($type)){
01870                 $str .= '<'.$type;
01871             if(is_array($typeDef['attrs'])){
01872                 foreach($typeDef['attrs'] as $attName => $data){
01873                     $str .= " $attName=\"{type = ".$data['type']."}\"";
01874                 }
01875             }
01876             $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
01877             if(count($typeDef['elements']) > 0){
01878                 $str .= ">";
01879                 foreach($typeDef['elements'] as $element => $eData){
01880                     $str .= $this->serializeTypeDef($element);
01881                 }
01882                 $str .= "</$type>";
01883             } elseif($typeDef['typeClass'] == 'element') {
01884                 $str .= "></$type>";
01885             } else {
01886                 $str .= "/>";
01887             }
01888                         return $str;
01889         }
01890         return false;
01891     }
01892 
01903         function typeToForm($name,$type){
01904                 // get typedef
01905                 if($typeDef = $this->getTypeDef($type)){
01906                         // if struct
01907                         if($typeDef['phpType'] == 'struct'){
01908                                 $buffer .= '<table>';
01909                                 foreach($typeDef['elements'] as $child => $childDef){
01910                                         $buffer .= "
01911                                         <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
01912                                         <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
01913                                 }
01914                                 $buffer .= '</table>';
01915                         // if array
01916                         } elseif($typeDef['phpType'] == 'array'){
01917                                 $buffer .= '<table>';
01918                                 for($i=0;$i < 3; $i++){
01919                                         $buffer .= "
01920                                         <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
01921                                         <td><input type='text' name='parameters[".$name."][]'></td></tr>";
01922                                 }
01923                                 $buffer .= '</table>';
01924                         // if scalar
01925                         } else {
01926                                 $buffer .= "<input type='text' name='parameters[$name]'>";
01927                         }
01928                 } else {
01929                         $buffer .= "<input type='text' name='parameters[$name]'>";
01930                 }
01931                 return $buffer;
01932         }
01933         
01975         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
01976                 $this->complexTypes[$name] = array(
01977             'name'              => $name,
01978             'typeClass' => $typeClass,
01979             'phpType'   => $phpType,
01980                 'compositor'=> $compositor,
01981             'restrictionBase' => $restrictionBase,
01982                 'elements'      => $elements,
01983             'attrs'             => $attrs,
01984             'arrayType' => $arrayType
01985                 );
01986                 
01987                 $this->xdebug("addComplexType $name:");
01988                 $this->appendDebug($this->varDump($this->complexTypes[$name]));
01989         }
01990         
02003         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
02004                 $this->simpleTypes[$name] = array(
02005             'name'                      => $name,
02006             'typeClass'         => $typeClass,
02007             'phpType'           => $phpType,
02008             'type'                      => $restrictionBase,
02009             'enumeration'       => $enumeration
02010                 );
02011                 
02012                 $this->xdebug("addSimpleType $name:");
02013                 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
02014         }
02015 
02023         function addElement($attrs) {
02024                 if (! $this->getPrefix($attrs['type'])) {
02025                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
02026                 }
02027                 $this->elements[ $attrs['name'] ] = $attrs;
02028                 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
02029                 
02030                 $this->xdebug("addElement " . $attrs['name']);
02031                 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
02032         }
02033 }
02034 
02038 class XMLSchema extends nusoap_xmlschema {
02039 }
02040 
02041 ?><?php
02042 
02043 
02044 
02056 class soapval extends nusoap_base {
02063         var $name;
02070         var $type;
02077         var $value;
02084         var $element_ns;
02091         var $type_ns;
02098         var $attributes;
02099 
02111         function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
02112                 parent::nusoap_base();
02113                 $this->name = $name;
02114                 $this->type = $type;
02115                 $this->value = $value;
02116                 $this->element_ns = $element_ns;
02117                 $this->type_ns = $type_ns;
02118                 $this->attributes = $attributes;
02119     }
02120 
02128         function serialize($use='encoded') {
02129                 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
02130     }
02131 
02138         function decode(){
02139                 return $this->value;
02140         }
02141 }
02142 
02143 
02144 
02145 ?><?php
02146 
02147 
02148 
02158 class soap_transport_http extends nusoap_base {
02159 
02160         var $url = '';
02161         var $uri = '';
02162         var $digest_uri = '';
02163         var $scheme = '';
02164         var $host = '';
02165         var $port = '';
02166         var $path = '';
02167         var $request_method = 'POST';
02168         var $protocol_version = '1.0';
02169         var $encoding = '';
02170         var $outgoing_headers = array();
02171         var $incoming_headers = array();
02172         var $incoming_cookies = array();
02173         var $outgoing_payload = '';
02174         var $incoming_payload = '';
02175         var $response_status_line;      // HTTP response status line
02176         var $useSOAPAction = true;
02177         var $persistentConnection = false;
02178         var $ch = false;        // cURL handle
02179         var $ch_options = array();      // cURL custom options
02180         var $use_curl = false;          // force cURL use
02181         var $proxy = null;                      // proxy information (associative array)
02182         var $username = '';
02183         var $password = '';
02184         var $authtype = '';
02185         var $digestRequest = array();
02186         var $certRequest = array();     // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
02187                                                                 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
02188                                                                 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
02189                                                                 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
02190                                                                 // passphrase: SSL key password/passphrase
02191                                                                 // certpassword: SSL certificate password
02192                                                                 // verifypeer: default is 1
02193                                                                 // verifyhost: default is 1
02194 
02203         function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
02204                 parent::nusoap_base();
02205                 $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
02206                 $this->appendDebug($this->varDump($curl_options));
02207                 $this->setURL($url);
02208                 if (is_array($curl_options)) {
02209                         $this->ch_options = $curl_options;
02210                 }
02211                 $this->use_curl = $use_curl;
02212                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
02213                 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
02214         }
02215 
02223         function setCurlOption($option, $value) {
02224                 $this->debug("setCurlOption option=$option, value=");
02225                 $this->appendDebug($this->varDump($value));
02226                 curl_setopt($this->ch, $option, $value);
02227         }
02228 
02236         function setHeader($name, $value) {
02237                 $this->outgoing_headers[$name] = $value;
02238                 $this->debug("set header $name: $value");
02239         }
02240 
02247         function unsetHeader($name) {
02248                 if (isset($this->outgoing_headers[$name])) {
02249                         $this->debug("unset header $name");
02250                         unset($this->outgoing_headers[$name]);
02251                 }
02252         }
02253 
02260         function setURL($url) {
02261                 $this->url = $url;
02262 
02263                 $u = parse_url($url);
02264                 foreach($u as $k => $v){
02265                         $this->debug("parsed URL $k = $v");
02266                         $this->$k = $v;
02267                 }
02268                 
02269                 // add any GET params to path
02270                 if(isset($u['query']) && $u['query'] != ''){
02271             $this->path .= '?' . $u['query'];
02272                 }
02273                 
02274                 // set default port
02275                 if(!isset($u['port'])){
02276                         if($u['scheme'] == 'https'){
02277                                 $this->port = 443;
02278                         } else {
02279                                 $this->port = 80;
02280                         }
02281                 }
02282                 
02283                 $this->uri = $this->path;
02284                 $this->digest_uri = $this->uri;
02285                 
02286                 // build headers
02287                 if (!isset($u['port'])) {
02288                         $this->setHeader('Host', $this->host);
02289                 } else {
02290                         $this->setHeader('Host', $this->host.':'.$this->port);
02291                 }
02292 
02293                 if (isset($u['user']) && $u['user'] != '') {
02294                         $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
02295                 }
02296         }
02297 
02304         function io_method() {
02305                 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
02306                         return 'curl';
02307                 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
02308                         return 'socket';
02309                 return 'unknown';
02310         }
02311 
02320         function connect($connection_timeout=0,$response_timeout=30){
02321                 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
02322                 // "regular" socket.
02323                 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
02324                 //       loaded), and until PHP5 stream_get_wrappers is not available.
02325 //              if ($this->scheme == 'https') {
02326 //                      if (version_compare(phpversion(), '4.3.0') >= 0) {
02327 //                              if (extension_loaded('openssl')) {
02328 //                                      $this->scheme = 'ssl';
02329 //                                      $this->debug('Using SSL over OpenSSL');
02330 //                              }
02331 //                      }
02332 //              }
02333                 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
02334           if ($this->io_method() == 'socket') {
02335                 if (!is_array($this->proxy)) {
02336                         $host = $this->host;
02337                         $port = $this->port;
02338                 } else {
02339                         $host = $this->proxy['host'];
02340                         $port = $this->proxy['port'];
02341                 }
02342 
02343                 // use persistent connection
02344                 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
02345                         if (!feof($this->fp)) {
02346                                 $this->debug('Re-use persistent connection');
02347                                 return true;
02348                         }
02349                         fclose($this->fp);
02350                         $this->debug('Closed persistent connection at EOF');
02351                 }
02352 
02353                 // munge host if using OpenSSL
02354                 if ($this->scheme == 'ssl') {
02355                         $host = 'ssl://' . $host;
02356                 }
02357                 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
02358 
02359                 // open socket
02360                 if($connection_timeout > 0){
02361                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
02362                 } else {
02363                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
02364                 }
02365                 
02366                 // test pointer
02367                 if(!$this->fp) {
02368                         $msg = 'Couldn\'t open socket connection to server ' . $this->url;
02369                         if ($this->errno) {
02370                                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
02371                         } else {
02372                                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';
02373                         }
02374                         $this->debug($msg);
02375                         $this->setError($msg);
02376                         return false;
02377                 }
02378                 
02379                 // set response timeout
02380                 $this->debug('set response timeout to ' . $response_timeout);
02381                 socket_set_timeout( $this->fp, $response_timeout);
02382 
02383                 $this->debug('socket connected');
02384                 return true;
02385           } else if ($this->io_method() == 'curl') {
02386                 if (!extension_loaded('curl')) {
02387 //                      $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
02388                         $this->setError('The PHP cURL Extension is required for HTTPS or NLTM.  You will need to re-build or update your PHP to included cURL.');
02389                         return false;
02390                 }
02391                 // Avoid warnings when PHP does not have these options
02392                 if (defined('CURLOPT_CONNECTIONTIMEOUT'))
02393                         $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
02394                 else
02395                         $CURLOPT_CONNECTIONTIMEOUT = 78;
02396                 if (defined('CURLOPT_HTTPAUTH'))
02397                         $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
02398                 else
02399                         $CURLOPT_HTTPAUTH = 107;
02400                 if (defined('CURLOPT_PROXYAUTH'))
02401                         $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
02402                 else
02403                         $CURLOPT_PROXYAUTH = 111;
02404                 if (defined('CURLAUTH_BASIC'))
02405                         $CURLAUTH_BASIC = CURLAUTH_BASIC;
02406                 else
02407                         $CURLAUTH_BASIC = 1;
02408                 if (defined('CURLAUTH_DIGEST'))
02409                         $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
02410                 else
02411                         $CURLAUTH_DIGEST = 2;
02412                 if (defined('CURLAUTH_NTLM'))
02413                         $CURLAUTH_NTLM = CURLAUTH_NTLM;
02414                 else
02415                         $CURLAUTH_NTLM = 8;
02416 
02417                 $this->debug('connect using cURL');
02418                 // init CURL
02419                 $this->ch = curl_init();
02420                 // set url
02421                 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
02422                 // add path
02423                 $hostURL .= $this->path;
02424                 $this->setCurlOption(CURLOPT_URL, $hostURL);
02425                 // follow location headers (re-directs)
02426                 if (ini_get('safe_mode') || ini_get('open_basedir')) {
02427                         $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
02428                         $this->debug('safe_mode = ');
02429                         $this->appendDebug($this->varDump(ini_get('safe_mode')));
02430                         $this->debug('open_basedir = ');
02431                         $this->appendDebug($this->varDump(ini_get('open_basedir')));
02432                 } else {
02433                         $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
02434                 }
02435                 // ask for headers in the response output
02436                 $this->setCurlOption(CURLOPT_HEADER, 1);
02437                 // ask for the response output as the return value
02438                 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
02439                 // encode
02440                 // We manage this ourselves through headers and encoding
02441 //              if(function_exists('gzuncompress')){
02442 //                      $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
02443 //              }
02444                 // persistent connection
02445                 if ($this->persistentConnection) {
02446                         // I believe the following comment is now bogus, having applied to
02447                         // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
02448                         // The way we send data, we cannot use persistent connections, since
02449                         // there will be some "junk" at the end of our request.
02450                         //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
02451                         $this->persistentConnection = false;
02452                         $this->setHeader('Connection', 'close');
02453                 }
02454                 // set timeouts
02455                 if ($connection_timeout != 0) {
02456                         $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
02457                 }
02458                 if ($response_timeout != 0) {
02459                         $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
02460                 }
02461 
02462                 if ($this->scheme == 'https') {
02463                         $this->debug('set cURL SSL verify options');
02464                         // recent versions of cURL turn on peer/host checking by default,
02465                         // while PHP binaries are not compiled with a default location for the
02466                         // CA cert bundle, so disable peer/host checking.
02467                         //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');             
02468                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
02469                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
02470         
02471                         // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
02472                         if ($this->authtype == 'certificate') {
02473                                 $this->debug('set cURL certificate options');
02474                                 if (isset($this->certRequest['cainfofile'])) {
02475                                         $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
02476                                 }
02477                                 if (isset($this->certRequest['verifypeer'])) {
02478                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
02479                                 } else {
02480                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
02481                                 }
02482                                 if (isset($this->certRequest['verifyhost'])) {
02483                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
02484                                 } else {
02485                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
02486                                 }
02487                                 if (isset($this->certRequest['sslcertfile'])) {
02488                                         $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
02489                                 }
02490                                 if (isset($this->certRequest['sslkeyfile'])) {
02491                                         $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
02492                                 }
02493                                 if (isset($this->certRequest['passphrase'])) {
02494                                         $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
02495                                 }
02496                                 if (isset($this->certRequest['certpassword'])) {
02497                                         $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
02498                                 }
02499                         }
02500                 }
02501                 if ($this->authtype && ($this->authtype != 'certificate')) {
02502                         if ($this->username) {
02503                                 $this->debug('set cURL username/password');
02504                                 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
02505                         }
02506                         if ($this->authtype == 'basic') {
02507                                 $this->debug('set cURL for Basic authentication');
02508                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
02509                         }
02510                         if ($this->authtype == 'digest') {
02511                                 $this->debug('set cURL for digest authentication');
02512                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
02513                         }
02514                         if ($this->authtype == 'ntlm') {
02515                                 $this->debug('set cURL for NTLM authentication');
02516                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
02517                         }
02518                 }
02519                 if (is_array($this->proxy)) {
02520                         $this->debug('set cURL proxy options');
02521                         if ($this->proxy['port'] != '') {
02522                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
02523                         } else {
02524                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
02525                         }
02526                         if ($this->proxy['username'] || $this->proxy['password']) {
02527                                 $this->debug('set cURL proxy authentication options');
02528                                 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
02529                                 if ($this->proxy['authtype'] == 'basic') {
02530                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
02531                                 }
02532                                 if ($this->proxy['authtype'] == 'ntlm') {
02533                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
02534                                 }
02535                         }
02536                 }
02537                 $this->debug('cURL connection set up');
02538                 return true;
02539           } else {
02540                 $this->setError('Unknown scheme ' . $this->scheme);
02541                 $this->debug('Unknown scheme ' . $this->scheme);
02542                 return false;
02543           }
02544         }
02545 
02556         function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
02557                 
02558                 $this->debug('entered send() with data of length: '.strlen($data));
02559 
02560                 $this->tryagain = true;
02561                 $tries = 0;
02562                 while ($this->tryagain) {
02563                         $this->tryagain = false;
02564                         if ($tries++ < 2) {
02565                                 // make connnection
02566                                 if (!$this->connect($timeout, $response_timeout)){
02567                                         return false;
02568                                 }
02569                                 
02570                                 // send request
02571                                 if (!$this->sendRequest($data, $cookies)){
02572                                         return false;
02573                                 }
02574                                 
02575                                 // get response
02576                                 $respdata = $this->getResponse();
02577                         } else {
02578                                 $this->setError("Too many tries to get an OK response ($this->response_status_line)");
02579                         }
02580                 }               
02581                 $this->debug('end of send()');
02582                 return $respdata;
02583         }
02584 
02585 
02597         function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
02598                 return $this->send($data, $timeout, $response_timeout, $cookies);
02599         }
02600         
02611         function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
02612                 $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
02613                 $this->appendDebug($this->varDump($digestRequest));
02614                 $this->debug("certRequest=");
02615                 $this->appendDebug($this->varDump($certRequest));
02616                 // cf. RFC 2617
02617                 if ($authtype == 'basic') {
02618                         $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
02619                 } elseif ($authtype == 'digest') {
02620                         if (isset($digestRequest['nonce'])) {
02621                                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
02622                                 
02623                                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
02624         
02625                                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
02626                                 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
02627         
02628                                 // H(A1) = MD5(A1)
02629                                 $HA1 = md5($A1);
02630         
02631                                 // A2 = Method ":" digest-uri-value
02632                                 $A2 = $this->request_method . ':' . $this->digest_uri;
02633         
02634                                 // H(A2)
02635                                 $HA2 =  md5($A2);
02636         
02637                                 // KD(secret, data) = H(concat(secret, ":", data))
02638                                 // if qop == auth:
02639                                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
02640                                 //                              ":" nc-value
02641                                 //                              ":" unq(cnonce-value)
02642                                 //                              ":" unq(qop-value)
02643                                 //                              ":" H(A2)
02644                                 //                            ) <">
02645                                 // if qop is missing,
02646                                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
02647         
02648                                 $unhashedDigest = '';
02649                                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
02650                                 $cnonce = $nonce;
02651                                 if ($digestRequest['qop'] != '') {
02652                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
02653                                 } else {
02654                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
02655                                 }
02656         
02657                                 $hashedDigest = md5($unhashedDigest);
02658         
02659                                 $opaque = '';   
02660                                 if (isset($digestRequest['opaque'])) {
02661                                         $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
02662                                 }
02663 
02664                                 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
02665                         }
02666                 } elseif ($authtype == 'certificate') {
02667                         $this->certRequest = $certRequest;
02668                         $this->debug('Authorization header not set for certificate');
02669                 } elseif ($authtype == 'ntlm') {
02670                         // do nothing
02671                         $this->debug('Authorization header not set for ntlm');
02672                 }
02673                 $this->username = $username;
02674                 $this->password = $password;
02675                 $this->authtype = $authtype;
02676                 $this->digestRequest = $digestRequest;
02677         }
02678         
02685         function setSOAPAction($soapaction) {
02686                 $this->setHeader('SOAPAction', '"' . $soapaction . '"');
02687         }
02688         
02695         function setEncoding($enc='gzip, deflate') {
02696                 if (function_exists('gzdeflate')) {
02697                         $this->protocol_version = '1.1';
02698                         $this->setHeader('Accept-Encoding', $enc);
02699                         if (!isset($this->outgoing_headers['Connection'])) {
02700                                 $this->setHeader('Connection', 'close');
02701                                 $this->persistentConnection = false;
02702                         }
02703                         set_magic_quotes_runtime(0);
02704                         // deprecated
02705                         $this->encoding = $enc;
02706                 }
02707         }
02708         
02719         function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
02720                 if ($proxyhost) {
02721                         $this->proxy = array(
02722                                 'host' => $proxyhost,
02723                                 'port' => $proxyport,
02724                                 'username' => $proxyusername,
02725                                 'password' => $proxypassword,
02726                                 'authtype' => $proxyauthtype
02727                         );
02728                         if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
02729                                 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
02730                         }
02731                 } else {
02732                         $this->debug('remove proxy');
02733                         $proxy = null;
02734                         unsetHeader('Proxy-Authorization');
02735                 }
02736         }
02737         
02738 
02747         function isSkippableCurlHeader(&$data) {
02748                 $skipHeaders = array(   'HTTP/1.1 100',
02749                                                                 'HTTP/1.0 301',
02750                                                                 'HTTP/1.1 301',
02751                                                                 'HTTP/1.0 302',
02752                                                                 'HTTP/1.1 302',
02753                                                                 'HTTP/1.0 401',
02754                                                                 'HTTP/1.1 401',
02755                                                                 'HTTP/1.0 200 Connection established');
02756                 foreach ($skipHeaders as $hd) {
02757                         $prefix = substr($data, 0, strlen($hd));
02758                         if ($prefix == $hd) return true;
02759                 }
02760 
02761                 return false;
02762         }
02763 
02774         function decodeChunked($buffer, $lb){
02775                 // length := 0
02776                 $length = 0;
02777                 $new = '';
02778                 
02779                 // read chunk-size, chunk-extension (if any) and CRLF
02780                 // get the position of the linebreak
02781                 $chunkend = strpos($buffer, $lb);
02782                 if ($chunkend == FALSE) {
02783                         $this->debug('no linebreak found in decodeChunked');
02784                         return $new;
02785                 }
02786                 $temp = substr($buffer,0,$chunkend);
02787                 $chunk_size = hexdec( trim($temp) );
02788                 $chunkstart = $chunkend + strlen($lb);
02789                 // while (chunk-size > 0) {
02790                 while ($chunk_size > 0) {
02791                         $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
02792                         $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
02793                         
02794                         // Just in case we got a broken connection
02795                         if ($chunkend == FALSE) {
02796                             $chunk = substr($buffer,$chunkstart);
02797                                 // append chunk-data to entity-body
02798                         $new .= $chunk;
02799                             $length += strlen($chunk);
02800                             break;
02801                         }
02802                         
02803                         // read chunk-data and CRLF
02804                         $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
02805                         // append chunk-data to entity-body
02806                         $new .= $chunk;
02807                         // length := length + chunk-size
02808                         $length += strlen($chunk);
02809                         // read chunk-size and CRLF
02810                         $chunkstart = $chunkend + strlen($lb);
02811                         
02812                         $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
02813                         if ($chunkend == FALSE) {
02814                                 break; //Just in case we got a broken connection
02815                         }
02816                         $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
02817                         $chunk_size = hexdec( trim($temp) );
02818                         $chunkstart = $chunkend;
02819                 }
02820                 return $new;
02821         }
02822         
02831         function buildPayload($data, $cookie_str = '') {
02832                 // Note: for cURL connections, $this->outgoing_payload is ignored,
02833                 // as is the Content-Length header, but these are still created as
02834                 // debugging guides.
02835 
02836                 // add content-length header
02837                 if ($this->request_method != 'GET') {
02838                         $this->setHeader('Content-Length', strlen($data));
02839                 }
02840 
02841                 // start building outgoing payload:
02842                 if ($this->proxy) {
02843                         $uri = $this->url;
02844                 } else {
02845                         $uri = $this->uri;
02846                 }
02847                 $req = "$this->request_method $uri HTTP/$this->protocol_version";
02848                 $this->debug("HTTP request: $req");
02849                 $this->outgoing_payload = "$req\r\n";
02850 
02851                 // loop thru headers, serializing
02852                 foreach($this->outgoing_headers as $k => $v){
02853                         $hdr = $k.': '.$v;
02854                         $this->debug("HTTP header: $hdr");
02855                         $this->outgoing_payload .= "$hdr\r\n";
02856                 }
02857 
02858                 // add any cookies
02859                 if ($cookie_str != '') {
02860                         $hdr = 'Cookie: '.$cookie_str;
02861                         $this->debug("HTTP header: $hdr");
02862                         $this->outgoing_payload .= "$hdr\r\n";
02863                 }
02864 
02865                 // header/body separator
02866                 $this->outgoing_payload .= "\r\n";
02867                 
02868                 // add data
02869                 $this->outgoing_payload .= $data;
02870         }
02871 
02880         function sendRequest($data, $cookies = NULL) {
02881                 // build cookie string
02882                 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
02883 
02884                 // build payload
02885                 $this->buildPayload($data, $cookie_str);
02886 
02887           if ($this->io_method() == 'socket') {
02888                 // send payload
02889                 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
02890                         $this->setError('couldn\'t write message data to socket');
02891                         $this->debug('couldn\'t write message data to socket');
02892                         return false;
02893                 }
02894                 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
02895                 return true;
02896           } else if ($this->io_method() == 'curl') {
02897                 // set payload
02898                 // cURL does say this should only be the verb, and in fact it
02899                 // turns out that the URI and HTTP version are appended to this, which
02900                 // some servers refuse to work with (so we no longer use this method!)
02901                 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
02902                 $curl_headers = array();
02903                 foreach($this->outgoing_headers as $k => $v){
02904                         if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
02905                                 $this->debug("Skip cURL header $k: $v");
02906                         } else {
02907                                 $curl_headers[] = "$k: $v";
02908                         }
02909                 }
02910                 if ($cookie_str != '') {
02911                         $curl_headers[] = 'Cookie: ' . $cookie_str;
02912                 }
02913                 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
02914                 $this->debug('set cURL HTTP headers');
02915                 if ($this->request_method == "POST") {
02916                         $this->setCurlOption(CURLOPT_POST, 1);
02917                         $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
02918                         $this->debug('set cURL POST data');
02919                 } else {
02920                 }
02921                 // insert custom user-set cURL options
02922                 foreach ($this->ch_options as $key => $val) {
02923                         $this->setCurlOption($key, $val);
02924                 }
02925 
02926                 $this->debug('set cURL payload');
02927                 return true;
02928           }
02929         }
02930 
02937         function getResponse(){
02938                 $this->incoming_payload = '';
02939             
02940           if ($this->io_method() == 'socket') {
02941             // loop until headers have been retrieved
02942             $data = '';
02943             while (!isset($lb)){
02944 
02945                         // We might EOF during header read.
02946                         if(feof($this->fp)) {
02947                                 $this->incoming_payload = $data;
02948                                 $this->debug('found no headers before EOF after length ' . strlen($data));
02949                                 $this->debug("received before EOF:\n" . $data);
02950                                 $this->setError('server failed to send headers');
02951                                 return false;
02952                         }
02953 
02954                         $tmp = fgets($this->fp, 256);
02955                         $tmplen = strlen($tmp);
02956                         $this->debug("read line of $tmplen bytes: " . trim($tmp));
02957 
02958                         if ($tmplen == 0) {
02959                                 $this->incoming_payload = $data;
02960                                 $this->debug('socket read of headers timed out after length ' . strlen($data));
02961                                 $this->debug("read before timeout: " . $data);
02962                                 $this->setError('socket read of headers timed out');
02963                                 return false;
02964                         }
02965 
02966                         $data .= $tmp;
02967                         $pos = strpos($data,"\r\n\r\n");
02968                         if($pos > 1){
02969                                 $lb = "\r\n";
02970                         } else {
02971                                 $pos = strpos($data,"\n\n");
02972                                 if($pos > 1){
02973                                         $lb = "\n";
02974                                 }
02975                         }
02976                         // remove 100 headers
02977                         if (isset($lb) && ereg('^HTTP/1.1 100',$data)) {
02978                                 unset($lb);
02979                                 $data = '';
02980                         }//
02981                 }
02982                 // store header data
02983                 $this->incoming_payload .= $data;
02984                 $this->debug('found end of headers after length ' . strlen($data));
02985                 // process headers
02986                 $header_data = trim(substr($data,0,$pos));
02987                 $header_array = explode($lb,$header_data);
02988                 $this->incoming_headers = array();
02989                 $this->incoming_cookies = array();
02990                 foreach($header_array as $header_line){
02991                         $arr = explode(':',$header_line, 2);
02992                         if(count($arr) > 1){
02993                                 $header_name = strtolower(trim($arr[0]));
02994                                 $this->incoming_headers[$header_name] = trim($arr[1]);
02995                                 if ($header_name == 'set-cookie') {
02996                                         // TODO: allow multiple cookies from parseCookie
02997                                         $cookie = $this->parseCookie(trim($arr[1]));
02998                                         if ($cookie) {
02999                                                 $this->incoming_cookies[] = $cookie;
03000                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
03001                                         } else {
03002                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
03003                                         }
03004                         }
03005                         } else if (isset($header_name)) {
03006                                 // append continuation line to previous header
03007                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
03008                         }
03009                 }
03010                 
03011                 // loop until msg has been received
03012                 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
03013                         $content_length =  2147483647;  // ignore any content-length header
03014                         $chunked = true;
03015                         $this->debug("want to read chunked content");
03016                 } elseif (isset($this->incoming_headers['content-length'])) {
03017                         $content_length = $this->incoming_headers['content-length'];
03018                         $chunked = false;
03019                         $this->debug("want to read content of length $content_length");
03020                 } else {
03021                         $content_length =  2147483647;
03022                         $chunked = false;
03023                         $this->debug("want to read content to EOF");
03024                 }
03025                 $data = '';
03026                 do {
03027                         if ($chunked) {
03028                                 $tmp = fgets($this->fp, 256);
03029                                 $tmplen = strlen($tmp);
03030                                 $this->debug("read chunk line of $tmplen bytes");
03031                                 if ($tmplen == 0) {
03032                                         $this->incoming_payload = $data;
03033                                         $this->debug('socket read of chunk length timed out after length ' . strlen($data));
03034                                         $this->debug("read before timeout:\n" . $data);
03035                                         $this->setError('socket read of chunk length timed out');
03036                                         return false;
03037                                 }
03038                                 $content_length = hexdec(trim($tmp));
03039                                 $this->debug("chunk length $content_length");
03040                         }
03041                         $strlen = 0;
03042                     while (($strlen < $content_length) && (!feof($this->fp))) {
03043                         $readlen = min(8192, $content_length - $strlen);
03044                                 $tmp = fread($this->fp, $readlen);
03045                                 $tmplen = strlen($tmp);
03046                                 $this->debug("read buffer of $tmplen bytes");
03047                                 if (($tmplen == 0) && (!feof($this->fp))) {
03048                                         $this->incoming_payload = $data;
03049                                         $this->debug('socket read of body timed out after length ' . strlen($data));
03050                                         $this->debug("read before timeout:\n" . $data);
03051                                         $this->setError('socket read of body timed out');
03052                                         return false;
03053                                 }
03054                                 $strlen += $tmplen;
03055                                 $data .= $tmp;
03056                         }
03057                         if ($chunked && ($content_length > 0)) {
03058                                 $tmp = fgets($this->fp, 256);
03059                                 $tmplen = strlen($tmp);
03060                                 $this->debug("read chunk terminator of $tmplen bytes");
03061                                 if ($tmplen == 0) {
03062                                         $this->incoming_payload = $data;
03063                                         $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
03064                                         $this->debug("read before timeout:\n" . $data);
03065                                         $this->setError('socket read of chunk terminator timed out');
03066                                         return false;
03067                                 }
03068                         }
03069                 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
03070                 if (feof($this->fp)) {
03071                         $this->debug('read to EOF');
03072                 }
03073                 $this->debug('read body of length ' . strlen($data));
03074                 $this->incoming_payload .= $data;
03075                 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
03076                 
03077                 // close filepointer
03078                 if(
03079                         (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 
03080                         (! $this->persistentConnection) || feof($this->fp)){
03081                         fclose($this->fp);
03082                         $this->fp = false;
03083                         $this->debug('closed socket');
03084                 }
03085                 
03086                 // connection was closed unexpectedly
03087                 if($this->incoming_payload == ''){
03088                         $this->setError('no response from server');
03089                         return false;
03090                 }
03091                 
03092                 // decode transfer-encoding
03093 //              if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
03094 //                      if(!$data = $this->decodeChunked($data, $lb)){
03095 //                              $this->setError('Decoding of chunked data failed');
03096 //                              return false;
03097 //                      }
03098                         //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
03099                         // set decoded payload
03100 //                      $this->incoming_payload = $header_data.$lb.$lb.$data;
03101 //              }
03102         
03103           } else if ($this->io_method() == 'curl') {
03104                 // send and receive
03105                 $this->debug('send and receive with cURL');
03106                 $this->incoming_payload = curl_exec($this->ch);
03107                 $data = $this->incoming_payload;
03108 
03109         $cErr = curl_error($this->ch);
03110                 if ($cErr != '') {
03111                 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
03112                 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
03113                         foreach(curl_getinfo($this->ch) as $k => $v){
03114                                 $err .= "$k: $v<br>";
03115                         }
03116                         $this->debug($err);
03117                         $this->setError($err);
03118                         curl_close($this->ch);
03119                 return false;
03120                 } else {
03121                         //echo '<pre>';
03122                         //var_dump(curl_getinfo($this->ch));
03123                         //echo '</pre>';
03124                 }
03125                 // close curl
03126                 $this->debug('No cURL error, closing cURL');
03127                 curl_close($this->ch);
03128                 
03129                 // try removing skippable headers
03130                 $savedata = $data;
03131                 while ($this->isSkippableCurlHeader($data)) {
03132                         $this->debug("Found HTTP header to skip");
03133                         if ($pos = strpos($data,"\r\n\r\n")) {
03134                                 $data = ltrim(substr($data,$pos));
03135                         } elseif($pos = strpos($data,"\n\n") ) {
03136                                 $data = ltrim(substr($data,$pos));
03137                         }
03138                 }
03139 
03140                 if ($data == '') {
03141                         // have nothing left; just remove 100 header(s)
03142                         $data = $savedata;
03143                         while (ereg('^HTTP/1.1 100',$data)) {
03144                                 if ($pos = strpos($data,"\r\n\r\n")) {
03145                                         $data = ltrim(substr($data,$pos));
03146                                 } elseif($pos = strpos($data,"\n\n") ) {
03147                                         $data = ltrim(substr($data,$pos));
03148                                 }
03149                         }
03150                 }
03151                 
03152                 // separate content from HTTP headers
03153                 if ($pos = strpos($data,"\r\n\r\n")) {
03154                         $lb = "\r\n";
03155                 } elseif( $pos = strpos($data,"\n\n")) {
03156                         $lb = "\n";
03157                 } else {
03158                         $this->debug('no proper separation of headers and document');
03159                         $this->setError('no proper separation of headers and document');
03160                         return false;
03161                 }
03162                 $header_data = trim(substr($data,0,$pos));
03163                 $header_array = explode($lb,$header_data);
03164                 $data = ltrim(substr($data,$pos));
03165                 $this->debug('found proper separation of headers and document');
03166                 $this->debug('cleaned data, stringlen: '.strlen($data));
03167                 // clean headers
03168                 foreach ($header_array as $header_line) {
03169                         $arr = explode(':',$header_line,2);
03170                         if(count($arr) > 1){
03171                                 $header_name = strtolower(trim($arr[0]));
03172                                 $this->incoming_headers[$header_name] = trim($arr[1]);
03173                                 if ($header_name == 'set-cookie') {
03174                                         // TODO: allow multiple cookies from parseCookie
03175                                         $cookie = $this->parseCookie(trim($arr[1]));
03176                                         if ($cookie) {
03177                                                 $this->incoming_cookies[] = $cookie;
03178                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
03179                                         } else {
03180                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
03181                                         }
03182                         }
03183                         } else if (isset($header_name)) {
03184                                 // append continuation line to previous header
03185                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
03186                         }
03187                 }
03188           }
03189 
03190                 $this->response_status_line = $header_array[0];
03191                 $arr = explode(' ', $this->response_status_line, 3);
03192                 $http_version = $arr[0];
03193                 $http_status = intval($arr[1]);
03194                 $http_reason = count($arr) > 2 ? $arr[2] : '';
03195 
03196                 // see if we need to resend the request with http digest authentication
03197                 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
03198                         $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
03199                         $this->setURL($this->incoming_headers['location']);
03200                         $this->tryagain = true;
03201                         return false;
03202                 }
03203 
03204                 // see if we need to resend the request with http digest authentication
03205                 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
03206                         $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
03207                         if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
03208                                 $this->debug('Server wants digest authentication');
03209                                 // remove "Digest " from our elements
03210                                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
03211                                 
03212                                 // parse elements into array
03213                                 $digestElements = explode(',', $digestString);
03214                                 foreach ($digestElements as $val) {
03215                                         $tempElement = explode('=', trim($val), 2);
03216                                         $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
03217                                 }
03218 
03219                                 // should have (at least) qop, realm, nonce
03220                                 if (isset($digestRequest['nonce'])) {
03221                                         $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
03222                                         $this->tryagain = true;
03223                                         return false;
03224                                 }
03225                         }
03226                         $this->debug('HTTP authentication failed');
03227                         $this->setError('HTTP authentication failed');
03228                         return false;
03229                 }
03230                 
03231                 if (
03232                         ($http_status >= 300 && $http_status <= 307) ||
03233                         ($http_status >= 400 && $http_status <= 417) ||
03234                         ($http_status >= 501 && $http_status <= 505)
03235                    ) {
03236                         $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
03237                         return false;
03238                 }
03239 
03240                 // decode content-encoding
03241                 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
03242                         if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
03243                         // if decoding works, use it. else assume data wasn't gzencoded
03244                         if(function_exists('gzinflate')){
03245                                         //$timer->setMarker('starting decoding of gzip/deflated content');
03246                                         // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
03247                                         // this means there are no Zlib headers, although there should be
03248                                         $this->debug('The gzinflate function exists');
03249                                         $datalen = strlen($data);
03250                                         if ($this->incoming_headers['content-encoding'] == 'deflate') {
03251                                                 if ($degzdata = @gzinflate($data)) {
03252                                                 $data = $degzdata;
03253                                                 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
03254                                                 if (strlen($data) < $datalen) {
03255                                                         // test for the case that the payload has been compressed twice
03256                                                         $this->debug('The inflated payload is smaller than the gzipped one; try again');
03257                                                                 if ($degzdata = @gzinflate($data)) {
03258                                                                 $data = $degzdata;
03259                                                                 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
03260                                                                 }
03261                                                 }
03262                                         } else {
03263                                                 $this->debug('Error using gzinflate to inflate the payload');
03264                                                 $this->setError('Error using gzinflate to inflate the payload');
03265                                         }
03266                                         } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
03267                                                 if ($degzdata = @gzinflate(substr($data, 10))) {        // do our best
03268                                                         $data = $degzdata;
03269                                                 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
03270                                                 if (strlen($data) < $datalen) {
03271                                                         // test for the case that the payload has been compressed twice
03272                                                         $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
03273                                                                 if ($degzdata = @gzinflate(substr($data, 10))) {
03274                                                                 $data = $degzdata;
03275                                                                 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
03276                                                                 }
03277                                                 }
03278                                         } else {
03279                                                 $this->debug('Error using gzinflate to un-gzip the payload');
03280                                                         $this->setError('Error using gzinflate to un-gzip the payload');
03281                                         }
03282                                         }
03283                                         //$timer->setMarker('finished decoding of gzip/deflated content');
03284                                         //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
03285                                         // set decoded payload
03286                                         $this->incoming_payload = $header_data.$lb.$lb.$data;
03287                         } else {
03288                                         $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
03289                                         $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
03290                                 }
03291                         } else {
03292                                 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
03293                                 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
03294                         }
03295                 } else {
03296                         $this->debug('No Content-Encoding header');
03297                 }
03298                 
03299                 if(strlen($data) == 0){
03300                         $this->debug('no data after headers!');
03301                         $this->setError('no data present after HTTP headers');
03302                         return false;
03303                 }
03304                 
03305                 return $data;
03306         }
03307 
03315         function setContentType($type, $charset = false) {
03316                 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
03317         }
03318 
03325         function usePersistentConnection(){
03326                 if (isset($this->outgoing_headers['Accept-Encoding'])) {
03327                         return false;
03328                 }
03329                 $this->protocol_version = '1.1';
03330                 $this->persistentConnection = true;
03331                 $this->setHeader('Connection', 'Keep-Alive');
03332                 return true;
03333         }
03334 
03342         /*
03343          * TODO: allow a Set-Cookie string to be parsed into multiple cookies
03344          */
03345         function parseCookie($cookie_str) {
03346                 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
03347                 $data = split(';', $cookie_str);
03348                 $value_str = $data[0];
03349 
03350                 $cookie_param = 'domain=';
03351                 $start = strpos($cookie_str, $cookie_param);
03352                 if ($start > 0) {
03353                         $domain = substr($cookie_str, $start + strlen($cookie_param));
03354                         $domain = substr($domain, 0, strpos($domain, ';'));
03355                 } else {
03356                         $domain = '';
03357                 }
03358 
03359                 $cookie_param = 'expires=';
03360                 $start = strpos($cookie_str, $cookie_param);
03361                 if ($start > 0) {
03362                         $expires = substr($cookie_str, $start + strlen($cookie_param));
03363                         $expires = substr($expires, 0, strpos($expires, ';'));
03364                 } else {
03365                         $expires = '';
03366                 }
03367 
03368                 $cookie_param = 'path=';
03369                 $start = strpos($cookie_str, $cookie_param);
03370                 if ( $start > 0 ) {
03371                         $path = substr($cookie_str, $start + strlen($cookie_param));
03372                         $path = substr($path, 0, strpos($path, ';'));
03373                 } else {
03374                         $path = '/';
03375                 }
03376                                                 
03377                 $cookie_param = ';secure;';
03378                 if (strpos($cookie_str, $cookie_param) !== FALSE) {
03379                         $secure = true;
03380                 } else {
03381                         $secure = false;
03382                 }
03383 
03384                 $sep_pos = strpos($value_str, '=');
03385 
03386                 if ($sep_pos) {
03387                         $name = substr($value_str, 0, $sep_pos);
03388                         $value = substr($value_str, $sep_pos + 1);
03389                         $cookie= array( 'name' => $name,
03390                                         'value' => $value,
03391                                                         'domain' => $domain,
03392                                                         'path' => $path,
03393                                                         'expires' => $expires,
03394                                                         'secure' => $secure
03395                                                         );              
03396                         return $cookie;
03397                 }
03398                 return false;
03399         }
03400   
03409         function getCookiesForRequest($cookies, $secure=false) {
03410                 $cookie_str = '';
03411                 if ((! is_null($cookies)) && (is_array($cookies))) {
03412                         foreach ($cookies as $cookie) {
03413                                 if (! is_array($cookie)) {
03414                                         continue;
03415                                 }
03416                         $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
03417                                 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
03418                                         if (strtotime($cookie['expires']) <= time()) {
03419                                                 $this->debug('cookie has expired');
03420                                                 continue;
03421                                         }
03422                                 }
03423                                 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
03424                                         $domain = preg_quote($cookie['domain']);
03425                                         if (! preg_match("'.*$domain$'i", $this->host)) {
03426                                                 $this->debug('cookie has different domain');
03427                                                 continue;
03428                                         }
03429                                 }
03430                                 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
03431                                         $path = preg_quote($cookie['path']);
03432                                         if (! preg_match("'^$path.*'i", $this->path)) {
03433                                                 $this->debug('cookie is for a different path');
03434                                                 continue;
03435                                         }
03436                                 }
03437                                 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
03438                                         $this->debug('cookie is secure, transport is not');
03439                                         continue;
03440                                 }
03441                                 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
03442                         $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
03443                         }
03444                 }
03445                 return $cookie_str;
03446   }
03447 }
03448 
03449 ?><?php
03450 
03451 
03452 
03463 class nusoap_server extends nusoap_base {
03469         var $headers = array();
03475         var $request = '';
03481         var $requestHeaders = '';
03487         var $requestHeader = NULL;
03493         var $document = '';
03499         var $requestSOAP = '';
03505         var $methodURI = '';
03511         var $methodname = '';
03517         var $methodparams = array();
03523         var $SOAPAction = '';
03529         var $xml_encoding = '';
03535     var $decode_utf8 = true;
03536 
03542         var $outgoing_headers = array();
03548         var $response = '';
03554         var $responseHeaders = '';
03560         var $responseSOAP = '';
03566         var $methodreturn = false;
03572         var $methodreturnisliteralxml = false;
03578         var $fault = false;
03584         var $result = 'successful';
03585 
03592         var $operations = array();
03598         var $wsdl = false;
03604         var $externalWSDLURL = false;
03610         var $debug_flag = false;
03611 
03612 
03620         function nusoap_server($wsdl=false){
03621                 parent::nusoap_base();
03622                 // turn on debugging?
03623                 global $debug;
03624                 global $HTTP_SERVER_VARS;
03625 
03626                 if (isset($_SERVER)) {
03627                         $this->debug("_SERVER is defined:");
03628                         $this->appendDebug($this->varDump($_SERVER));
03629                 } elseif (isset($HTTP_SERVER_VARS)) {
03630                         $this->debug("HTTP_SERVER_VARS is defined:");
03631                         $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
03632                 } else {
03633                         $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
03634                 }
03635 
03636                 if (isset($debug)) {
03637                         $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
03638                         $this->debug_flag = $debug;
03639                 } elseif (isset($_SERVER['QUERY_STRING'])) {
03640                         $qs = explode('&', $_SERVER['QUERY_STRING']);
03641                         foreach ($qs as $v) {
03642                                 if (substr($v, 0, 6) == 'debug=') {
03643                                         $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
03644                                         $this->debug_flag = substr($v, 6);
03645                                 }
03646                         }
03647                 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
03648                         $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
03649                         foreach ($qs as $v) {
03650                                 if (substr($v, 0, 6) == 'debug=') {
03651                                         $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
03652                                         $this->debug_flag = substr($v, 6);
03653                                 }
03654                         }
03655                 }
03656 
03657                 // wsdl
03658                 if($wsdl){
03659                         $this->debug("In nusoap_server, WSDL is specified");
03660                         if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
03661                                 $this->wsdl = $wsdl;
03662                                 $this->externalWSDLURL = $this->wsdl->wsdl;
03663                                 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
03664                         } else {
03665                                 $this->debug('Create wsdl from ' . $wsdl);
03666                                 $this->wsdl = new wsdl($wsdl);
03667                                 $this->externalWSDLURL = $wsdl;
03668                         }
03669                         $this->appendDebug($this->wsdl->getDebug());
03670                         $this->wsdl->clearDebug();
03671                         if($err = $this->wsdl->getError()){
03672                                 die('WSDL ERROR: '.$err);
03673                         }
03674                 }
03675         }
03676 
03683         function service($data){
03684                 global $HTTP_SERVER_VARS;
03685 
03686                 if (isset($_SERVER['REQUEST_METHOD'])) {
03687                         $rm = $_SERVER['REQUEST_METHOD'];
03688                 } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
03689                         $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
03690                 } else {
03691                         $rm = '';
03692                 }
03693 
03694                 if (isset($_SERVER['QUERY_STRING'])) {
03695                         $qs = $_SERVER['QUERY_STRING'];
03696                 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
03697                         $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
03698                 } else {
03699                         $qs = '';
03700                 }
03701                 $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
03702 
03703                 if ($rm == 'POST') {
03704                         $this->debug("In service, invoke the request");
03705                         $this->parse_request($data);
03706                         if (! $this->fault) {
03707                                 $this->invoke_method();
03708                         }
03709                         if (! $this->fault) {
03710                                 $this->serialize_return();
03711                         }
03712                         $this->send_response();
03713                 } elseif (ereg('wsdl', $qs) ){
03714                         $this->debug("In service, this is a request for WSDL");
03715                         if ($this->externalWSDLURL){
03716               if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
03717                                 $this->debug("In service, re-direct for WSDL");
03718                                 header('Location: '.$this->externalWSDLURL);
03719               } else { // assume file
03720                                 $this->debug("In service, use file passthru for WSDL");
03721                 header("Content-Type: text/xml\r\n");
03722                                 $pos = strpos($this->externalWSDLURL, "file://");
03723                                 if ($pos === false) {
03724                                         $filename = $this->externalWSDLURL;
03725                                 } else {
03726                                         $filename = substr($this->externalWSDLURL, $pos + 7);
03727                                 }
03728                 $fp = fopen($this->externalWSDLURL, 'r');
03729                 fpassthru($fp);
03730               }
03731                         } elseif ($this->wsdl) {
03732                                 $this->debug("In service, serialize WSDL");
03733                                 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
03734                                 print $this->wsdl->serialize($this->debug_flag);
03735                                 if ($this->debug_flag) {
03736                                         $this->debug('wsdl:');
03737                                         $this->appendDebug($this->varDump($this->wsdl));
03738                                         print $this->getDebugAsXMLComment();
03739                                 }
03740                         } else {
03741                                 $this->debug("In service, there is no WSDL");
03742                                 header("Content-Type: text/html; charset=ISO-8859-1\r\n");
03743                                 print "This service does not provide WSDL";
03744                         }
03745                 } elseif ($this->wsdl) {
03746                         $this->debug("In service, return Web description");
03747                         print $this->wsdl->webDescription();
03748                 } else {
03749                         $this->debug("In service, no Web description");
03750                         header("Content-Type: text/html; charset=ISO-8859-1\r\n");
03751                         print "This service does not provide a Web description";
03752                 }
03753         }
03754 
03767         function parse_http_headers() {
03768                 global $HTTP_SERVER_VARS;
03769 
03770                 $this->request = '';
03771                 $this->SOAPAction = '';
03772                 if(function_exists('getallheaders')){
03773                         $this->debug("In parse_http_headers, use getallheaders");
03774                         $headers = getallheaders();
03775                         foreach($headers as $k=>$v){
03776                                 $k = strtolower($k);
03777                                 $this->headers[$k] = $v;
03778                                 $this->request .= "$k: $v\r\n";
03779                                 $this->debug("$k: $v");
03780                         }
03781                         // get SOAPAction header
03782                         if(isset($this->headers['soapaction'])){
03783                                 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
03784                         }
03785                         // get the character encoding of the incoming request
03786                         if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
03787                                 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
03788                                 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
03789                                         $this->xml_encoding = strtoupper($enc);
03790                                 } else {
03791                                         $this->xml_encoding = 'US-ASCII';
03792                                 }
03793                         } else {
03794                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
03795                                 $this->xml_encoding = 'ISO-8859-1';
03796                         }
03797                 } elseif(isset($_SERVER) && is_array($_SERVER)){
03798                         $this->debug("In parse_http_headers, use _SERVER");
03799                         foreach ($_SERVER as $k => $v) {
03800                                 if (substr($k, 0, 5) == 'HTTP_') {
03801                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
03802                                 } else {
03803                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
03804                                 }
03805                                 if ($k == 'soapaction') {
03806                                         // get SOAPAction header
03807                                         $k = 'SOAPAction';
03808                                         $v = str_replace('"', '', $v);
03809                                         $v = str_replace('\\', '', $v);
03810                                         $this->SOAPAction = $v;
03811                                 } else if ($k == 'content-type') {
03812                                         // get the character encoding of the incoming request
03813                                         if (strpos($v, '=')) {
03814                                                 $enc = substr(strstr($v, '='), 1);
03815                                                 $enc = str_replace('"', '', $enc);
03816                                                 $enc = str_replace('\\', '', $enc);
03817                                                 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
03818                                                         $this->xml_encoding = strtoupper($enc);
03819                                                 } else {
03820                                                         $this->xml_encoding = 'US-ASCII';
03821                                                 }
03822                                         } else {
03823                                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
03824                                                 $this->xml_encoding = 'ISO-8859-1';
03825                                         }
03826                                 }
03827                                 $this->headers[$k] = $v;
03828                                 $this->request .= "$k: $v\r\n";
03829                                 $this->debug("$k: $v");
03830                         }
03831                 } elseif (is_array($HTTP_SERVER_VARS)) {
03832                         $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
03833                         foreach ($HTTP_SERVER_VARS as $k => $v) {
03834                                 if (substr($k, 0, 5) == 'HTTP_') {
03835                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                            $k = strtolower(substr($k, 5));
03836                                 } else {
03837                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                               $k = strtolower($k);
03838                                 }
03839                                 if ($k == 'soapaction') {
03840                                         // get SOAPAction header
03841                                         $k = 'SOAPAction';
03842                                         $v = str_replace('"', '', $v);
03843                                         $v = str_replace('\\', '', $v);
03844                                         $this->SOAPAction = $v;
03845                                 } else if ($k == 'content-type') {
03846                                         // get the character encoding of the incoming request
03847                                         if (strpos($v, '=')) {
03848                                                 $enc = substr(strstr($v, '='), 1);
03849                                                 $enc = str_replace('"', '', $enc);
03850                                                 $enc = str_replace('\\', '', $enc);
03851                                                 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
03852                                                         $this->xml_encoding = strtoupper($enc);
03853                                                 } else {
03854                                                         $this->xml_encoding = 'US-ASCII';
03855                                                 }
03856                                         } else {
03857                                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
03858                                                 $this->xml_encoding = 'ISO-8859-1';
03859                                         }
03860                                 }
03861                                 $this->headers[$k] = $v;
03862                                 $this->request .= "$k: $v\r\n";
03863                                 $this->debug("$k: $v");
03864                         }
03865                 } else {
03866                         $this->debug("In parse_http_headers, HTTP headers not accessible");
03867                         $this->setError("HTTP headers not accessible");
03868                 }
03869         }
03870 
03893         function parse_request($data='') {
03894                 $this->debug('entering parse_request()');
03895                 $this->parse_http_headers();
03896                 $this->debug('got character encoding: '.$this->xml_encoding);
03897                 // uncompress if necessary
03898                 if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
03899                         $this->debug('got content encoding: ' . $this->headers['content-encoding']);
03900                         if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
03901                         // if decoding works, use it. else assume data wasn't gzencoded
03902                                 if (function_exists('gzuncompress')) {
03903                                         if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
03904                                                 $data = $degzdata;
03905                                         } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
03906                                                 $data = $degzdata;
03907                                         } else {
03908                                                 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
03909                                                 return;
03910                                         }
03911                                 } else {
03912                                         $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
03913                                         return;
03914                                 }
03915                         }
03916                 }
03917                 $this->request .= "\r\n".$data;
03918                 $data = $this->parseRequest($this->headers, $data);
03919                 $this->requestSOAP = $data;
03920                 $this->debug('leaving parse_request');
03921         }
03922 
03940         function invoke_method() {
03941                 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
03942 
03943                 if ($this->wsdl) {
03944                         if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
03945                                 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
03946                                 $this->appendDebug('opData=' . $this->varDump($this->opData));
03947                         } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
03948                                 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
03949                                 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
03950                                 $this->appendDebug('opData=' . $this->varDump($this->opData));
03951                                 $this->methodname = $this->opData['name'];
03952                         } else {
03953                                 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
03954                                 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
03955                                 return;
03956                         }
03957                 } else {
03958                         $this->debug('in invoke_method, no WSDL to validate method');
03959                 }
03960 
03961                 // if a . is present in $this->methodname, we see if there is a class in scope,
03962                 // which could be referred to. We will also distinguish between two deliminators,
03963                 // to allow methods to be called a the class or an instance
03964                 $class = '';
03965                 $method = '';
03966                 if (strpos($this->methodname, '..') > 0) {
03967                         $delim = '..';
03968                 } else if (strpos($this->methodname, '.') > 0) {
03969                         $delim = '.';
03970                 } else {
03971                         $delim = '';
03972                 }
03973 
03974                 if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
03975                         class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
03976                         // get the class and method name
03977                         $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
03978                         $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
03979                         $this->debug("in invoke_method, class=$class method=$method delim=$delim");
03980                 }
03981 
03982                 // does method exist?
03983                 if ($class == '') {
03984                         if (!function_exists($this->methodname)) {
03985                                 $this->debug("in invoke_method, function '$this->methodname' not found!");
03986                                 $this->result = 'fault: method not found';
03987                                 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
03988                                 return;
03989                         }
03990                 } else {
03991                         $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
03992                         if (!in_array($method_to_compare, get_class_methods($class))) {
03993                                 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
03994                                 $this->result = 'fault: method not found';
03995                                 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
03996                                 return;
03997                         }
03998                 }
03999 
04000                 // evaluate message, getting back parameters
04001                 // verify that request parameters match the method's signature
04002                 if(! $this->verify_method($this->methodname,$this->methodparams)){
04003                         // debug
04004                         $this->debug('ERROR: request not verified against method signature');
04005                         $this->result = 'fault: request failed validation against method signature';
04006                         // return fault
04007                         $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
04008                         return;
04009                 }
04010 
04011                 // if there are parameters to pass
04012                 $this->debug('in invoke_method, params:');
04013                 $this->appendDebug($this->varDump($this->methodparams));
04014                 $this->debug("in invoke_method, calling '$this->methodname'");
04015                 if (!function_exists('call_user_func_array')) {
04016                         if ($class == '') {
04017                                 $this->debug('in invoke_method, calling function using eval()');
04018                                 $funcCall = "\$this->methodreturn = $this->methodname(";
04019                         } else {
04020                                 if ($delim == '..') {
04021                                         $this->debug('in invoke_method, calling class method using eval()');
04022                                         $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
04023                                 } else {
04024                                         $this->debug('in invoke_method, calling instance method using eval()');
04025                                         // generate unique instance name
04026                                         $instname = "\$inst_".time();
04027                                         $funcCall = $instname." = new ".$class."(); ";
04028                                         $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
04029                                 }
04030                         }
04031                         if ($this->methodparams) {
04032                                 foreach ($this->methodparams as $param) {
04033                                         if (is_array($param) || is_object($param)) {
04034                                                 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
04035                                                 return;
04036                                         }
04037                                         $funcCall .= "\"$param\",";
04038                                 }
04039                                 $funcCall = substr($funcCall, 0, -1);
04040                         }
04041                         $funcCall .= ');';
04042                         $this->debug('in invoke_method, function call: '.$funcCall);
04043                         @eval($funcCall);
04044                 } else {
04045                         if ($class == '') {
04046                                 $this->debug('in invoke_method, calling function using call_user_func_array()');
04047                                 $call_arg = "$this->methodname";        // straight assignment changes $this->methodname to lower case after call_user_func_array()
04048                         } elseif ($delim == '..') {
04049                                 $this->debug('in invoke_method, calling class method using call_user_func_array()');
04050                                 $call_arg = array ($class, $method);
04051                         } else {
04052                                 $this->debug('in invoke_method, calling instance method using call_user_func_array()');
04053                                 $instance = new $class ();
04054                                 $call_arg = array(&$instance, $method);
04055                         }
04056                         if (is_array($this->methodparams)) {
04057                                 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
04058                         } else {
04059                                 $this->methodreturn = call_user_func_array($call_arg, array());
04060                         }
04061                 }
04062         $this->debug('in invoke_method, methodreturn:');
04063         $this->appendDebug($this->varDump($this->methodreturn));
04064                 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
04065         }
04066 
04078         function serialize_return() {
04079                 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
04080                 // if fault
04081                 if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
04082                         $this->debug('got a fault object from method');
04083                         $this->fault = $this->methodreturn;
04084                         return;
04085                 } elseif ($this->methodreturnisliteralxml) {
04086                         $return_val = $this->methodreturn;
04087                 // returned value(s)
04088                 } else {
04089                         $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
04090                         $this->debug('serializing return value');
04091                         if($this->wsdl){
04092                                 if (sizeof($this->opData['output']['parts']) > 1) {
04093                                         $this->debug('more than one output part, so use the method return unchanged');
04094                                 $opParams = $this->methodreturn;
04095                             } elseif (sizeof($this->opData['output']['parts']) == 1) {
04096                                         $this->debug('exactly one output part, so wrap the method return in a simple array');
04097                                         // TODO: verify that it is not already wrapped!
04098                                 //foreach ($this->opData['output']['parts'] as $name => $type) {
04099                                         //      $this->debug('wrap in element named ' . $name);
04100                                 //}
04101                                 $opParams = array($this->methodreturn);
04102                             }
04103                             $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
04104                             $this->appendDebug($this->wsdl->getDebug());
04105                             $this->wsdl->clearDebug();
04106                                 if($errstr = $this->wsdl->getError()){
04107                                         $this->debug('got wsdl error: '.$errstr);
04108                                         $this->fault('SOAP-ENV:Server', 'unable to serialize result');
04109                                         return;
04110                                 }
04111                         } else {
04112                                 if (isset($this->methodreturn)) {
04113                                         $return_val = $this->serialize_val($this->methodreturn, 'return');
04114                                 } else {
04115                                         $return_val = '';
04116                                         $this->debug('in absence of WSDL, assume void return for backward compatibility');
04117                                 }
04118                         }
04119                 }
04120                 $this->debug('return value:');
04121                 $this->appendDebug($this->varDump($return_val));
04122 
04123                 $this->debug('serializing response');
04124                 if ($this->wsdl) {
04125                         $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
04126                         if ($this->opData['style'] == 'rpc') {
04127                                 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
04128                                 if ($this->opData['output']['use'] == 'literal') {
04129                                         // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
04130                                         if ($this->methodURI) {
04131                                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
04132                                         } else {
04133                                                 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
04134                                         }
04135                                 } else {
04136                                         if ($this->methodURI) {
04137                                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
04138                                         } else {
04139                                                 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
04140                                         }
04141                                 }
04142                         } else {
04143                                 $this->debug('style is not rpc for serialization: assume document');
04144                                 $payload = $return_val;
04145                         }
04146                 } else {
04147                         $this->debug('do not have WSDL for serialization: assume rpc/encoded');
04148                         $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
04149                 }
04150                 $this->result = 'successful';
04151                 if($this->wsdl){
04152                         //if($this->debug_flag){
04153                 $this->appendDebug($this->wsdl->getDebug());
04154             //  }
04155                         if (isset($opData['output']['encodingStyle'])) {
04156                                 $encodingStyle = $opData['output']['encodingStyle'];
04157                         } else {
04158                                 $encodingStyle = '';
04159                         }
04160                         // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
04161                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
04162                 } else {
04163                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
04164                 }
04165                 $this->debug("Leaving serialize_return");
04166         }
04167 
04178         function send_response() {
04179                 $this->debug('Enter send_response');
04180                 if ($this->fault) {
04181                         $payload = $this->fault->serialize();
04182                         $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
04183                         $this->outgoing_headers[] = "Status: 500 Internal Server Error";
04184                 } else {
04185                         $payload = $this->responseSOAP;
04186                         // Some combinations of PHP+Web server allow the Status
04187                         // to come through as a header.  Since OK is the default
04188                         // just do nothing.
04189                         // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
04190                         // $this->outgoing_headers[] = "Status: 200 OK";
04191                 }
04192         // add debug data if in debug mode
04193                 if(isset($this->debug_flag) && $this->debug_flag){
04194                 $payload .= $this->getDebugAsXMLComment();
04195         }
04196                 $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
04197                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
04198                 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
04199                 // Let the Web server decide about this
04200                 //$this->outgoing_headers[] = "Connection: Close\r\n";
04201                 $payload = $this->getHTTPBody($payload);
04202                 $type = $this->getHTTPContentType();
04203                 $charset = $this->getHTTPContentTypeCharset();
04204                 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
04205                 //begin code to compress payload - by John
04206                 // NOTE: there is no way to know whether the Web server will also compress
04207                 // this data.
04208                 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {     
04209                         if (strstr($this->headers['accept-encoding'], 'gzip')) {
04210                                 if (function_exists('gzencode')) {
04211                                         if (isset($this->debug_flag) && $this->debug_flag) {
04212                                                 $payload .= "<!-- Content being gzipped -->";
04213                                         }
04214                                         $this->outgoing_headers[] = "Content-Encoding: gzip";
04215                                         $payload = gzencode($payload);
04216                                 } else {
04217                                         if (isset($this->debug_flag) && $this->debug_flag) {
04218                                                 $payload .= "<!-- Content will not be gzipped: no gzencode -->";
04219                                         }
04220                                 }
04221                         } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
04222                                 // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
04223                                 // instead of gzcompress output,
04224                                 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
04225                                 if (function_exists('gzdeflate')) {
04226                                         if (isset($this->debug_flag) && $this->debug_flag) {
04227                                                 $payload .= "<!-- Content being deflated -->";
04228                                         }
04229                                         $this->outgoing_headers[] = "Content-Encoding: deflate";
04230                                         $payload = gzdeflate($payload);
04231                                 } else {
04232                                         if (isset($this->debug_flag) && $this->debug_flag) {
04233                                                 $payload .= "<!-- Content will not be deflated: no gzcompress -->";
04234                                         }
04235                                 }
04236                         }
04237                 }
04238                 //end code
04239                 $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
04240                 reset($this->outgoing_headers);
04241                 foreach($this->outgoing_headers as $hdr){
04242                         header($hdr, false);
04243                 }
04244                 print $payload;
04245                 $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
04246         }
04247 
04257         function verify_method($operation,$request){
04258                 if(isset($this->wsdl) && is_object($this->wsdl)){
04259                         if($this->wsdl->getOperationData($operation)){
04260                                 return true;
04261                         }
04262             } elseif(isset($this->operations[$operation])){
04263                         return true;
04264                 }
04265                 return false;
04266         }
04267 
04276     function parseRequest($headers, $data) {
04277                 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
04278                 $this->appendDebug($this->varDump($headers));
04279         if (!isset($headers['content-type'])) {
04280                         $this->setError('Request not of type text/xml (no content-type header)');
04281                         return false;
04282         }
04283                 if (!strstr($headers['content-type'], 'text/xml')) {
04284                         $this->setError('Request not of type text/xml');
04285                         return false;
04286                 }
04287                 if (strpos($headers['content-type'], '=')) {
04288                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
04289                         $this->debug('Got response encoding: ' . $enc);
04290                         if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
04291                                 $this->xml_encoding = strtoupper($enc);
04292                         } else {
04293                                 $this->xml_encoding = 'US-ASCII';
04294                         }
04295                 } else {
04296                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
04297                         $this->xml_encoding = 'ISO-8859-1';
04298                 }
04299                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
04300                 // parse response, get soap parser obj
04301                 $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
04302                 // parser debug
04303                 $this->debug("parser debug: \n".$parser->getDebug());
04304                 // if fault occurred during message parsing
04305                 if($err = $parser->getError()){
04306                         $this->result = 'fault: error in msg parsing: '.$err;
04307                         $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
04308                 // else successfully parsed request into soapval object
04309                 } else {
04310                         // get/set methodname
04311                         $this->methodURI = $parser->root_struct_namespace;
04312                         $this->methodname = $parser->root_struct_name;
04313                         $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
04314                         $this->debug('calling parser->get_soapbody()');
04315                         $this->methodparams = $parser->get_soapbody();
04316                         // get SOAP headers
04317                         $this->requestHeaders = $parser->getHeaders();
04318                         // get SOAP Header
04319                         $this->requestHeader = $parser->get_soapheader();
04320             // add document for doclit support
04321             $this->document = $parser->document;
04322                 }
04323          }
04324 
04332         function getHTTPBody($soapmsg) {
04333                 return $soapmsg;
04334         }
04335         
04344         function getHTTPContentType() {
04345                 return 'text/xml';
04346         }
04347         
04357         function getHTTPContentTypeCharset() {
04358                 return $this->soap_defencoding;
04359         }
04360 
04370         function add_to_map($methodname,$in,$out){
04371                         $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
04372         }
04373 
04388         function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
04389                 global $HTTP_SERVER_VARS;
04390 
04391                 if($this->externalWSDLURL){
04392                         die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
04393                 }
04394                 if (! $name) {
04395                         die('You must specify a name when you register an operation');
04396                 }
04397                 if (!is_array($in)) {
04398                         die('You must provide an array for operation inputs');
04399                 }
04400                 if (!is_array($out)) {
04401                         die('You must provide an array for operation outputs');
04402                 }
04403                 if(false == $namespace) {
04404                 }
04405                 if(false == $soapaction) {
04406                         if (isset($_SERVER)) {
04407                                 $SERVER_NAME = $_SERVER['SERVER_NAME'];
04408                                 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
04409                                 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
04410                         } elseif (isset($HTTP_SERVER_VARS)) {
04411                                 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
04412                                 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
04413                                 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
04414                         } else {
04415                                 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
04416                         }
04417                 if ($HTTPS == '1' || $HTTPS == 'on') {
04418                         $SCHEME = 'https';
04419                 } else {
04420                         $SCHEME = 'http';
04421                 }
04422                         $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
04423                 }
04424                 if(false == $style) {
04425                         $style = "rpc";
04426                 }
04427                 if(false == $use) {
04428                         $use = "encoded";
04429                 }
04430                 if ($use == 'encoded' && $encodingStyle == '') {
04431                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
04432                 }
04433 
04434                 $this->operations[$name] = array(
04435             'name' => $name,
04436             'in' => $in,
04437             'out' => $out,
04438             'namespace' => $namespace,
04439             'soapaction' => $soapaction,
04440             'style' => $style);
04441         if($this->wsdl){
04442                 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
04443             }
04444                 return true;
04445         }
04446 
04457         function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
04458                 if ($faultdetail == '' && $this->debug_flag) {
04459                         $faultdetail = $this->getDebug();
04460                 }
04461                 $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
04462                 $this->fault->soap_defencoding = $this->soap_defencoding;
04463         }
04464 
04476     function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
04477     {
04478         global $HTTP_SERVER_VARS;
04479 
04480                 if (isset($_SERVER)) {
04481                         $SERVER_NAME = $_SERVER['SERVER_NAME'];
04482                         $SERVER_PORT = $_SERVER['SERVER_PORT'];
04483                         $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
04484                         $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
04485                 } elseif (isset($HTTP_SERVER_VARS)) {
04486                         $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
04487                         $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
04488                         $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
04489                         $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
04490                 } else {
04491                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
04492                 }
04493                 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
04494                 $colon = strpos($SERVER_NAME,":");
04495                 if ($colon) {
04496                     $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
04497                 }
04498                 if ($SERVER_PORT == 80) {
04499                         $SERVER_PORT = '';
04500                 } else {
04501                         $SERVER_PORT = ':' . $SERVER_PORT;
04502                 }
04503         if(false == $namespace) {
04504             $namespace = "http://$SERVER_NAME/soap/$serviceName";
04505         }
04506         
04507         if(false == $endpoint) {
04508                 if ($HTTPS == '1' || $HTTPS == 'on') {
04509                         $SCHEME = 'https';
04510                 } else {
04511                         $SCHEME = 'http';
04512                 }
04513             $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
04514         }
04515         
04516         if(false == $schemaTargetNamespace) {
04517             $schemaTargetNamespace = $namespace;
04518         }
04519         
04520                 $this->wsdl = new wsdl;
04521                 $this->wsdl->serviceName = $serviceName;
04522         $this->wsdl->endpoint = $endpoint;
04523                 $this->wsdl->namespaces['tns'] = $namespace;
04524                 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
04525                 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
04526                 if ($schemaTargetNamespace != $namespace) {
04527                         $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
04528                 }
04529         $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
04530         if ($style == 'document') {
04531                 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
04532         }
04533         $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
04534         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
04535         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
04536         $this->wsdl->bindings[$serviceName.'Binding'] = array(
04537                 'name'=>$serviceName.'Binding',
04538             'style'=>$style,
04539             'transport'=>$transport,
04540             'portType'=>$serviceName.'PortType');
04541         $this->wsdl->ports[$serviceName.'Port'] = array(
04542                 'binding'=>$serviceName.'Binding',
04543             'location'=>$endpoint,
04544             'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
04545     }
04546 }
04547 
04551 class soap_server extends nusoap_server {
04552 }
04553 
04554 ?><?php
04555 
04556 
04557 
04567 class wsdl extends nusoap_base {
04568         // URL or filename of the root of this WSDL
04569     var $wsdl; 
04570     // define internal arrays of bindings, ports, operations, messages, etc.
04571     var $schemas = array();
04572     var $currentSchema;
04573     var $message = array();
04574     var $complexTypes = array();
04575     var $messages = array();
04576     var $currentMessage;
04577     var $currentOperation;
04578     var $portTypes = array();
04579     var $currentPortType;
04580     var $bindings = array();
04581     var $currentBinding;
04582     var $ports = array();
04583     var $currentPort;
04584     var $opData = array();
04585     var $status = '';
04586     var $documentation = false;
04587     var $endpoint = ''; 
04588     // array of wsdl docs to import
04589     var $import = array(); 
04590     // parser vars
04591     var $parser;
04592     var $position = 0;
04593     var $depth = 0;
04594     var $depth_array = array();
04595         // for getting wsdl
04596         var $proxyhost = '';
04597     var $proxyport = '';
04598         var $proxyusername = '';
04599         var $proxypassword = '';
04600         var $timeout = 0;
04601         var $response_timeout = 30;
04602         var $curl_options = array();    // User-specified cURL options
04603         var $use_curl = false;                  // whether to always try to use cURL
04604         // for HTTP authentication
04605         var $username = '';                             // Username for HTTP authentication
04606         var $password = '';                             // Password for HTTP authentication
04607         var $authtype = '';                             // Type of HTTP authentication
04608         var $certRequest = array();             // Certificate for HTTP SSL authentication
04609 
04624     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
04625                 parent::nusoap_base();
04626                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
04627         $this->proxyhost = $proxyhost;
04628         $this->proxyport = $proxyport;
04629                 $this->proxyusername = $proxyusername;
04630                 $this->proxypassword = $proxypassword;
04631                 $this->timeout = $timeout;
04632                 $this->response_timeout = $response_timeout;
04633                 if (is_array($curl_options))
04634                         $this->curl_options = $curl_options;
04635                 $this->use_curl = $use_curl;
04636                 $this->fetchWSDL($wsdl);
04637     }
04638 
04644         function fetchWSDL($wsdl) {
04645                 $this->debug("parse and process WSDL path=$wsdl");
04646                 $this->wsdl = $wsdl;
04647         // parse wsdl file
04648         if ($this->wsdl != "") {
04649             $this->parseWSDL($this->wsdl);
04650         }
04651         // imports
04652         // TODO: handle imports more properly, grabbing them in-line and nesting them
04653         $imported_urls = array();
04654         $imported = 1;
04655         while ($imported > 0) {
04656                 $imported = 0;
04657                 // Schema imports
04658                 foreach ($this->schemas as $ns => $list) {
04659                         foreach ($list as $xs) {
04660                                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
04661                             foreach ($xs->imports as $ns2 => $list2) {
04662                                 for ($ii = 0; $ii < count($list2); $ii++) {
04663                                         if (! $list2[$ii]['loaded']) {
04664                                                 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
04665                                                 $url = $list2[$ii]['location'];
04666                                                                 if ($url != '') {
04667                                                                         $urlparts = parse_url($url);
04668                                                                         if (!isset($urlparts['host'])) {
04669                                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
04670                                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
04671                                                                         }
04672                                                                         if (! in_array($url, $imported_urls)) {
04673                                                                 $this->parseWSDL($url);
04674                                                                 $imported++;
04675                                                                 $imported_urls[] = $url;
04676                                                         }
04677                                                                 } else {
04678                                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");
04679                                                                 }
04680                                                         }
04681                                                 }
04682                             } 
04683                         }
04684                 }
04685                 // WSDL imports
04686                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
04687             foreach ($this->import as $ns => $list) {
04688                 for ($ii = 0; $ii < count($list); $ii++) {
04689                         if (! $list[$ii]['loaded']) {
04690                                 $this->import[$ns][$ii]['loaded'] = true;
04691                                 $url = $list[$ii]['location'];
04692                                                 if ($url != '') {
04693                                                         $urlparts = parse_url($url);
04694                                                         if (!isset($urlparts['host'])) {
04695                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
04696                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
04697                                                         }
04698                                                         if (! in_array($url, $imported_urls)) {
04699                                                 $this->parseWSDL($url);
04700                                                 $imported++;
04701                                                 $imported_urls[] = $url;
04702                                         }
04703                                                 } else {
04704                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");
04705                                                 }
04706                                         }
04707                                 }
04708             } 
04709                 }
04710         // add new data to operation data
04711         foreach($this->bindings as $binding => $bindingData) {
04712             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
04713                 foreach($bindingData['operations'] as $operation => $data) {
04714                     $this->debug('post-parse data gathering for ' . $operation);
04715                     $this->bindings[$binding]['operations'][$operation]['input'] = 
04716                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
04717                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
04718                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
04719                     $this->bindings[$binding]['operations'][$operation]['output'] = 
04720                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
04721                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
04722                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
04723                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
04724                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
04725                                         }
04726                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
04727                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
04728                     }
04729                     // Set operation style if necessary, but do not override one already provided
04730                                         if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
04731                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
04732                     }
04733                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
04734                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
04735                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
04736                 } 
04737             } 
04738         }
04739         }
04740 
04747     function parseWSDL($wsdl = '') {
04748                 $this->debug("parse WSDL at path=$wsdl");
04749 
04750         if ($wsdl == '') {
04751             $this->debug('no wsdl passed to parseWSDL()!!');
04752             $this->setError('no wsdl passed to parseWSDL()!!');
04753             return false;
04754         }
04755         
04756         // parse $wsdl for url format
04757         $wsdl_props = parse_url($wsdl);
04758 
04759         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
04760             $this->debug('getting WSDL http(s) URL ' . $wsdl);
04761                 // get wsdl
04762                 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
04763                         $tr->request_method = 'GET';
04764                         $tr->useSOAPAction = false;
04765                         if($this->proxyhost && $this->proxyport){
04766                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
04767                         }
04768                         if ($this->authtype != '') {
04769                                 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
04770                         }
04771                         $tr->setEncoding('gzip, deflate');
04772                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
04773                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);
04774                         //$this->debug("WSDL response\n" . $tr->incoming_payload);
04775                         $this->appendDebug($tr->getDebug());
04776                         // catch errors
04777                         if($err = $tr->getError() ){
04778                                 $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err;
04779                                 $this->debug($errstr);
04780                     $this->setError($errstr);
04781                                 unset($tr);
04782                     return false;
04783                         }
04784                         unset($tr);
04785                         $this->debug("got WSDL URL");
04786         } else {
04787             // $wsdl is not http(s), so treat it as a file URL or plain file path
04788                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
04789                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
04790                 } else {
04791                         $path = $wsdl;
04792                 }
04793             $this->debug('getting WSDL file ' . $path);
04794             if ($fp = @fopen($path, 'r')) {
04795                 $wsdl_string = '';
04796                 while ($data = fread($fp, 32768)) {
04797                     $wsdl_string .= $data;
04798                 } 
04799                 fclose($fp);
04800             } else {
04801                 $errstr = "Bad path to WSDL file $path";
04802                 $this->debug($errstr);
04803                 $this->setError($errstr);
04804                 return false;
04805             } 
04806         }
04807         $this->debug('Parse WSDL');
04808         // end new code added
04809         // Create an XML parser.
04810         $this->parser = xml_parser_create(); 
04811         // Set the options for parsing the XML data.
04812         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
04813         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
04814         // Set the object for the parser.
04815         xml_set_object($this->parser, $this); 
04816         // Set the element handlers for the parser.
04817         xml_set_element_handler($this->parser, 'start_element', 'end_element');
04818         xml_set_character_data_handler($this->parser, 'character_data');
04819         // Parse the XML file.
04820         if (!xml_parse($this->parser, $wsdl_string, true)) {
04821             // Display an error message.
04822             $errstr = sprintf(
04823                                 'XML error parsing WSDL from %s on line %d: %s',
04824                                 $wsdl,
04825                 xml_get_current_line_number($this->parser),
04826                 xml_error_string(xml_get_error_code($this->parser))
04827                 );
04828             $this->debug($errstr);
04829                         $this->debug("XML payload:\n" . $wsdl_string);
04830             $this->setError($errstr);
04831             return false;
04832         } 
04833                 // free the parser
04834         xml_parser_free($this->parser);
04835         $this->debug('Parsing WSDL done');
04836                 // catch wsdl parse errors
04837                 if($this->getError()){
04838                         return false;
04839                 }
04840         return true;
04841     } 
04842 
04851     function start_element($parser, $name, $attrs)
04852     {
04853         if ($this->status == 'schema') {
04854             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
04855             $this->appendDebug($this->currentSchema->getDebug());
04856             $this->currentSchema->clearDebug();
04857         } elseif (ereg('schema$', $name)) {
04858                 $this->debug('Parsing WSDL schema');
04859             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
04860             $this->status = 'schema';
04861             $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
04862             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
04863             $this->appendDebug($this->currentSchema->getDebug());
04864             $this->currentSchema->clearDebug();
04865         } else {
04866             // position in the total number of elements, starting from 0
04867             $pos = $this->position++;
04868             $depth = $this->depth++; 
04869             // set self as current value for this depth
04870             $this->depth_array[$depth] = $pos;
04871             $this->message[$pos] = array('cdata' => ''); 
04872             // process attributes
04873             if (count($attrs) > 0) {
04874                                 // register namespace declarations
04875                 foreach($attrs as $k => $v) {
04876                     if (ereg("^xmlns", $k)) {
04877                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
04878                             $this->namespaces[$ns_prefix] = $v;
04879                         } else {
04880                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
04881                         } 
04882                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
04883                             $this->XMLSchemaVersion = $v;
04884                             $this->namespaces['xsi'] = $v . '-instance';
04885                         } 
04886                     }
04887                 }
04888                 // expand each attribute prefix to its namespace
04889                 foreach($attrs as $k => $v) {
04890                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
04891                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
04892                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
04893                     } 
04894                     $eAttrs[$k] = $v;
04895                 } 
04896                 $attrs = $eAttrs;
04897             } else {
04898                 $attrs = array();
04899             } 
04900             // get element prefix, namespace and