Support Incident Tracker GIT4.x
nusoap.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004 $Id: nusoap.php,v 1.114 2007/11/06 15:17:46 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 mailing list:
00028 nusoap-general@lists.sourceforge.net
00029 
00030 If you have any questions or comments, please email:
00031 
00032 Dietrich Ayala
00033 dietrich@ganx4.com
00034 http://dietrich.ganx4.com/nusoap
00035 
00036 NuSphere Corporation
00037 http://www.nusphere.com
00038 
00039 */
00040 
00041 /*
00042  *  Some of the standards implmented in whole or part by NuSOAP:
00043  *
00044  *  SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
00045  *  WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
00046  *  SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
00047  *  XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
00048  *  Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
00049  *  XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
00050  *  RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
00051  *  RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
00052  *  RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
00053  */
00054 
00055 /* load classes
00056 
00057 // necessary classes
00058 require_once('class.soapclient.php');
00059 require_once('class.soap_val.php');
00060 require_once('class.soap_parser.php');
00061 require_once('class.soap_fault.php');
00062 
00063 // transport classes
00064 require_once('class.soap_transport_http.php');
00065 
00066 // optional add-on classes
00067 require_once('class.xmlschema.php');
00068 require_once('class.wsdl.php');
00069 
00070 // server class
00071 require_once('class.soap_server.php');*/
00072 
00073 // class variable emulation
00074 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
00075 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
00076 
00086 class nusoap_base {
00093     var $title = 'NuSOAP';
00100     var $version = '0.7.3';
00107     var $revision = '$Revision: 1.114 $';
00114     var $error_str = '';
00121     var $debug_str = '';
00129     var $charencoding = true;
00136     var $debugLevel;
00137 
00144     var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
00145     
00152     var $soap_defencoding = 'ISO-8859-1';
00153     //var $soap_defencoding = 'UTF-8';
00154 
00163     var $namespaces = array(
00164         'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
00165         'xsd' => 'http://www.w3.org/2001/XMLSchema',
00166         'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
00167         'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
00168         );
00169 
00176     var $usedNamespaces = array();
00177 
00185     var $typemap = array(
00186     'http://www.w3.org/2001/XMLSchema' => array(
00187         'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
00188         'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
00189         'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
00190         // abstract "any" types
00191         'anyType'=>'string','anySimpleType'=>'string',
00192         // derived datatypes
00193         'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
00194         'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
00195         'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
00196         'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
00197     'http://www.w3.org/2000/10/XMLSchema' => array(
00198         'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00199         'float'=>'double','dateTime'=>'string',
00200         'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00201     'http://www.w3.org/1999/XMLSchema' => array(
00202         'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00203         'float'=>'double','dateTime'=>'string',
00204         'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00205     'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
00206     'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
00207     'http://xml.apache.org/xml-soap' => array('Map')
00208     );
00209 
00218     var $xmlEntities = array('quot' => '"','amp' => '&',
00219         'lt' => '<','gt' => '>','apos' => "'");
00220 
00226     function nusoap_base() {
00227         $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
00228     }
00229 
00236     function getGlobalDebugLevel() {
00237         return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
00238     }
00239 
00246     function setGlobalDebugLevel($level) {
00247         $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
00248     }
00249 
00256     function getDebugLevel() {
00257         return $this->debugLevel;
00258     }
00259 
00266     function setDebugLevel($level) {
00267         $this->debugLevel = $level;
00268     }
00269 
00276     function debug($string){
00277         if ($this->debugLevel > 0) {
00278             $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
00279         }
00280     }
00281 
00288     function appendDebug($string){
00289         if ($this->debugLevel > 0) {
00290             // it would be nice to use a memory stream here to use
00291             // memory more efficiently
00292             $this->debug_str .= $string;
00293         }
00294     }
00295 
00301     function clearDebug() {
00302         // it would be nice to use a memory stream here to use
00303         // memory more efficiently
00304         $this->debug_str = '';
00305     }
00306 
00313     function &getDebug() {
00314         // it would be nice to use a memory stream here to use
00315         // memory more efficiently
00316         return $this->debug_str;
00317     }
00318 
00326     function &getDebugAsXMLComment() {
00327         // it would be nice to use a memory stream here to use
00328         // memory more efficiently
00329         while (strpos($this->debug_str, '--')) {
00330             $this->debug_str = str_replace('--', '- -', $this->debug_str);
00331         }
00332         $ret = "<!--\n" . $this->debug_str . "\n-->";
00333         return $ret;
00334     }
00335 
00342     function expandEntities($val) {
00343         if ($this->charencoding) {
00344             $val = str_replace('&', '&amp;', $val);
00345             $val = str_replace("'", '&apos;', $val);
00346             $val = str_replace('"', '&quot;', $val);
00347             $val = str_replace('<', '&lt;', $val);
00348             $val = str_replace('>', '&gt;', $val);
00349         }
00350         return $val;
00351     }
00352 
00359     function getError(){
00360         if($this->error_str != ''){
00361             return $this->error_str;
00362         }
00363         return false;
00364     }
00365 
00372     function setError($str){
00373         $this->error_str = $str;
00374     }
00375 
00383     function isArraySimpleOrStruct($val) {
00384         $keyList = array_keys($val);
00385         foreach ($keyList as $keyListValue) {
00386             if (!is_int($keyListValue)) {
00387                 return 'arrayStruct';
00388             }
00389         }
00390         return 'arraySimple';
00391     }
00392 
00408     function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
00409         $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
00410         $this->appendDebug('value=' . $this->varDump($val));
00411         $this->appendDebug('attributes=' . $this->varDump($attributes));
00412         
00413         if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
00414             $this->debug("serialize_val: serialize soapval");
00415             $xml = $val->serialize($use);
00416             $this->appendDebug($val->getDebug());
00417             $val->clearDebug();
00418             $this->debug("serialize_val of soapval returning $xml");
00419             return $xml;
00420         }
00421         // force valid name if necessary
00422         if (is_numeric($name)) {
00423             $name = '__numeric_' . $name;
00424         } elseif (! $name) {
00425             $name = 'noname';
00426         }
00427         // if name has ns, add ns prefix to name
00428         $xmlns = '';
00429         if($name_ns){
00430             $prefix = 'nu'.rand(1000,9999);
00431             $name = $prefix.':'.$name;
00432             $xmlns .= " xmlns:$prefix=\"$name_ns\"";
00433         }
00434         // if type is prefixed, create type prefix
00435         if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
00436             // need to fix this. shouldn't default to xsd if no ns specified
00437             // w/o checking against typemap
00438             $type_prefix = 'xsd';
00439         } elseif($type_ns){
00440             $type_prefix = 'ns'.rand(1000,9999);
00441             $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
00442         }
00443         // serialize attributes if present
00444         $atts = '';
00445         if($attributes){
00446             foreach($attributes as $k => $v){
00447                 $atts .= " $k=\"".$this->expandEntities($v).'"';
00448             }
00449         }
00450         // serialize null value
00451         if (is_null($val)) {
00452             $this->debug("serialize_val: serialize null");
00453             if ($use == 'literal') {
00454                 // TODO: depends on minOccurs
00455                 $xml = "<$name$xmlns$atts/>";
00456                 $this->debug("serialize_val returning $xml");
00457                 return $xml;
00458             } else {
00459                 if (isset($type) && isset($type_prefix)) {
00460                     $type_str = " xsi:type=\"$type_prefix:$type\"";
00461                 } else {
00462                     $type_str = '';
00463                 }
00464                 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
00465                 $this->debug("serialize_val returning $xml");
00466                 return $xml;
00467             }
00468         }
00469         // serialize if an xsd built-in primitive type
00470         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
00471             $this->debug("serialize_val: serialize xsd built-in primitive type");
00472             if (is_bool($val)) {
00473                 if ($type == 'boolean') {
00474                     $val = $val ? 'true' : 'false';
00475                 } elseif (! $val) {
00476                     $val = 0;
00477                 }
00478             } else if (is_string($val)) {
00479                 $val = $this->expandEntities($val);
00480             }
00481             if ($use == 'literal') {
00482                 $xml = "<$name$xmlns$atts>$val</$name>";
00483                 $this->debug("serialize_val returning $xml");
00484                 return $xml;
00485             } else {
00486                 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
00487                 $this->debug("serialize_val returning $xml");
00488                 return $xml;
00489             }
00490         }
00491         // detect type and serialize
00492         $xml = '';
00493         switch(true) {
00494             case (is_bool($val) || $type == 'boolean'):
00495                 $this->debug("serialize_val: serialize boolean");
00496                 if ($type == 'boolean') {
00497                     $val = $val ? 'true' : 'false';
00498                 } elseif (! $val) {
00499                     $val = 0;
00500                 }
00501                 if ($use == 'literal') {
00502                     $xml .= "<$name$xmlns$atts>$val</$name>";
00503                 } else {
00504                     $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
00505                 }
00506                 break;
00507             case (is_int($val) || is_long($val) || $type == 'int'):
00508                 $this->debug("serialize_val: serialize int");
00509                 if ($use == 'literal') {
00510                     $xml .= "<$name$xmlns$atts>$val</$name>";
00511                 } else {
00512                     $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
00513                 }
00514                 break;
00515             case (is_float($val)|| is_double($val) || $type == 'float'):
00516                 $this->debug("serialize_val: serialize float");
00517                 if ($use == 'literal') {
00518                     $xml .= "<$name$xmlns$atts>$val</$name>";
00519                 } else {
00520                     $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
00521                 }
00522                 break;
00523             case (is_string($val) || $type == 'string'):
00524                 $this->debug("serialize_val: serialize string");
00525                 $val = $this->expandEntities($val);
00526                 if ($use == 'literal') {
00527                     $xml .= "<$name$xmlns$atts>$val</$name>";
00528                 } else {
00529                     $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
00530                 }
00531                 break;
00532             case is_object($val):
00533                 $this->debug("serialize_val: serialize object");
00534                 if (get_class($val) == 'soapval') {
00535                     $this->debug("serialize_val: serialize soapval object");
00536                     $pXml = $val->serialize($use);
00537                     $this->appendDebug($val->getDebug());
00538                     $val->clearDebug();
00539                 } else {
00540                     if (! $name) {
00541                         $name = get_class($val);
00542                         $this->debug("In serialize_val, used class name $name as element name");
00543                     } else {
00544                         $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
00545                     }
00546                     foreach(get_object_vars($val) as $k => $v){
00547                         $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
00548                     }
00549                 }
00550                 if(isset($type) && isset($type_prefix)){
00551                     $type_str = " xsi:type=\"$type_prefix:$type\"";
00552                 } else {
00553                     $type_str = '';
00554                 }
00555                 if ($use == 'literal') {
00556                     $xml .= "<$name$xmlns$atts>$pXml</$name>";
00557                 } else {
00558                     $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
00559                 }
00560                 break;
00561             break;
00562             case (is_array($val) || $type):
00563                 // detect if struct or array
00564                 $valueType = $this->isArraySimpleOrStruct($val);
00565                 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
00566                     $this->debug("serialize_val: serialize array");
00567                     $i = 0;
00568                     if(is_array($val) && count($val)> 0){
00569                         foreach($val as $v){
00570                             if(is_object($v) && get_class($v) ==  'soapval'){
00571                                 $tt_ns = $v->type_ns;
00572                                 $tt = $v->type;
00573                             } elseif (is_array($v)) {
00574                                 $tt = $this->isArraySimpleOrStruct($v);
00575                             } else {
00576                                 $tt = gettype($v);
00577                             }
00578                             $array_types[$tt] = 1;
00579                             // TODO: for literal, the name should be $name
00580                             $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
00581                             ++$i;
00582                         }
00583                         if(count($array_types) > 1){
00584                             $array_typename = 'xsd:anyType';
00585                         } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
00586                             if ($tt == 'integer') {
00587                                 $tt = 'int';
00588                             }
00589                             $array_typename = 'xsd:'.$tt;
00590                         } elseif(isset($tt) && $tt == 'arraySimple'){
00591                             $array_typename = 'SOAP-ENC:Array';
00592                         } elseif(isset($tt) && $tt == 'arrayStruct'){
00593                             $array_typename = 'unnamed_struct_use_soapval';
00594                         } else {
00595                             // if type is prefixed, create type prefix
00596                             if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
00597                                  $array_typename = 'xsd:' . $tt;
00598                             } elseif ($tt_ns) {
00599                                 $tt_prefix = 'ns' . rand(1000, 9999);
00600                                 $array_typename = "$tt_prefix:$tt";
00601                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
00602                             } else {
00603                                 $array_typename = $tt;
00604                             }
00605                         }
00606                         $array_type = $i;
00607                         if ($use == 'literal') {
00608                             $type_str = '';
00609                         } else if (isset($type) && isset($type_prefix)) {
00610                             $type_str = " xsi:type=\"$type_prefix:$type\"";
00611                         } else {
00612                             $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
00613                         }
00614                     // empty array
00615                     } else {
00616                         if ($use == 'literal') {
00617                             $type_str = '';
00618                         } else if (isset($type) && isset($type_prefix)) {
00619                             $type_str = " xsi:type=\"$type_prefix:$type\"";
00620                         } else {
00621                             $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
00622                         }
00623                     }
00624                     // TODO: for array in literal, there is no wrapper here
00625                     $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
00626                 } else {
00627                     // got a struct
00628                     $this->debug("serialize_val: serialize struct");
00629                     if(isset($type) && isset($type_prefix)){
00630                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00631                     } else {
00632                         $type_str = '';
00633                     }
00634                     if ($use == 'literal') {
00635                         $xml .= "<$name$xmlns$atts>";
00636                     } else {
00637                         $xml .= "<$name$xmlns$type_str$atts>";
00638                     }
00639                     foreach($val as $k => $v){
00640                         // Apache Map
00641                         if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
00642                             $xml .= '<item>';
00643                             $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
00644                             $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
00645                             $xml .= '</item>';
00646                         } else {
00647                             $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
00648                         }
00649                     }
00650                     $xml .= "</$name>";
00651                 }
00652                 break;
00653             default:
00654                 $this->debug("serialize_val: serialize unknown");
00655                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
00656                 break;
00657         }
00658         $this->debug("serialize_val returning $xml");
00659         return $xml;
00660     }
00661 
00674     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
00675     // TODO: add an option to automatically run utf8_encode on $body and $headers
00676     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
00677     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
00678 
00679     $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
00680     $this->debug("headers:");
00681     $this->appendDebug($this->varDump($headers));
00682     $this->debug("namespaces:");
00683     $this->appendDebug($this->varDump($namespaces));
00684 
00685     // serialize namespaces
00686     $ns_string = '';
00687     foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
00688         $ns_string .= " xmlns:$k=\"$v\"";
00689     }
00690     if($encodingStyle) {
00691         $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
00692     }
00693 
00694     // serialize headers
00695     if($headers){
00696         if (is_array($headers)) {
00697             $xml = '';
00698             foreach ($headers as $k => $v) {
00699                 if (is_object($v) && get_class($v) == 'soapval') {
00700                     $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
00701                 } else {
00702                     $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
00703                 }
00704             }
00705             $headers = $xml;
00706             $this->debug("In serializeEnvelope, serialized array of headers to $headers");
00707         }
00708         $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
00709     }
00710     // serialize envelope
00711     return
00712     '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
00713     '<SOAP-ENV:Envelope'.$ns_string.">".
00714     $headers.
00715     "<SOAP-ENV:Body>".
00716         $body.
00717     "</SOAP-ENV:Body>".
00718     "</SOAP-ENV:Envelope>";
00719     }
00720 
00729     function formatDump($str){
00730         $str = htmlspecialchars($str);
00731         return nl2br($str);
00732     }
00733 
00741     function contractQname($qname){
00742         // get element namespace
00743         //$this->xdebug("Contract $qname");
00744         if (strrpos($qname, ':')) {
00745             // get unqualified name
00746             $name = substr($qname, strrpos($qname, ':') + 1);
00747             // get ns
00748             $ns = substr($qname, 0, strrpos($qname, ':'));
00749             $p = $this->getPrefixFromNamespace($ns);
00750             if ($p) {
00751                 return $p . ':' . $name;
00752             }
00753             return $qname;
00754         } else {
00755             return $qname;
00756         }
00757     }
00758 
00766     function expandQname($qname){
00767         // get element prefix
00768         if(strpos($qname,':') && !ereg('^http://',$qname)){
00769             // get unqualified name
00770             $name = substr(strstr($qname,':'),1);
00771             // get ns prefix
00772             $prefix = substr($qname,0,strpos($qname,':'));
00773             if(isset($this->namespaces[$prefix])){
00774                 return $this->namespaces[$prefix].':'.$name;
00775             } else {
00776                 return $qname;
00777             }
00778         } else {
00779             return $qname;
00780         }
00781     }
00782 
00791     function getLocalPart($str){
00792         if($sstr = strrchr($str,':')){
00793             // get unqualified name
00794             return substr( $sstr, 1 );
00795         } else {
00796             return $str;
00797         }
00798     }
00799 
00808     function getPrefix($str){
00809         if($pos = strrpos($str,':')){
00810             // get prefix
00811             return substr($str,0,$pos);
00812         }
00813         return false;
00814     }
00815 
00823     function getNamespaceFromPrefix($prefix){
00824         if (isset($this->namespaces[$prefix])) {
00825             return $this->namespaces[$prefix];
00826         }
00827         //$this->setError("No namespace registered for prefix '$prefix'");
00828         return false;
00829     }
00830 
00839     function getPrefixFromNamespace($ns) {
00840         foreach ($this->namespaces as $p => $n) {
00841             if ($ns == $n || $ns == $p) {
00842                 $this->usedNamespaces[$p] = $n;
00843                 return $p;
00844             }
00845         }
00846         return false;
00847     }
00848 
00855     function getmicrotime() {
00856         if (function_exists('gettimeofday')) {
00857             $tod = gettimeofday();
00858             $sec = $tod['sec'];
00859             $usec = $tod['usec'];
00860         } else {
00861             $sec = time();
00862             $usec = 0;
00863         }
00864         return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
00865     }
00866 
00874     function varDump($data) {
00875         ob_start();
00876         var_dump($data);
00877         $ret_val = ob_get_contents();
00878         ob_end_clean();
00879         return $ret_val;
00880     }
00881 
00888     function __toString() {
00889         return $this->varDump($this);
00890     }
00891 }
00892 
00893 // XML Schema Datatype Helper Functions
00894 
00895 //xsd:dateTime helpers
00896 
00904 function timestamp_to_iso8601($timestamp,$utc=true){
00905     $datestr = date('Y-m-d\TH:i:sO',$timestamp);
00906     if($utc){
00907         $eregStr =
00908         '([0-9]{4})-'.  // centuries & years CCYY-
00909         '([0-9]{2})-'.  // months MM-
00910         '([0-9]{2})'.   // days DD
00911         'T'.            // separator T
00912         '([0-9]{2}):'.  // hours hh:
00913         '([0-9]{2}):'.  // minutes mm:
00914         '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
00915         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00916 
00917         if(ereg($eregStr,$datestr,$regs)){
00918             return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
00919         }
00920         return false;
00921     } else {
00922         return $datestr;
00923     }
00924 }
00925 
00932 function iso8601_to_timestamp($datestr){
00933     $eregStr =
00934     '([0-9]{4})-'.  // centuries & years CCYY-
00935     '([0-9]{2})-'.  // months MM-
00936     '([0-9]{2})'.   // days DD
00937     'T'.            // separator T
00938     '([0-9]{2}):'.  // hours hh:
00939     '([0-9]{2}):'.  // minutes mm:
00940     '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
00941     '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00942     if(ereg($eregStr,$datestr,$regs)){
00943         // not utc
00944         if($regs[8] != 'Z'){
00945             $op = substr($regs[8],0,1);
00946             $h = substr($regs[8],1,2);
00947             $m = substr($regs[8],strlen($regs[8])-2,2);
00948             if($op == '-'){
00949                 $regs[4] = $regs[4] + $h;
00950                 $regs[5] = $regs[5] + $m;
00951             } elseif($op == '+'){
00952                 $regs[4] = $regs[4] - $h;
00953                 $regs[5] = $regs[5] - $m;
00954             }
00955         }
00956         return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
00957 //      return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
00958     } else {
00959         return false;
00960     }
00961 }
00962 
00970 function usleepWindows($usec)
00971 {
00972     $start = gettimeofday();
00973     
00974     do
00975     {
00976         $stop = gettimeofday();
00977         $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
00978         + $stop['usec'] - $start['usec'];
00979     }
00980     while ($timePassed < $usec);
00981 }
00982 
00983 ?><?php
00984 
00985 
00986 
00995 class nusoap_fault extends nusoap_base {
01001     var $faultcode;
01007     var $faultactor;
01013     var $faultstring;
01019     var $faultdetail;
01020 
01029     function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
01030         parent::nusoap_base();
01031         $this->faultcode = $faultcode;
01032         $this->faultactor = $faultactor;
01033         $this->faultstring = $faultstring;
01034         $this->faultdetail = $faultdetail;
01035     }
01036 
01043     function serialize(){
01044         $ns_string = '';
01045         foreach($this->namespaces as $k => $v){
01046             $ns_string .= "\n  xmlns:$k=\"$v\"";
01047         }
01048         $return_msg =
01049             '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
01050             '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
01051                 '<SOAP-ENV:Body>'.
01052                 '<SOAP-ENV:Fault>'.
01053                     $this->serialize_val($this->faultcode, 'faultcode').
01054                     $this->serialize_val($this->faultactor, 'faultactor').
01055                     $this->serialize_val($this->faultstring, 'faultstring').
01056                     $this->serialize_val($this->faultdetail, 'detail').
01057                 '</SOAP-ENV:Fault>'.
01058                 '</SOAP-ENV:Body>'.
01059             '</SOAP-ENV:Envelope>';
01060         return $return_msg;
01061     }
01062 }
01063 
01067 class soap_fault extends nusoap_fault {
01068 }
01069 
01070 ?><?php
01071 
01072 
01073 
01083 class nusoap_xmlschema extends nusoap_base  {
01084     
01085     // files
01086     var $schema = '';
01087     var $xml = '';
01088     // namespaces
01089     var $enclosingNamespaces;
01090     // schema info
01091     var $schemaInfo = array();
01092     var $schemaTargetNamespace = '';
01093     // types, elements, attributes defined by the schema
01094     var $attributes = array();
01095     var $complexTypes = array();
01096     var $complexTypeStack = array();
01097     var $currentComplexType = null;
01098     var $elements = array();
01099     var $elementStack = array();
01100     var $currentElement = null;
01101     var $simpleTypes = array();
01102     var $simpleTypeStack = array();
01103     var $currentSimpleType = null;
01104     // imports
01105     var $imports = array();
01106     // parser vars
01107     var $parser;
01108     var $position = 0;
01109     var $depth = 0;
01110     var $depth_array = array();
01111     var $message = array();
01112     var $defaultNamespace = array();
01113     
01122     function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
01123         parent::nusoap_base();
01124         $this->debug('nusoap_xmlschema class instantiated, inside constructor');
01125         // files
01126         $this->schema = $schema;
01127         $this->xml = $xml;
01128 
01129         // namespaces
01130         $this->enclosingNamespaces = $namespaces;
01131         $this->namespaces = array_merge($this->namespaces, $namespaces);
01132 
01133         // parse schema file
01134         if($schema != ''){
01135             $this->debug('initial schema file: '.$schema);
01136             $this->parseFile($schema, 'schema');
01137         }
01138 
01139         // parse xml file
01140         if($xml != ''){
01141             $this->debug('initial xml file: '.$xml);
01142             $this->parseFile($xml, 'xml');
01143         }
01144 
01145     }
01146 
01155     function parseFile($xml,$type){
01156         // parse xml file
01157         if($xml != ""){
01158             $xmlStr = @join("",@file($xml));
01159             if($xmlStr == ""){
01160                 $msg = 'Error reading XML from '.$xml;
01161                 $this->setError($msg);
01162                 $this->debug($msg);
01163             return false;
01164             } else {
01165                 $this->debug("parsing $xml");
01166                 $this->parseString($xmlStr,$type);
01167                 $this->debug("done parsing $xml");
01168             return true;
01169             }
01170         }
01171         return false;
01172     }
01173 
01181     function parseString($xml,$type){
01182         // parse xml string
01183         if($xml != ""){
01184 
01185             // Create an XML parser.
01186             $this->parser = xml_parser_create();
01187             // Set the options for parsing the XML data.
01188             xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
01189 
01190             // Set the object for the parser.
01191             xml_set_object($this->parser, $this);
01192 
01193             // Set the element handlers for the parser.
01194             if($type == "schema"){
01195                 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
01196                 xml_set_character_data_handler($this->parser,'schemaCharacterData');
01197             } elseif($type == "xml"){
01198                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
01199                 xml_set_character_data_handler($this->parser,'xmlCharacterData');
01200             }
01201 
01202             // Parse the XML file.
01203             if(!xml_parse($this->parser,$xml,true)){
01204             // Display an error message.
01205                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
01206                 xml_get_current_line_number($this->parser),
01207                 xml_error_string(xml_get_error_code($this->parser))
01208                 );
01209                 $this->debug($errstr);
01210                 $this->debug("XML payload:\n" . $xml);
01211                 $this->setError($errstr);
01212             }
01213             
01214             xml_parser_free($this->parser);
01215         } else{
01216             $this->debug('no xml passed to parseString()!!');
01217             $this->setError('no xml passed to parseString()!!');
01218         }
01219     }
01220 
01228     function CreateTypeName($ename) {
01229         $scope = '';
01230         for ($i = 0; $i < count($this->complexTypeStack); $i++) {
01231             $scope .= $this->complexTypeStack[$i] . '_';
01232         }
01233         return $scope . $ename . '_ContainedType';
01234     }
01235     
01244     function schemaStartElement($parser, $name, $attrs) {
01245         
01246         // position in the total number of elements, starting from 0
01247         $pos = $this->position++;
01248         $depth = $this->depth++;
01249         // set self as current value for this depth
01250         $this->depth_array[$depth] = $pos;
01251         $this->message[$pos] = array('cdata' => ''); 
01252         if ($depth > 0) {
01253             $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
01254         } else {
01255             $this->defaultNamespace[$pos] = false;
01256         }
01257 
01258         // get element prefix
01259         if($prefix = $this->getPrefix($name)){
01260             // get unqualified name
01261             $name = $this->getLocalPart($name);
01262         } else {
01263             $prefix = '';
01264         }
01265         
01266         // loop thru attributes, expanding, and registering namespace declarations
01267         if(count($attrs) > 0){
01268             foreach($attrs as $k => $v){
01269                 // if ns declarations, add to class level array of valid namespaces
01270                 if(ereg("^xmlns",$k)){
01271                     //$this->xdebug("$k: $v");
01272                     //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
01273                     if($ns_prefix = substr(strrchr($k,':'),1)){
01274                         //$this->xdebug("Add namespace[$ns_prefix] = $v");
01275                         $this->namespaces[$ns_prefix] = $v;
01276                     } else {
01277                         $this->defaultNamespace[$pos] = $v;
01278                         if (! $this->getPrefixFromNamespace($v)) {
01279                             $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
01280                         }
01281                     }
01282                     if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
01283                         $this->XMLSchemaVersion = $v;
01284                         $this->namespaces['xsi'] = $v.'-instance';
01285                     }
01286                 }
01287             }
01288             foreach($attrs as $k => $v){
01289                 // expand each attribute
01290                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
01291                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
01292                 $eAttrs[$k] = $v;
01293             }
01294             $attrs = $eAttrs;
01295         } else {
01296             $attrs = array();
01297         }
01298         // find status, register data
01299         switch($name){
01300             case 'all':         // (optional) compositor content for a complexType
01301             case 'choice':
01302             case 'group':
01303             case 'sequence':
01304                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
01305                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
01306                 //if($name == 'all' || $name == 'sequence'){
01307                 //  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01308                 //}
01309             break;
01310             case 'attribute':   // complexType attribute
01311                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
01312                 $this->xdebug("parsing attribute:");
01313                 $this->appendDebug($this->varDump($attrs));
01314                 if (!isset($attrs['form'])) {
01315                     $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
01316                 }
01317                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01318                     $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01319                     if (!strpos($v, ':')) {
01320                         // no namespace in arrayType attribute value...
01321                         if ($this->defaultNamespace[$pos]) {
01322                             // ...so use the default
01323                             $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01324                         }
01325                     }
01326                 }
01327                 if(isset($attrs['name'])){
01328                     $this->attributes[$attrs['name']] = $attrs;
01329                     $aname = $attrs['name'];
01330                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
01331                     if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01332                         $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01333                     } else {
01334                         $aname = '';
01335                     }
01336                 } elseif(isset($attrs['ref'])){
01337                     $aname = $attrs['ref'];
01338                     $this->attributes[$attrs['ref']] = $attrs;
01339                 }
01340                 
01341                 if($this->currentComplexType){  // This should *always* be
01342                     $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
01343                 }
01344                 // arrayType attribute
01345                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
01346                     $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01347                     $prefix = $this->getPrefix($aname);
01348                     if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
01349                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01350                     } else {
01351                         $v = '';
01352                     }
01353                     if(strpos($v,'[,]')){
01354                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
01355                     }
01356                     $v = substr($v,0,strpos($v,'[')); // clip the []
01357                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
01358                         $v = $this->XMLSchemaVersion.':'.$v;
01359                     }
01360                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
01361                 }
01362             break;
01363             case 'complexContent':  // (optional) content for a complexType
01364             break;
01365             case 'complexType':
01366                 array_push($this->complexTypeStack, $this->currentComplexType);
01367                 if(isset($attrs['name'])){
01368                     // TODO: what is the scope of named complexTypes that appear
01369                     //       nested within other c complexTypes?
01370                     $this->xdebug('processing named complexType '.$attrs['name']);
01371                     //$this->currentElement = false;
01372                     $this->currentComplexType = $attrs['name'];
01373                     $this->complexTypes[$this->currentComplexType] = $attrs;
01374                     $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01375                     // This is for constructs like
01376                     //           <complexType name="ListOfString" base="soap:Array">
01377                     //                <sequence>
01378                     //                    <element name="string" type="xsd:string"
01379                     //                        minOccurs="0" maxOccurs="unbounded" />
01380                     //                </sequence>
01381                     //            </complexType>
01382                     if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01383                         $this->xdebug('complexType is unusual array');
01384                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01385                     } else {
01386                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01387                     }
01388                 } else {
01389                     $name = $this->CreateTypeName($this->currentElement);
01390                     $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
01391                     $this->currentComplexType = $name;
01392                     //$this->currentElement = false;
01393                     $this->complexTypes[$this->currentComplexType] = $attrs;
01394                     $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01395                     // This is for constructs like
01396                     //           <complexType name="ListOfString" base="soap:Array">
01397                     //                <sequence>
01398                     //                    <element name="string" type="xsd:string"
01399                     //                        minOccurs="0" maxOccurs="unbounded" />
01400                     //                </sequence>
01401                     //            </complexType>
01402                     if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01403                         $this->xdebug('complexType is unusual array');
01404                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01405                     } else {
01406                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01407                     }
01408                 }
01409             break;
01410             case 'element':
01411                 array_push($this->elementStack, $this->currentElement);
01412                 if (!isset($attrs['form'])) {
01413                     $attrs['form'] = $this->schemaInfo['elementFormDefault'];
01414                 }
01415                 if(isset($attrs['type'])){
01416                     $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
01417                     if (! $this->getPrefix($attrs['type'])) {
01418                         if ($this->defaultNamespace[$pos]) {
01419                             $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
01420                             $this->xdebug('used default namespace to make type ' . $attrs['type']);
01421                         }
01422                     }
01423                     // This is for constructs like
01424                     //           <complexType name="ListOfString" base="soap:Array">
01425                     //                <sequence>
01426                     //                    <element name="string" type="xsd:string"
01427                     //                        minOccurs="0" maxOccurs="unbounded" />
01428                     //                </sequence>
01429                     //            </complexType>
01430                     if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
01431                         $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
01432                         $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
01433                     }
01434                     $this->currentElement = $attrs['name'];
01435                     $ename = $attrs['name'];
01436                 } elseif(isset($attrs['ref'])){
01437                     $this->xdebug("processing element as ref to ".$attrs['ref']);
01438                     $this->currentElement = "ref to ".$attrs['ref'];
01439                     $ename = $this->getLocalPart($attrs['ref']);
01440                 } else {
01441                     $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
01442                     $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
01443                     $this->currentElement = $attrs['name'];
01444                     $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
01445                     $ename = $attrs['name'];
01446                 }
01447                 if (isset($ename) && $this->currentComplexType) {
01448                     $this->xdebug("add element $ename to complexType $this->currentComplexType");
01449                     $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
01450                 } elseif (!isset($attrs['ref'])) {
01451                     $this->xdebug("add element $ename to elements array");
01452                     $this->elements[ $attrs['name'] ] = $attrs;
01453                     $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01454                 }
01455             break;
01456             case 'enumeration': //  restriction value list member
01457                 $this->xdebug('enumeration ' . $attrs['value']);
01458                 if ($this->currentSimpleType) {
01459                     $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
01460                 } elseif ($this->currentComplexType) {
01461                     $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
01462                 }
01463             break;
01464             case 'extension':   // simpleContent or complexContent type extension
01465                 $this->xdebug('extension ' . $attrs['base']);
01466                 if ($this->currentComplexType) {
01467                     $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
01468                 }
01469             break;
01470             case 'import':
01471                 if (isset($attrs['schemaLocation'])) {
01472                     //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
01473                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
01474                 } else {
01475                     //$this->xdebug('import namespace ' . $attrs['namespace']);
01476                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
01477                     if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
01478                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
01479                     }
01480                 }
01481             break;
01482             case 'list':    // simpleType value list
01483             break;
01484             case 'restriction': // simpleType, simpleContent or complexContent value restriction
01485                 $this->xdebug('restriction ' . $attrs['base']);
01486                 if($this->currentSimpleType){
01487                     $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
01488                 } elseif($this->currentComplexType){
01489                     $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
01490                     if(strstr($attrs['base'],':') == ':Array'){
01491                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01492                     }
01493                 }
01494             break;
01495             case 'schema':
01496                 $this->schemaInfo = $attrs;
01497                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
01498                 if (isset($attrs['targetNamespace'])) {
01499                     $this->schemaTargetNamespace = $attrs['targetNamespace'];
01500                 }
01501                 if (!isset($attrs['elementFormDefault'])) {
01502                     $this->schemaInfo['elementFormDefault'] = 'unqualified';
01503                 }
01504                 if (!isset($attrs['attributeFormDefault'])) {
01505                     $this->schemaInfo['attributeFormDefault'] = 'unqualified';
01506                 }
01507             break;
01508             case 'simpleContent':   // (optional) content for a complexType
01509             break;
01510             case 'simpleType':
01511                 array_push($this->simpleTypeStack, $this->currentSimpleType);
01512                 if(isset($attrs['name'])){
01513                     $this->xdebug("processing simpleType for name " . $attrs['name']);
01514                     $this->currentSimpleType = $attrs['name'];
01515                     $this->simpleTypes[ $attrs['name'] ] = $attrs;
01516                     $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
01517                     $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
01518                 } else {
01519                     $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
01520                     $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
01521                     $this->currentSimpleType = $name;
01522                     //$this->currentElement = false;
01523                     $this->simpleTypes[$this->currentSimpleType] = $attrs;
01524                     $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
01525                 }
01526             break;
01527             case 'union':   // simpleType type list
01528             break;
01529             default:
01530                 //$this->xdebug("do not have anything to do for element $name");
01531         }
01532     }
01533 
01541     function schemaEndElement($parser, $name) {
01542         // bring depth down a notch
01543         $this->depth--;
01544         // position of current element is equal to the last value left in depth_array for my depth
01545         if(isset($this->depth_array[$this->depth])){
01546             $pos = $this->depth_array[$this->depth];
01547         }
01548         // get element prefix
01549         if ($prefix = $this->getPrefix($name)){
01550             // get unqualified name
01551             $name = $this->getLocalPart($name);
01552         } else {
01553             $prefix = '';
01554         }
01555         // move on...
01556         if($name == 'complexType'){
01557             $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
01558             $this->currentComplexType = array_pop($this->complexTypeStack);
01559             //$this->currentElement = false;
01560         }
01561         if($name == 'element'){
01562             $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
01563             $this->currentElement = array_pop($this->elementStack);
01564         }
01565         if($name == 'simpleType'){
01566             $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
01567             $this->currentSimpleType = array_pop($this->simpleTypeStack);
01568         }
01569     }
01570 
01578     function schemaCharacterData($parser, $data){
01579         $pos = $this->depth_array[$this->depth - 1];
01580         $this->message[$pos]['cdata'] .= $data;
01581     }
01582 
01588     function serializeSchema(){
01589 
01590         $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
01591         $xml = '';
01592         // imports
01593         if (sizeof($this->imports) > 0) {
01594             foreach($this->imports as $ns => $list) {
01595                 foreach ($list as $ii) {
01596                     if ($ii['location'] != '') {
01597                         $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
01598                     } else {
01599                         $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
01600                     }
01601                 }
01602             } 
01603         } 
01604         // complex types
01605         foreach($this->complexTypes as $typeName => $attrs){
01606             $contentStr = '';
01607             // serialize child elements
01608             if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
01609                 foreach($attrs['elements'] as $element => $eParts){
01610                     if(isset($eParts['ref'])){
01611                         $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
01612                     } else {
01613                         $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
01614                         foreach ($eParts as $aName => $aValue) {
01615                             // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
01616                             if ($aName != 'name' && $aName != 'type') {
01617                                 $contentStr .= " $aName=\"$aValue\"";
01618                             }
01619                         }
01620                         $contentStr .= "/>\n";
01621                     }
01622                 }
01623                 // compositor wraps elements
01624                 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
01625                     $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
01626                 }
01627             }
01628             // attributes
01629             if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
01630                 foreach($attrs['attrs'] as $attr => $aParts){
01631                     $contentStr .= "    <$schemaPrefix:attribute";
01632                     foreach ($aParts as $a => $v) {
01633                         if ($a == 'ref' || $a == 'type') {
01634                             $contentStr .= " $a=\"".$this->contractQName($v).'"';
01635                         } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
01636                             $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
01637                             $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
01638                         } else {
01639                             $contentStr .= " $a=\"$v\"";
01640                         }
01641                     }
01642                     $contentStr .= "/>\n";
01643                 }
01644             }
01645             // if restriction
01646             if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
01647                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
01648                 // complex or simple content
01649                 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
01650                     $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
01651                 }
01652             }
01653             // finalize complex type
01654             if($contentStr != ''){
01655                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
01656             } else {
01657                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
01658             }
01659             $xml .= $contentStr;
01660         }
01661         // simple types
01662         if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
01663             foreach($this->simpleTypes as $typeName => $eParts){
01664                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
01665                 if (isset($eParts['enumeration'])) {
01666                     foreach ($eParts['enumeration'] as $e) {
01667                         $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
01668                     }
01669                 }
01670                 $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
01671             }
01672         }
01673         // elements
01674         if(isset($this->elements) && count($this->elements) > 0){
01675             foreach($this->elements as $element => $eParts){
01676                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
01677             }
01678         }
01679         // attributes
01680         if(isset($this->attributes) && count($this->attributes) > 0){
01681             foreach($this->attributes as $attr => $aParts){
01682                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
01683             }
01684         }
01685         // finish 'er up
01686         $attr = '';
01687         foreach ($this->schemaInfo as $k => $v) {
01688             if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
01689                 $attr .= " $k=\"$v\"";
01690             }
01691         }
01692         $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
01693         foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
01694             $el .= " xmlns:$nsp=\"$ns\"";
01695         }
01696         $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
01697         return $xml;
01698     }
01699 
01706     function xdebug($string){
01707         $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
01708     }
01709 
01722     function getPHPType($type,$ns){
01723         if(isset($this->typemap[$ns][$type])){
01724             //print "found type '$type' and ns $ns in typemap<br>";
01725             return $this->typemap[$ns][$type];
01726         } elseif(isset($this->complexTypes[$type])){
01727             //print "getting type '$type' and ns $ns from complexTypes array<br>";
01728             return $this->complexTypes[$type]['phpType'];
01729         }
01730         return false;
01731     }
01732 
01755     function getTypeDef($type){
01756         //$this->debug("in getTypeDef for type $type");
01757         if (substr($type, -1) == '^') {
01758             $is_element = 1;
01759             $type = substr($type, 0, -1);
01760         } else {
01761             $is_element = 0;
01762         }
01763 
01764         if((! $is_element) && isset($this->complexTypes[$type])){
01765             $this->xdebug("in getTypeDef, found complexType $type");
01766             return $this->complexTypes[$type];
01767         } elseif((! $is_element) && isset($this->simpleTypes[$type])){
01768             $this->xdebug("in getTypeDef, found simpleType $type");
01769             if (!isset($this->simpleTypes[$type]['phpType'])) {
01770                 // get info for type to tack onto the simple type
01771                 // TODO: can this ever really apply (i.e. what is a simpleType really?)
01772                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
01773                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
01774                 $etype = $this->getTypeDef($uqType);
01775                 if ($etype) {
01776                     $this->xdebug("in getTypeDef, found type for simpleType $type:");
01777                     $this->xdebug($this->varDump($etype));
01778                     if (isset($etype['phpType'])) {
01779                         $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
01780                     }
01781                     if (isset($etype['elements'])) {
01782                         $this->simpleTypes[$type]['elements'] = $etype['elements'];
01783                     }
01784                 }
01785             }
01786             return $this->simpleTypes[$type];
01787         } elseif(isset($this->elements[$type])){
01788             $this->xdebug("in getTypeDef, found element $type");
01789             if (!isset($this->elements[$type]['phpType'])) {
01790                 // get info for type to tack onto the element
01791                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
01792                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
01793                 $etype = $this->getTypeDef($uqType);
01794                 if ($etype) {
01795                     $this->xdebug("in getTypeDef, found type for element $type:");
01796                     $this->xdebug($this->varDump($etype));
01797                     if (isset($etype['phpType'])) {
01798                         $this->elements[$type]['phpType'] = $etype['phpType'];
01799                     }
01800                     if (isset($etype['elements'])) {
01801                         $this->elements[$type]['elements'] = $etype['elements'];
01802                     }
01803                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
01804                     $this->xdebug("in getTypeDef, element $type is an XSD type");
01805                     $this->elements[$type]['phpType'] = 'scalar';
01806                 }
01807             }
01808             return $this->elements[$type];
01809         } elseif(isset($this->attributes[$type])){
01810             $this->xdebug("in getTypeDef, found attribute $type");
01811             return $this->attributes[$type];
01812         } elseif (ereg('_ContainedType$', $type)) {
01813             $this->xdebug("in getTypeDef, have an untyped element $type");
01814             $typeDef['typeClass'] = 'simpleType';
01815             $typeDef['phpType'] = 'scalar';
01816             $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
01817             return $typeDef;
01818         }
01819         $this->xdebug("in getTypeDef, did not find $type");
01820         return false;
01821     }
01822 
01831     function serializeTypeDef($type){
01832         //print "in sTD() for type $type<br>";
01833     if($typeDef = $this->getTypeDef($type)){
01834         $str .= '<'.$type;
01835         if(is_array($typeDef['attrs'])){
01836         foreach($typeDef['attrs'] as $attName => $data){
01837             $str .= " $attName=\"{type = ".$data['type']."}\"";
01838         }
01839         }
01840         $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
01841         if(count($typeDef['elements']) > 0){
01842         $str .= ">";
01843         foreach($typeDef['elements'] as $element => $eData){
01844             $str .= $this->serializeTypeDef($element);
01845         }
01846         $str .= "</$type>";
01847         } elseif($typeDef['typeClass'] == 'element') {
01848         $str .= "></$type>";
01849         } else {
01850         $str .= "/>";
01851         }
01852             return $str;
01853     }
01854         return false;
01855     }
01856 
01867     function typeToForm($name,$type){
01868         // get typedef
01869         if($typeDef = $this->getTypeDef($type)){
01870             // if struct
01871             if($typeDef['phpType'] == 'struct'){
01872                 $buffer .= '<table>';
01873                 foreach($typeDef['elements'] as $child => $childDef){
01874                     $buffer .= "
01875                     <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
01876                     <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
01877                 }
01878                 $buffer .= '</table>';
01879             // if array
01880             } elseif($typeDef['phpType'] == 'array'){
01881                 $buffer .= '<table>';
01882                 for($i=0;$i < 3; $i++){
01883                     $buffer .= "
01884                     <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
01885                     <td><input type='text' name='parameters[".$name."][]'></td></tr>";
01886                 }
01887                 $buffer .= '</table>';
01888             // if scalar
01889             } else {
01890                 $buffer .= "<input type='text' name='parameters[$name]'>";
01891             }
01892         } else {
01893             $buffer .= "<input type='text' name='parameters[$name]'>";
01894         }
01895         return $buffer;
01896     }
01897     
01939     function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
01940         $this->complexTypes[$name] = array(
01941         'name'      => $name,
01942         'typeClass' => $typeClass,
01943         'phpType'   => $phpType,
01944         'compositor'=> $compositor,
01945         'restrictionBase' => $restrictionBase,
01946         'elements'  => $elements,
01947         'attrs'     => $attrs,
01948         'arrayType' => $arrayType
01949         );
01950         
01951         $this->xdebug("addComplexType $name:");
01952         $this->appendDebug($this->varDump($this->complexTypes[$name]));
01953     }
01954     
01967     function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
01968         $this->simpleTypes[$name] = array(
01969         'name'          => $name,
01970         'typeClass'     => $typeClass,
01971         'phpType'       => $phpType,
01972         'type'          => $restrictionBase,
01973         'enumeration'   => $enumeration
01974         );
01975         
01976         $this->xdebug("addSimpleType $name:");
01977         $this->appendDebug($this->varDump($this->simpleTypes[$name]));
01978     }
01979 
01987     function addElement($attrs) {
01988         if (! $this->getPrefix($attrs['type'])) {
01989             $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
01990         }
01991         $this->elements[ $attrs['name'] ] = $attrs;
01992         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01993         
01994         $this->xdebug("addElement " . $attrs['name']);
01995         $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
01996     }
01997 }
01998 
02002 class XMLSchema extends nusoap_xmlschema {
02003 }
02004 
02005 ?><?php
02006 
02007 
02008 
02020 class soapval extends nusoap_base {
02027     var $name;
02034     var $type;
02041     var $value;
02048     var $element_ns;
02055     var $type_ns;
02062     var $attributes;
02063 
02075     function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
02076         parent::nusoap_base();
02077         $this->name = $name;
02078         $this->type = $type;
02079         $this->value = $value;
02080         $this->element_ns = $element_ns;
02081         $this->type_ns = $type_ns;
02082         $this->attributes = $attributes;
02083     }
02084 
02092     function serialize($use='encoded') {
02093         return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
02094     }
02095 
02102     function decode(){
02103         return $this->value;
02104     }
02105 }
02106 
02107 
02108 
02109 ?><?php
02110 
02111 
02112 
02122 class soap_transport_http extends nusoap_base {
02123 
02124     var $url = '';
02125     var $uri = '';
02126     var $digest_uri = '';
02127     var $scheme = '';
02128     var $host = '';
02129     var $port = '';
02130     var $path = '';
02131     var $request_method = 'POST';
02132     var $protocol_version = '1.0';
02133     var $encoding = '';
02134     var $outgoing_headers = array();
02135     var $incoming_headers = array();
02136     var $incoming_cookies = array();
02137     var $outgoing_payload = '';
02138     var $incoming_payload = '';
02139     var $response_status_line;  // HTTP response status line
02140     var $useSOAPAction = true;
02141     var $persistentConnection = false;
02142     var $ch = false;    // cURL handle
02143     var $ch_options = array();  // cURL custom options
02144     var $use_curl = false;      // force cURL use
02145     var $proxy = null;          // proxy information (associative array)
02146     var $username = '';
02147     var $password = '';
02148     var $authtype = '';
02149     var $digestRequest = array();
02150     var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
02151                                 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
02152                                 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
02153                                 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
02154                                 // passphrase: SSL key password/passphrase
02155                                 // certpassword: SSL certificate password
02156                                 // verifypeer: default is 1
02157                                 // verifyhost: default is 1
02158 
02167     function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
02168         parent::nusoap_base();
02169         $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
02170         $this->appendDebug($this->varDump($curl_options));
02171         $this->setURL($url);
02172         if (is_array($curl_options)) {
02173             $this->ch_options = $curl_options;
02174         }
02175         $this->use_curl = $use_curl;
02176         ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
02177         $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
02178     }
02179 
02187     function setCurlOption($option, $value) {
02188         $this->debug("setCurlOption option=$option, value=");
02189         $this->appendDebug($this->varDump($value));
02190         curl_setopt($this->ch, $option, $value);
02191     }
02192 
02200     function setHeader($name, $value) {
02201         $this->outgoing_headers[$name] = $value;
02202         $this->debug("set header $name: $value");
02203     }
02204 
02211     function unsetHeader($name) {
02212         if (isset($this->outgoing_headers[$name])) {
02213             $this->debug("unset header $name");
02214             unset($this->outgoing_headers[$name]);
02215         }
02216     }
02217 
02224     function setURL($url) {
02225         $this->url = $url;
02226 
02227         $u = parse_url($url);
02228         foreach($u as $k => $v){
02229             $this->debug("parsed URL $k = $v");
02230             $this->$k = $v;
02231         }
02232         
02233         // add any GET params to path
02234         if(isset($u['query']) && $u['query'] != ''){
02235             $this->path .= '?' . $u['query'];
02236         }
02237         
02238         // set default port
02239         if(!isset($u['port'])){
02240             if($u['scheme'] == 'https'){
02241                 $this->port = 443;
02242             } else {
02243                 $this->port = 80;
02244             }
02245         }
02246         
02247         $this->uri = $this->path;
02248         $this->digest_uri = $this->uri;
02249         
02250         // build headers
02251         if (!isset($u['port'])) {
02252             $this->setHeader('Host', $this->host);
02253         } else {
02254             $this->setHeader('Host', $this->host.':'.$this->port);
02255         }
02256 
02257         if (isset($u['user']) && $u['user'] != '') {
02258             $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
02259         }
02260     }
02261 
02268     function io_method() {
02269         if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
02270             return 'curl';
02271         if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
02272             return 'socket';
02273         return 'unknown';
02274     }
02275 
02284     function connect($connection_timeout=0,$response_timeout=30){
02285         // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
02286         // "regular" socket.
02287         // TODO: disabled for now because OpenSSL must be *compiled* in (not just
02288         //       loaded), and until PHP5 stream_get_wrappers is not available.
02289 //      if ($this->scheme == 'https') {
02290 //          if (version_compare(phpversion(), '4.3.0') >= 0) {
02291 //              if (extension_loaded('openssl')) {
02292 //                  $this->scheme = 'ssl';
02293 //                  $this->debug('Using SSL over OpenSSL');
02294 //              }
02295 //          }
02296 //      }
02297         $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
02298       if ($this->io_method() == 'socket') {
02299         if (!is_array($this->proxy)) {
02300             $host = $this->host;
02301             $port = $this->port;
02302         } else {
02303             $host = $this->proxy['host'];
02304             $port = $this->proxy['port'];
02305         }
02306 
02307         // use persistent connection
02308         if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
02309             if (!feof($this->fp)) {
02310                 $this->debug('Re-use persistent connection');
02311                 return true;
02312             }
02313             fclose($this->fp);
02314             $this->debug('Closed persistent connection at EOF');
02315         }
02316 
02317         // munge host if using OpenSSL
02318         if ($this->scheme == 'ssl') {
02319             $host = 'ssl://' . $host;
02320         }
02321         $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
02322 
02323         // open socket
02324         if($connection_timeout > 0){
02325             $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
02326         } else {
02327             $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
02328         }
02329         
02330         // test pointer
02331         if(!$this->fp) {
02332             $msg = 'Couldn\'t open socket connection to server ' . $this->url;
02333             if ($this->errno) {
02334                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
02335             } else {
02336                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';
02337             }
02338             $this->debug($msg);
02339             $this->setError($msg);
02340             return false;
02341         }
02342         
02343         // set response timeout
02344         $this->debug('set response timeout to ' . $response_timeout);
02345         socket_set_timeout( $this->fp, $response_timeout);
02346 
02347         $this->debug('socket connected');
02348         return true;
02349       } else if ($this->io_method() == 'curl') {
02350         if (!extension_loaded('curl')) {
02351 //          $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
02352             $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.');
02353             return false;
02354         }
02355         // Avoid warnings when PHP does not have these options
02356         if (defined('CURLOPT_CONNECTIONTIMEOUT'))
02357             $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
02358         else
02359             $CURLOPT_CONNECTIONTIMEOUT = 78;
02360         if (defined('CURLOPT_HTTPAUTH'))
02361             $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
02362         else
02363             $CURLOPT_HTTPAUTH = 107;
02364         if (defined('CURLOPT_PROXYAUTH'))
02365             $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
02366         else
02367             $CURLOPT_PROXYAUTH = 111;
02368         if (defined('CURLAUTH_BASIC'))
02369             $CURLAUTH_BASIC = CURLAUTH_BASIC;
02370         else
02371             $CURLAUTH_BASIC = 1;
02372         if (defined('CURLAUTH_DIGEST'))
02373             $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
02374         else
02375             $CURLAUTH_DIGEST = 2;
02376         if (defined('CURLAUTH_NTLM'))
02377             $CURLAUTH_NTLM = CURLAUTH_NTLM;
02378         else
02379             $CURLAUTH_NTLM = 8;
02380 
02381         $this->debug('connect using cURL');
02382         // init CURL
02383         $this->ch = curl_init();
02384         // set url
02385         $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
02386         // add path
02387         $hostURL .= $this->path;
02388         $this->setCurlOption(CURLOPT_URL, $hostURL);
02389         // follow location headers (re-directs)
02390         if (ini_get('safe_mode') || ini_get('open_basedir')) {
02391             $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
02392             $this->debug('safe_mode = ');
02393             $this->appendDebug($this->varDump(ini_get('safe_mode')));
02394             $this->debug('open_basedir = ');
02395             $this->appendDebug($this->varDump(ini_get('open_basedir')));
02396         } else {
02397             $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
02398         }
02399         // ask for headers in the response output
02400         $this->setCurlOption(CURLOPT_HEADER, 1);
02401         // ask for the response output as the return value
02402         $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
02403         // encode
02404         // We manage this ourselves through headers and encoding
02405 //      if(function_exists('gzuncompress')){
02406 //          $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
02407 //      }
02408         // persistent connection
02409         if ($this->persistentConnection) {
02410             // I believe the following comment is now bogus, having applied to
02411             // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
02412             // The way we send data, we cannot use persistent connections, since
02413             // there will be some "junk" at the end of our request.
02414             //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
02415             $this->persistentConnection = false;
02416             $this->setHeader('Connection', 'close');
02417         }
02418         // set timeouts
02419         if ($connection_timeout != 0) {
02420             $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
02421         }
02422         if ($response_timeout != 0) {
02423             $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
02424         }
02425 
02426         if ($this->scheme == 'https') {
02427             $this->debug('set cURL SSL verify options');
02428             // recent versions of cURL turn on peer/host checking by default,
02429             // while PHP binaries are not compiled with a default location for the
02430             // CA cert bundle, so disable peer/host checking.
02431             //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');     
02432             $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
02433             $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
02434     
02435             // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
02436             if ($this->authtype == 'certificate') {
02437                 $this->debug('set cURL certificate options');
02438                 if (isset($this->certRequest['cainfofile'])) {
02439                     $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
02440                 }
02441                 if (isset($this->certRequest['verifypeer'])) {
02442                     $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
02443                 } else {
02444                     $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
02445                 }
02446                 if (isset($this->certRequest['verifyhost'])) {
02447                     $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
02448                 } else {
02449                     $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
02450                 }
02451                 if (isset($this->certRequest['sslcertfile'])) {
02452                     $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
02453                 }
02454                 if (isset($this->certRequest['sslkeyfile'])) {
02455                     $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
02456                 }
02457                 if (isset($this->certRequest['passphrase'])) {
02458                     $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
02459                 }
02460                 if (isset($this->certRequest['certpassword'])) {
02461                     $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
02462                 }
02463             }
02464         }
02465         if ($this->authtype && ($this->authtype != 'certificate')) {
02466             if ($this->username) {
02467                 $this->debug('set cURL username/password');
02468                 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
02469             }
02470             if ($this->authtype == 'basic') {
02471                 $this->debug('set cURL for Basic authentication');
02472                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
02473             }
02474             if ($this->authtype == 'digest') {
02475                 $this->debug('set cURL for digest authentication');
02476                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
02477             }
02478             if ($this->authtype == 'ntlm') {
02479                 $this->debug('set cURL for NTLM authentication');
02480                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
02481             }
02482         }
02483         if (is_array($this->proxy)) {
02484             $this->debug('set cURL proxy options');
02485             if ($this->proxy['port'] != '') {
02486                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
02487             } else {
02488                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
02489             }
02490             if ($this->proxy['username'] || $this->proxy['password']) {
02491                 $this->debug('set cURL proxy authentication options');
02492                 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
02493                 if ($this->proxy['authtype'] == 'basic') {
02494                     $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
02495                 }
02496                 if ($this->proxy['authtype'] == 'ntlm') {
02497                     $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
02498                 }
02499             }
02500         }
02501         $this->debug('cURL connection set up');
02502         return true;
02503       } else {
02504         $this->setError('Unknown scheme ' . $this->scheme);
02505         $this->debug('Unknown scheme ' . $this->scheme);
02506         return false;
02507       }
02508     }
02509 
02520     function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
02521         
02522         $this->debug('entered send() with data of length: '.strlen($data));
02523 
02524         $this->tryagain = true;
02525         $tries = 0;
02526         while ($this->tryagain) {
02527             $this->tryagain = false;
02528             if ($tries++ < 2) {
02529                 // make connnection
02530                 if (!$this->connect($timeout, $response_timeout)){
02531                     return false;
02532                 }
02533                 
02534                 // send request
02535                 if (!$this->sendRequest($data, $cookies)){
02536                     return false;
02537                 }
02538                 
02539                 // get response
02540                 $respdata = $this->getResponse();
02541             } else {
02542                 $this->setError("Too many tries to get an OK response ($this->response_status_line)");
02543             }
02544         }       
02545         $this->debug('end of send()');
02546         return $respdata;
02547     }
02548 
02549 
02561     function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
02562         return $this->send($data, $timeout, $response_timeout, $cookies);
02563     }
02564     
02575     function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
02576         $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
02577         $this->appendDebug($this->varDump($digestRequest));
02578         $this->debug("certRequest=");
02579         $this->appendDebug($this->varDump($certRequest));
02580         // cf. RFC 2617
02581         if ($authtype == 'basic') {
02582             $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
02583         } elseif ($authtype == 'digest') {
02584             if (isset($digestRequest['nonce'])) {
02585                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
02586                 
02587                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
02588     
02589                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
02590                 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
02591     
02592                 // H(A1) = MD5(A1)
02593                 $HA1 = md5($A1);
02594     
02595                 // A2 = Method ":" digest-uri-value
02596                 $A2 = $this->request_method . ':' . $this->digest_uri;
02597     
02598                 // H(A2)
02599                 $HA2 =  md5($A2);
02600     
02601                 // KD(secret, data) = H(concat(secret, ":", data))
02602                 // if qop == auth:
02603                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
02604                 //                              ":" nc-value
02605                 //                              ":" unq(cnonce-value)
02606                 //                              ":" unq(qop-value)
02607                 //                              ":" H(A2)
02608                 //                            ) <">
02609                 // if qop is missing,
02610                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
02611     
02612                 $unhashedDigest = '';
02613                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
02614                 $cnonce = $nonce;
02615                 if ($digestRequest['qop'] != '') {
02616                     $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
02617                 } else {
02618                     $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
02619                 }
02620     
02621                 $hashedDigest = md5($unhashedDigest);
02622     
02623                 $opaque = '';   
02624                 if (isset($digestRequest['opaque'])) {
02625                     $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
02626                 }
02627 
02628                 $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 . '"');
02629             }
02630         } elseif ($authtype == 'certificate') {
02631             $this->certRequest = $certRequest;
02632             $this->debug('Authorization header not set for certificate');
02633         } elseif ($authtype == 'ntlm') {
02634             // do nothing
02635             $this->debug('Authorization header not set for ntlm');
02636         }
02637         $this->username = $username;
02638         $this->password = $password;
02639         $this->authtype = $authtype;
02640         $this->digestRequest = $digestRequest;
02641     }
02642     
02649     function setSOAPAction($soapaction) {
02650         $this->setHeader('SOAPAction', '"' . $soapaction . '"');
02651     }
02652     
02659     function setEncoding($enc='gzip, deflate') {
02660         if (function_exists('gzdeflate')) {
02661             $this->protocol_version = '1.1';
02662             $this->setHeader('Accept-Encoding', $enc);
02663             if (!isset($this->outgoing_headers['Connection'])) {
02664                 $this->setHeader('Connection', 'close');
02665                 $this->persistentConnection = false;
02666             }
02667             set_magic_quotes_runtime(0);
02668             // deprecated
02669             $this->encoding = $enc;
02670         }
02671     }
02672     
02683     function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
02684         if ($proxyhost) {
02685             $this->proxy = array(
02686                 'host' => $proxyhost,
02687                 'port' => $proxyport,
02688                 'username' => $proxyusername,
02689                 'password' => $proxypassword,
02690                 'authtype' => $proxyauthtype
02691             );
02692             if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
02693                 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
02694             }
02695         } else {
02696             $this->debug('remove proxy');
02697             $proxy = null;
02698             unsetHeader('Proxy-Authorization');
02699         }
02700     }
02701     
02702 
02711     function isSkippableCurlHeader(&$data) {
02712         $skipHeaders = array(   'HTTP/1.1 100',
02713                                 'HTTP/1.0 301',
02714                                 'HTTP/1.1 301',
02715                                 'HTTP/1.0 302',
02716                                 'HTTP/1.1 302',
02717                                 'HTTP/1.0 401',
02718                                 'HTTP/1.1 401',
02719                                 'HTTP/1.0 200 Connection established');
02720         foreach ($skipHeaders as $hd) {
02721             $prefix = substr($data, 0, strlen($hd));
02722             if ($prefix == $hd) return true;
02723         }
02724 
02725         return false;
02726     }
02727 
02738     function decodeChunked($buffer, $lb){
02739         // length := 0
02740         $length = 0;
02741         $new = '';
02742         
02743         // read chunk-size, chunk-extension (if any) and CRLF
02744         // get the position of the linebreak
02745         $chunkend = strpos($buffer, $lb);
02746         if ($chunkend == FALSE) {
02747             $this->debug('no linebreak found in decodeChunked');
02748             return $new;
02749         }
02750         $temp = substr($buffer,0,$chunkend);
02751         $chunk_size = hexdec( trim($temp) );
02752         $chunkstart = $chunkend + strlen($lb);
02753         // while (chunk-size > 0) {
02754         while ($chunk_size > 0) {
02755             $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
02756             $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
02757             
02758             // Just in case we got a broken connection
02759             if ($chunkend == FALSE) {
02760                 $chunk = substr($buffer,$chunkstart);
02761                 // append chunk-data to entity-body
02762                 $new .= $chunk;
02763                 $length += strlen($chunk);
02764                 break;
02765             }
02766             
02767             // read chunk-data and CRLF
02768             $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
02769             // append chunk-data to entity-body
02770             $new .= $chunk;
02771             // length := length + chunk-size
02772             $length += strlen($chunk);
02773             // read chunk-size and CRLF
02774             $chunkstart = $chunkend + strlen($lb);
02775             
02776             $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
02777             if ($chunkend == FALSE) {
02778                 break; //Just in case we got a broken connection
02779             }
02780             $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
02781             $chunk_size = hexdec( trim($temp) );
02782             $chunkstart = $chunkend;
02783         }
02784         return $new;
02785     }
02786     
02795     function buildPayload($data, $cookie_str = '') {
02796         // Note: for cURL connections, $this->outgoing_payload is ignored,
02797         // as is the Content-Length header, but these are still created as
02798         // debugging guides.
02799 
02800         // add content-length header
02801         $this->setHeader('Content-Length', strlen($data));
02802 
02803         // start building outgoing payload:
02804         if ($this->proxy) {
02805             $uri = $this->url;
02806         } else {
02807             $uri = $this->uri;
02808         }
02809         $req = "$this->request_method $uri HTTP/$this->protocol_version";
02810         $this->debug("HTTP request: $req");
02811         $this->outgoing_payload = "$req\r\n";
02812 
02813         // loop thru headers, serializing
02814         foreach($this->outgoing_headers as $k => $v){
02815             $hdr = $k.': '.$v;
02816             $this->debug("HTTP header: $hdr");
02817             $this->outgoing_payload .= "$hdr\r\n";
02818         }
02819 
02820         // add any cookies
02821         if ($cookie_str != '') {
02822             $hdr = 'Cookie: '.$cookie_str;
02823             $this->debug("HTTP header: $hdr");
02824             $this->outgoing_payload .= "$hdr\r\n";
02825         }
02826 
02827         // header/body separator
02828         $this->outgoing_payload .= "\r\n";
02829         
02830         // add data
02831         $this->outgoing_payload .= $data;
02832     }
02833 
02842     function sendRequest($data, $cookies = NULL) {
02843         // build cookie string
02844         $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
02845 
02846         // build payload
02847         $this->buildPayload($data, $cookie_str);
02848 
02849       if ($this->io_method() == 'socket') {
02850         // send payload
02851         if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
02852             $this->setError('couldn\'t write message data to socket');
02853             $this->debug('couldn\'t write message data to socket');
02854             return false;
02855         }
02856         $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
02857         return true;
02858       } else if ($this->io_method() == 'curl') {
02859         // set payload
02860         // cURL does say this should only be the verb, and in fact it
02861         // turns out that the URI and HTTP version are appended to this, which
02862         // some servers refuse to work with (so we no longer use this method!)
02863         //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
02864         $curl_headers = array();
02865         foreach($this->outgoing_headers as $k => $v){
02866             if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
02867                 $this->debug("Skip cURL header $k: $v");
02868             } else {
02869                 $curl_headers[] = "$k: $v";
02870             }
02871         }
02872         if ($cookie_str != '') {
02873             $curl_headers[] = 'Cookie: ' . $cookie_str;
02874         }
02875         $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
02876         $this->debug('set cURL HTTP headers');
02877         if ($this->request_method == "POST") {
02878             $this->setCurlOption(CURLOPT_POST, 1);
02879             $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
02880             $this->debug('set cURL POST data');
02881         } else {
02882         }
02883         // insert custom user-set cURL options
02884         foreach ($this->ch_options as $key => $val) {
02885             $this->setCurlOption($key, $val);
02886         }
02887 
02888         $this->debug('set cURL payload');
02889         return true;
02890       }
02891     }
02892 
02899     function getResponse(){
02900         $this->incoming_payload = '';
02901         
02902       if ($this->io_method() == 'socket') {
02903         // loop until headers have been retrieved
02904         $data = '';
02905         while (!isset($lb)){
02906 
02907             // We might EOF during header read.
02908             if(feof($this->fp)) {
02909                 $this->incoming_payload = $data;
02910                 $this->debug('found no headers before EOF after length ' . strlen($data));
02911                 $this->debug("received before EOF:\n" . $data);
02912                 $this->setError('server failed to send headers');
02913                 return false;
02914             }
02915 
02916             $tmp = fgets($this->fp, 256);
02917             $tmplen = strlen($tmp);
02918             $this->debug("read line of $tmplen bytes: " . trim($tmp));
02919 
02920             if ($tmplen == 0) {
02921                 $this->incoming_payload = $data;
02922                 $this->debug('socket read of headers timed out after length ' . strlen($data));
02923                 $this->debug("read before timeout: " . $data);
02924                 $this->setError('socket read of headers timed out');
02925                 return false;
02926             }
02927 
02928             $data .= $tmp;
02929             $pos = strpos($data,"\r\n\r\n");
02930             if($pos > 1){
02931                 $lb = "\r\n";
02932             } else {
02933                 $pos = strpos($data,"\n\n");
02934                 if($pos > 1){
02935                     $lb = "\n";
02936                 }
02937             }
02938             // remove 100 headers
02939             if (isset($lb) && ereg('^HTTP/1.1 100',$data)) {
02940                 unset($lb);
02941                 $data = '';
02942             }//
02943         }
02944         // store header data
02945         $this->incoming_payload .= $data;
02946         $this->debug('found end of headers after length ' . strlen($data));
02947         // process headers
02948         $header_data = trim(substr($data,0,$pos));
02949         $header_array = explode($lb,$header_data);
02950         $this->incoming_headers = array();
02951         $this->incoming_cookies = array();
02952         foreach($header_array as $header_line){
02953             $arr = explode(':',$header_line, 2);
02954             if(count($arr) > 1){
02955                 $header_name = strtolower(trim($arr[0]));
02956                 $this->incoming_headers[$header_name] = trim($arr[1]);
02957                 if ($header_name == 'set-cookie') {
02958                     // TODO: allow multiple cookies from parseCookie
02959                     $cookie = $this->parseCookie(trim($arr[1]));
02960                     if ($cookie) {
02961                         $this->incoming_cookies[] = $cookie;
02962                         $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
02963                     } else {
02964                         $this->debug('did not find cookie in ' . trim($arr[1]));
02965                     }
02966                 }
02967             } else if (isset($header_name)) {
02968                 // append continuation line to previous header
02969                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
02970             }
02971         }
02972         
02973         // loop until msg has been received
02974         if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
02975             $content_length =  2147483647;  // ignore any content-length header
02976             $chunked = true;
02977             $this->debug("want to read chunked content");
02978         } elseif (isset($this->incoming_headers['content-length'])) {
02979             $content_length = $this->incoming_headers['content-length'];
02980             $chunked = false;
02981             $this->debug("want to read content of length $content_length");
02982         } else {
02983             $content_length =  2147483647;
02984             $chunked = false;
02985             $this->debug("want to read content to EOF");
02986         }
02987         $data = '';
02988         do {
02989             if ($chunked) {
02990                 $tmp = fgets($this->fp, 256);
02991                 $tmplen = strlen($tmp);
02992                 $this->debug("read chunk line of $tmplen bytes");
02993                 if ($tmplen == 0) {
02994                     $this->incoming_payload = $data;
02995                     $this->debug('socket read of chunk length timed out after length ' . strlen($data));
02996                     $this->debug("read before timeout:\n" . $data);
02997                     $this->setError('socket read of chunk length timed out');
02998                     return false;
02999                 }
03000                 $content_length = hexdec(trim($tmp));
03001                 $this->debug("chunk length $content_length");
03002             }
03003             $strlen = 0;
03004             while (($strlen < $content_length) && (!feof($this->fp))) {
03005                 $readlen = min(8192, $content_length - $strlen);
03006                 $tmp = fread($this->fp, $readlen);
03007                 $tmplen = strlen($tmp);
03008                 $this->debug("read buffer of $tmplen bytes");
03009                 if (($tmplen == 0) && (!feof($this->fp))) {
03010                     $this->incoming_payload = $data;
03011                     $this->debug('socket read of body timed out after length ' . strlen($data));
03012                     $this->debug("read before timeout:\n" . $data);
03013                     $this->setError('socket read of body timed out');
03014                     return false;
03015                 }
03016                 $strlen += $tmplen;
03017                 $data .= $tmp;
03018             }
03019             if ($chunked && ($content_length > 0)) {
03020                 $tmp = fgets($this->fp, 256);
03021                 $tmplen = strlen($tmp);
03022                 $this->debug("read chunk terminator of $tmplen bytes");
03023                 if ($tmplen == 0) {
03024                     $this->incoming_payload = $data;
03025                     $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
03026                     $this->debug("read before timeout:\n" . $data);
03027                     $this->setError('socket read of chunk terminator timed out');
03028                     return false;
03029                 }
03030             }
03031         } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
03032         if (feof($this->fp)) {
03033             $this->debug('read to EOF');
03034         }
03035         $this->debug('read body of length ' . strlen($data));
03036         $this->incoming_payload .= $data;
03037         $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
03038         
03039         // close filepointer
03040         if(
03041             (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 
03042             (! $this->persistentConnection) || feof($this->fp)){
03043             fclose($this->fp);
03044             $this->fp = false;
03045             $this->debug('closed socket');
03046         }
03047         
03048         // connection was closed unexpectedly
03049         if($this->incoming_payload == ''){
03050             $this->setError('no response from server');
03051             return false;
03052         }
03053         
03054         // decode transfer-encoding
03055 //      if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
03056 //          if(!$data = $this->decodeChunked($data, $lb)){
03057 //              $this->setError('Decoding of chunked data failed');
03058 //              return false;
03059 //          }
03060             //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
03061             // set decoded payload
03062 //          $this->incoming_payload = $header_data.$lb.$lb.$data;
03063 //      }
03064     
03065       } else if ($this->io_method() == 'curl') {
03066         // send and receive
03067         $this->debug('send and receive with cURL');
03068         $this->incoming_payload = curl_exec($this->ch);
03069         $data = $this->incoming_payload;
03070 
03071         $cErr = curl_error($this->ch);
03072         if ($cErr != '') {
03073             $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
03074             // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
03075             foreach(curl_getinfo($this->ch) as $k => $v){
03076                 $err .= "$k: $v<br>";
03077             }
03078             $this->debug($err);
03079             $this->setError($err);
03080             curl_close($this->ch);
03081             return false;
03082         } else {
03083             //echo '<pre>';
03084             //var_dump(curl_getinfo($this->ch));
03085             //echo '</pre>';
03086         }
03087         // close curl
03088         $this->debug('No cURL error, closing cURL');
03089         curl_close($this->ch);
03090         
03091         // try removing skippable headers
03092         $savedata = $data;
03093         while ($this->isSkippableCurlHeader($data)) {
03094             $this->debug("Found HTTP header to skip");
03095             if ($pos = strpos($data,"\r\n\r\n")) {
03096                 $data = ltrim(substr($data,$pos));
03097             } elseif($pos = strpos($data,"\n\n") ) {
03098                 $data = ltrim(substr($data,$pos));
03099             }
03100         }
03101 
03102         if ($data == '') {
03103             // have nothing left; just remove 100 header(s)
03104             $data = $savedata;
03105             while (ereg('^HTTP/1.1 100',$data)) {
03106                 if ($pos = strpos($data,"\r\n\r\n")) {
03107                     $data = ltrim(substr($data,$pos));
03108                 } elseif($pos = strpos($data,"\n\n") ) {
03109                     $data = ltrim(substr($data,$pos));
03110                 }
03111             }
03112         }
03113         
03114         // separate content from HTTP headers
03115         if ($pos = strpos($data,"\r\n\r\n")) {
03116             $lb = "\r\n";
03117         } elseif( $pos = strpos($data,"\n\n")) {
03118             $lb = "\n";
03119         } else {
03120             $this->debug('no proper separation of headers and document');
03121             $this->setError('no proper separation of headers and document');
03122             return false;
03123         }
03124         $header_data = trim(substr($data,0,$pos));
03125         $header_array = explode($lb,$header_data);
03126         $data = ltrim(substr($data,$pos));
03127         $this->debug('found proper separation of headers and document');
03128         $this->debug('cleaned data, stringlen: '.strlen($data));
03129         // clean headers
03130         foreach ($header_array as $header_line) {
03131             $arr = explode(':',$header_line,2);
03132             if(count($arr) > 1){
03133                 $header_name = strtolower(trim($arr[0]));
03134                 $this->incoming_headers[$header_name] = trim($arr[1]);
03135                 if ($header_name == 'set-cookie') {
03136                     // TODO: allow multiple cookies from parseCookie
03137                     $cookie = $this->parseCookie(trim($arr[1]));
03138                     if ($cookie) {
03139                         $this->incoming_cookies[] = $cookie;
03140                         $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
03141                     } else {
03142                         $this->debug('did not find cookie in ' . trim($arr[1]));
03143                     }
03144                 }
03145             } else if (isset($header_name)) {
03146                 // append continuation line to previous header
03147                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
03148             }
03149         }
03150       }
03151 
03152         $this->response_status_line = $header_array[0];
03153         $arr = explode(' ', $this->response_status_line, 3);
03154         $http_version = $arr[0];
03155         $http_status = intval($arr[1]);
03156         $http_reason = count($arr) > 2 ? $arr[2] : '';
03157 
03158         // see if we need to resend the request with http digest authentication
03159         if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
03160             $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
03161             $this->setURL($this->incoming_headers['location']);
03162             $this->tryagain = true;
03163             return false;
03164         }
03165 
03166         // see if we need to resend the request with http digest authentication
03167         if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
03168             $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
03169             if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
03170                 $this->debug('Server wants digest authentication');
03171                 // remove "Digest " from our elements
03172                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
03173                 
03174                 // parse elements into array
03175                 $digestElements = explode(',', $digestString);
03176                 foreach ($digestElements as $val) {
03177                     $tempElement = explode('=', trim($val), 2);
03178                     $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
03179                 }
03180 
03181                 // should have (at least) qop, realm, nonce
03182                 if (isset($digestRequest['nonce'])) {
03183                     $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
03184                     $this->tryagain = true;
03185                     return false;
03186                 }
03187             }
03188             $this->debug('HTTP authentication failed');
03189             $this->setError('HTTP authentication failed');
03190             return false;
03191         }
03192         
03193         if (
03194             ($http_status >= 300 && $http_status <= 307) ||
03195             ($http_status >= 400 && $http_status <= 417) ||
03196             ($http_status >= 501 && $http_status <= 505)
03197            ) {
03198             $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
03199             return false;
03200         }
03201 
03202         // decode content-encoding
03203         if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
03204             if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
03205                 // if decoding works, use it. else assume data wasn't gzencoded
03206                 if(function_exists('gzinflate')){
03207                     //$timer->setMarker('starting decoding of gzip/deflated content');
03208                     // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
03209                     // this means there are no Zlib headers, although there should be
03210                     $this->debug('The gzinflate function exists');
03211                     $datalen = strlen($data);
03212                     if ($this->incoming_headers['content-encoding'] == 'deflate') {
03213                         if ($degzdata = @gzinflate($data)) {
03214                             $data = $degzdata;
03215                             $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
03216                             if (strlen($data) < $datalen) {
03217                                 // test for the case that the payload has been compressed twice
03218                                 $this->debug('The inflated payload is smaller than the gzipped one; try again');
03219                                 if ($degzdata = @gzinflate($data)) {
03220                                     $data = $degzdata;
03221                                     $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
03222                                 }
03223                             }
03224                         } else {
03225                             $this->debug('Error using gzinflate to inflate the payload');
03226                             $this->setError('Error using gzinflate to inflate the payload');
03227                         }
03228                     } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
03229                         if ($degzdata = @gzinflate(substr($data, 10))) {    // do our best
03230                             $data = $degzdata;
03231                             $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
03232                             if (strlen($data) < $datalen) {
03233                                 // test for the case that the payload has been compressed twice
03234                                 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
03235                                 if ($degzdata = @gzinflate(substr($data, 10))) {
03236                                     $data = $degzdata;
03237                                     $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
03238                                 }
03239                             }
03240                         } else {
03241                             $this->debug('Error using gzinflate to un-gzip the payload');
03242                             $this->setError('Error using gzinflate to un-gzip the payload');
03243                         }
03244                     }
03245                     //$timer->setMarker('finished decoding of gzip/deflated content');
03246                     //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
03247                     // set decoded payload
03248                     $this->incoming_payload = $header_data.$lb.$lb.$data;
03249                 } else {
03250                     $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
03251                     $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
03252                 }
03253             } else {
03254                 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
03255                 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
03256             }
03257         } else {
03258             $this->debug('No Content-Encoding header');
03259         }
03260         
03261         if(strlen($data) == 0){
03262             $this->debug('no data after headers!');
03263             $this->setError('no data present after HTTP headers');
03264             return false;
03265         }
03266         
03267         return $data;
03268     }
03269 
03277     function setContentType($type, $charset = false) {
03278         $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
03279     }
03280 
03287     function usePersistentConnection(){
03288         if (isset($this->outgoing_headers['Accept-Encoding'])) {
03289             return false;
03290         }
03291         $this->protocol_version = '1.1';
03292         $this->persistentConnection = true;
03293         $this->setHeader('Connection', 'Keep-Alive');
03294         return true;
03295     }
03296 
03304     /*
03305      * TODO: allow a Set-Cookie string to be parsed into multiple cookies
03306      */
03307     function parseCookie($cookie_str) {
03308         $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
03309         $data = split(';', $cookie_str);
03310         $value_str = $data[0];
03311 
03312         $cookie_param = 'domain=';
03313         $start = strpos($cookie_str, $cookie_param);
03314         if ($start > 0) {
03315             $domain = substr($cookie_str, $start + strlen($cookie_param));
03316             $domain = substr($domain, 0, strpos($domain, ';'));
03317         } else {
03318             $domain = '';
03319         }
03320 
03321         $cookie_param = 'expires=';
03322         $start = strpos($cookie_str, $cookie_param);
03323         if ($start > 0) {
03324             $expires = substr($cookie_str, $start + strlen($cookie_param));
03325             $expires = substr($expires, 0, strpos($expires, ';'));
03326         } else {
03327             $expires = '';
03328         }
03329 
03330         $cookie_param = 'path=';
03331         $start = strpos($cookie_str, $cookie_param);
03332         if ( $start > 0 ) {
03333             $path = substr($cookie_str, $start + strlen($cookie_param));
03334             $path = substr($path, 0, strpos($path, ';'));
03335         } else {
03336             $path = '/';
03337         }
03338                         
03339         $cookie_param = ';secure;';
03340         if (strpos($cookie_str, $cookie_param) !== FALSE) {
03341             $secure = true;
03342         } else {
03343             $secure = false;
03344         }
03345 
03346         $sep_pos = strpos($value_str, '=');
03347 
03348         if ($sep_pos) {
03349             $name = substr($value_str, 0, $sep_pos);
03350             $value = substr($value_str, $sep_pos + 1);
03351             $cookie= array( 'name' => $name,
03352                             'value' => $value,
03353                             'domain' => $domain,
03354                             'path' => $path,
03355                             'expires' => $expires,
03356                             'secure' => $secure
03357                             );      
03358             return $cookie;
03359         }
03360         return false;
03361     }
03362   
03371     function getCookiesForRequest($cookies, $secure=false) {
03372         $cookie_str = '';
03373         if ((! is_null($cookies)) && (is_array($cookies))) {
03374             foreach ($cookies as $cookie) {
03375                 if (! is_array($cookie)) {
03376                     continue;
03377                 }
03378                 $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
03379                 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
03380                     if (strtotime($cookie['expires']) <= time()) {
03381                         $this->debug('cookie has expired');
03382                         continue;
03383                     }
03384                 }
03385                 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
03386                     $domain = preg_quote($cookie['domain']);
03387                     if (! preg_match("'.*$domain$'i", $this->host)) {
03388                         $this->debug('cookie has different domain');
03389                         continue;
03390                     }
03391                 }
03392                 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
03393                     $path = preg_quote($cookie['path']);
03394                     if (! preg_match("'^$path.*'i", $this->path)) {
03395                         $this->debug('cookie is for a different path');
03396                         continue;
03397                     }
03398                 }
03399                 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
03400                     $this->debug('cookie is secure, transport is not');
03401                     continue;
03402                 }
03403                 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
03404                 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
03405             }
03406         }
03407         return $cookie_str;
03408   }
03409 }
03410 
03411 ?><?php
03412 
03413 
03414 
03425 class nusoap_server extends nusoap_base {
03431     var $headers = array();
03437     var $request = '';
03443     var $requestHeaders = '';
03449     var $requestHeader = NULL;
03455     var $document = '';
03461     var $requestSOAP = '';
03467     var $methodURI = '';
03473     var $methodname = '';
03479     var $methodparams = array();
03485     var $SOAPAction = '';
03491     var $xml_encoding = '';
03497     var $decode_utf8 = true;
03498 
03504     var $outgoing_headers = array();
03510     var $response = '';
03516     var $responseHeaders = '';
03522     var $responseSOAP = '';
03528     var $methodreturn = false;
03534     var $methodreturnisliteralxml = false;
03540     var $fault = false;
03546     var $result = 'successful';
03547 
03554     var $operations = array();
03560     var $wsdl = false;
03566     var $externalWSDLURL = false;
03572     var $debug_flag = false;
03573 
03574 
03582     function nusoap_server($wsdl=false){
03583         parent::nusoap_base();
03584         // turn on debugging?
03585         global $debug;
03586         global $HTTP_SERVER_VARS;
03587 
03588         if (isset($_SERVER)) {
03589             $this->debug("_SERVER is defined:");
03590             $this->appendDebug($this->varDump($_SERVER));
03591         } elseif (isset($HTTP_SERVER_VARS)) {
03592             $this->debug("HTTP_SERVER_VARS is defined:");
03593             $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
03594         } else {
03595             $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
03596         }
03597 
03598         if (isset($debug)) {
03599             $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
03600             $this->debug_flag = $debug;
03601         } elseif (isset($_SERVER['QUERY_STRING'])) {
03602             $qs = explode('&', $_SERVER['QUERY_STRING']);
03603             foreach ($qs as $v) {
03604                 if (substr($v, 0, 6) == 'debug=') {
03605                     $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
03606                     $this->debug_flag = substr($v, 6);
03607                 }
03608             }
03609         } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
03610             $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
03611             foreach ($qs as $v) {
03612                 if (substr($v, 0, 6) == 'debug=') {
03613                     $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
03614                     $this->debug_flag = substr($v, 6);
03615                 }
03616             }
03617         }
03618 
03619         // wsdl
03620         if($wsdl){
03621             $this->debug("In nusoap_server, WSDL is specified");
03622             if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
03623                 $this->wsdl = $wsdl;
03624                 $this->externalWSDLURL = $this->wsdl->wsdl;
03625                 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
03626             } else {
03627                 $this->debug('Create wsdl from ' . $wsdl);
03628                 $this->wsdl = new wsdl($wsdl);
03629                 $this->externalWSDLURL = $wsdl;
03630             }
03631             $this->appendDebug($this->wsdl->getDebug());
03632             $this->wsdl->clearDebug();
03633             if($err = $this->wsdl->getError()){
03634                 die('WSDL ERROR: '.$err);
03635             }
03636         }
03637     }
03638 
03645     function service($data){
03646         global $HTTP_SERVER_VARS;
03647 
03648         if (isset($_SERVER['QUERY_STRING'])) {
03649             $qs = $_SERVER['QUERY_STRING'];
03650         } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
03651             $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
03652         } else {
03653             $qs = '';
03654         }
03655         $this->debug("In service, query string=$qs");
03656 
03657         if (ereg('wsdl', $qs) ){
03658             $this->debug("In service, this is a request for WSDL");
03659             if($this->externalWSDLURL){
03660               if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
03661                 header('Location: '.$this->externalWSDLURL);
03662               } else { // assume file
03663                 header("Content-Type: text/xml\r\n");
03664                 $fp = fopen($this->externalWSDLURL, 'r');
03665                 fpassthru($fp);
03666               }
03667             } elseif ($this->wsdl) {
03668                 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
03669                 print $this->wsdl->serialize($this->debug_flag);
03670                 if ($this->debug_flag) {
03671                     $this->debug('wsdl:');
03672                     $this->appendDebug($this->varDump($this->wsdl));
03673                     print $this->getDebugAsXMLComment();
03674                 }
03675             } else {
03676                 header("Content-Type: text/html; charset=ISO-8859-1\r\n");
03677                 print "This service does not provide WSDL";
03678             }
03679         } elseif ($data == '' && $this->wsdl) {
03680             $this->debug("In service, there is no data, so return Web description");
03681             print $this->wsdl->webDescription();
03682         } else {
03683             $this->debug("In service, invoke the request");
03684             $this->parse_request($data);
03685             if (! $this->fault) {
03686                 $this->invoke_method();
03687             }
03688             if (! $this->fault) {
03689                 $this->serialize_return();
03690             }
03691             $this->send_response();
03692         }
03693     }
03694 
03707     function parse_http_headers() {
03708         global $HTTP_SERVER_VARS;
03709 
03710         $this->request = '';
03711         $this->SOAPAction = '';
03712         if(function_exists('getallheaders')){
03713             $this->debug("In parse_http_headers, use getallheaders");
03714             $headers = getallheaders();
03715             foreach($headers as $k=>$v){
03716                 $k = strtolower($k);
03717                 $this->headers[$k] = $v;
03718                 $this->request .= "$k: $v\r\n";
03719                 $this->debug("$k: $v");
03720             }
03721             // get SOAPAction header
03722             if(isset($this->headers['soapaction'])){
03723                 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
03724             }
03725             // get the character encoding of the incoming request
03726             if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
03727                 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
03728                 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
03729                     $this->xml_encoding = strtoupper($enc);
03730                 } else {
03731                     $this->xml_encoding = 'US-ASCII';
03732                 }
03733             } else {
03734                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
03735                 $this->xml_encoding = 'ISO-8859-1';
03736             }
03737         } elseif(isset($_SERVER) && is_array($_SERVER)){
03738             $this->debug("In parse_http_headers, use _SERVER");
03739             foreach ($_SERVER as $k => $v) {
03740                 if (substr($k, 0, 5) == 'HTTP_') {
03741                     $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
03742                 } else {
03743                     $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
03744                 }
03745                 if ($k == 'soapaction') {
03746                     // get SOAPAction header
03747                     $k = 'SOAPAction';
03748                     $v = str_replace('"', '', $v);
03749                     $v = str_replace('\\', '', $v);
03750                     $this->SOAPAction = $v;
03751                 } else if ($k == 'content-type') {
03752                     // get the character encoding of the incoming request
03753                     if (strpos($v, '=')) {
03754                         $enc = substr(strstr($v, '='), 1);
03755                         $enc = str_replace('"', '', $enc);
03756                         $enc = str_replace('\\', '', $enc);
03757                         if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
03758                             $this->xml_encoding = strtoupper($enc);
03759                         } else {
03760                             $this->xml_encoding = 'US-ASCII';
03761                         }
03762                     } else {
03763                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
03764                         $this->xml_encoding = 'ISO-8859-1';
03765                     }
03766                 }
03767                 $this->headers[$k] = $v;
03768                 $this->request .= "$k: $v\r\n";
03769                 $this->debug("$k: $v");
03770             }
03771         } elseif (is_array($HTTP_SERVER_VARS)) {
03772             $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
03773             foreach ($HTTP_SERVER_VARS as $k => $v) {
03774                 if (substr($k, 0, 5) == 'HTTP_') {
03775                     $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                            $k = strtolower(substr($k, 5));
03776                 } else {
03777                     $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                           $k = strtolower($k);
03778                 }
03779                 if ($k == 'soapaction') {
03780                     // get SOAPAction header
03781                     $k = 'SOAPAction';
03782                     $v = str_replace('"', '', $v);
03783                     $v = str_replace('\\', '', $v);
03784                     $this->SOAPAction = $v;
03785                 } else if ($k == 'content-type') {
03786                     // get the character encoding of the incoming request
03787                     if (strpos($v, '=')) {
03788                         $enc = substr(strstr($v, '='), 1);
03789                         $enc = str_replace('"', '', $enc);
03790                         $enc = str_replace('\\', '', $enc);
03791                         if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
03792                             $this->xml_encoding = strtoupper($enc);
03793                         } else {
03794                             $this->xml_encoding = 'US-ASCII';
03795                         }
03796                     } else {
03797                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
03798                         $this->xml_encoding = 'ISO-8859-1';
03799                     }
03800                 }
03801                 $this->headers[$k] = $v;
03802                 $this->request .= "$k: $v\r\n";
03803                 $this->debug("$k: $v");
03804             }
03805         } else {
03806             $this->debug("In parse_http_headers, HTTP headers not accessible");
03807             $this->setError("HTTP headers not accessible");
03808         }
03809     }
03810 
03833     function parse_request($data='') {
03834         $this->debug('entering parse_request()');
03835         $this->parse_http_headers();
03836         $this->debug('got character encoding: '.$this->xml_encoding);
03837         // uncompress if necessary
03838         if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
03839             $this->debug('got content encoding: ' . $this->headers['content-encoding']);
03840             if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
03841                 // if decoding works, use it. else assume data wasn't gzencoded
03842                 if (function_exists('gzuncompress')) {
03843                     if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
03844                         $data = $degzdata;
03845                     } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
03846                         $data = $degzdata;
03847                     } else {
03848                         $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
03849                         return;
03850                     }
03851                 } else {
03852                     $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
03853                     return;
03854                 }
03855             }
03856         }
03857         $this->request .= "\r\n".$data;
03858         $data = $this->parseRequest($this->headers, $data);
03859         $this->requestSOAP = $data;
03860         $this->debug('leaving parse_request');
03861     }
03862 
03880     function invoke_method() {
03881         $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
03882 
03883         if ($this->wsdl) {
03884             if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
03885                 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
03886                 $this->appendDebug('opData=' . $this->varDump($this->opData));
03887             } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
03888                 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
03889                 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
03890                 $this->appendDebug('opData=' . $this->varDump($this->opData));
03891                 $this->methodname = $this->opData['name'];
03892             } else {
03893                 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
03894                 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
03895                 return;
03896             }
03897         } else {
03898             $this->debug('in invoke_method, no WSDL to validate method');
03899         }
03900 
03901         // if a . is present in $this->methodname, we see if there is a class in scope,
03902         // which could be referred to. We will also distinguish between two deliminators,
03903         // to allow methods to be called a the class or an instance
03904         $class = '';
03905         $method = '';
03906         if (strpos($this->methodname, '..') > 0) {
03907             $delim = '..';
03908         } else if (strpos($this->methodname, '.') > 0) {
03909             $delim = '.';
03910         } else {
03911             $delim = '';
03912         }
03913 
03914         if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 &&
03915             class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) {
03916             // get the class and method name
03917             $class = substr($this->methodname, 0, strpos($this->methodname, $delim));
03918             $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
03919             $this->debug("in invoke_method, class=$class method=$method delim=$delim");
03920         }
03921 
03922         // does method exist?
03923         if ($class == '') {
03924             if (!function_exists($this->methodname)) {
03925                 $this->debug("in invoke_method, function '$this->methodname' not found!");
03926                 $this->result = 'fault: method not found';
03927                 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
03928                 return;
03929             }
03930         } else {
03931             $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
03932             if (!in_array($method_to_compare, get_class_methods($class))) {
03933                 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
03934                 $this->result = 'fault: method not found';
03935                 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service");
03936                 return;
03937             }
03938         }
03939 
03940         // evaluate message, getting back parameters
03941         // verify that request parameters match the method's signature
03942         if(! $this->verify_method($this->methodname,$this->methodparams)){
03943             // debug
03944             $this->debug('ERROR: request not verified against method signature');
03945             $this->result = 'fault: request failed validation against method signature';
03946             // return fault
03947             $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
03948             return;
03949         }
03950 
03951         // if there are parameters to pass
03952         $this->debug('in invoke_method, params:');
03953         $this->appendDebug($this->varDump($this->methodparams));
03954         $this->debug("in invoke_method, calling '$this->methodname'");
03955         if (!function_exists('call_user_func_array')) {
03956             if ($class == '') {
03957                 $this->debug('in invoke_method, calling function using eval()');
03958                 $funcCall = "\$this->methodreturn = $this->methodname(";
03959             } else {
03960                 if ($delim == '..') {
03961                     $this->debug('in invoke_method, calling class method using eval()');
03962                     $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
03963                 } else {
03964                     $this->debug('in invoke_method, calling instance method using eval()');
03965                     // generate unique instance name
03966                     $instname = "\$inst_".time();
03967                     $funcCall = $instname." = new ".$class."(); ";
03968                     $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
03969                 }
03970             }
03971             if ($this->methodparams) {
03972                 foreach ($this->methodparams as $param) {
03973                     if (is_array($param) || is_object($param)) {
03974                         $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
03975                         return;
03976                     }
03977                     $funcCall .= "\"$param\",";
03978                 }
03979                 $funcCall = substr($funcCall, 0, -1);
03980             }
03981             $funcCall .= ');';
03982             $this->debug('in invoke_method, function call: '.$funcCall);
03983             @eval($funcCall);
03984         } else {
03985             if ($class == '') {
03986                 $this->debug('in invoke_method, calling function using call_user_func_array()');
03987                 $call_arg = "$this->methodname";    // straight assignment changes $this->methodname to lower case after call_user_func_array()
03988             } elseif ($delim == '..') {
03989                 $this->debug('in invoke_method, calling class method using call_user_func_array()');
03990                 $call_arg = array ($class, $method);
03991             } else {
03992                 $this->debug('in invoke_method, calling instance method using call_user_func_array()');
03993                 $instance = new $class ();
03994                 $call_arg = array(&$instance, $method);
03995             }
03996             if (is_array($this->methodparams)) {
03997                 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
03998             } else {
03999                 $this->methodreturn = call_user_func_array($call_arg, array());
04000             }
04001         }
04002         $this->debug('in invoke_method, methodreturn:');
04003         $this->appendDebug($this->varDump($this->methodreturn));
04004         $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
04005     }
04006 
04018     function serialize_return() {
04019         $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
04020         // if fault
04021         if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
04022             $this->debug('got a fault object from method');
04023             $this->fault = $this->methodreturn;
04024             return;
04025         } elseif ($this->methodreturnisliteralxml) {
04026             $return_val = $this->methodreturn;
04027         // returned value(s)
04028         } else {
04029             $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
04030             $this->debug('serializing return value');
04031             if($this->wsdl){
04032                 if (sizeof($this->opData['output']['parts']) > 1) {
04033                     $this->debug('more than one output part, so use the method return unchanged');
04034                     $opParams = $this->methodreturn;
04035                 } elseif (sizeof($this->opData['output']['parts']) == 1) {
04036                     $this->debug('exactly one output part, so wrap the method return in a simple array');
04037                     // TODO: verify that it is not already wrapped!
04038                     //foreach ($this->opData['output']['parts'] as $name => $type) {
04039                     //  $this->debug('wrap in element named ' . $name);
04040                     //}
04041                     $opParams = array($this->methodreturn);
04042                 }
04043                 $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
04044                 $this->appendDebug($this->wsdl->getDebug());
04045                 $this->wsdl->clearDebug();
04046                 if($errstr = $this->wsdl->getError()){
04047                     $this->debug('got wsdl error: '.$errstr);
04048                     $this->fault('SOAP-ENV:Server', 'unable to serialize result');
04049                     return;
04050                 }
04051             } else {
04052                 if (isset($this->methodreturn)) {
04053                     $return_val = $this->serialize_val($this->methodreturn, 'return');
04054                 } else {
04055                     $return_val = '';
04056                     $this->debug('in absence of WSDL, assume void return for backward compatibility');
04057                 }
04058             }
04059         }
04060         $this->debug('return value:');
04061         $this->appendDebug($this->varDump($return_val));
04062 
04063         $this->debug('serializing response');
04064         if ($this->wsdl) {
04065             $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
04066             if ($this->opData['style'] == 'rpc') {
04067                 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
04068                 if ($this->opData['output']['use'] == 'literal') {
04069                     // 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
04070                     $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
04071                 } else {
04072                     $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
04073                 }
04074             } else {
04075                 $this->debug('style is not rpc for serialization: assume document');
04076                 $payload = $return_val;
04077             }
04078         } else {
04079             $this->debug('do not have WSDL for serialization: assume rpc/encoded');
04080             $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
04081         }
04082         $this->result = 'successful';
04083         if($this->wsdl){
04084             //if($this->debug_flag){
04085                 $this->appendDebug($this->wsdl->getDebug());
04086             //  }
04087             if (isset($opData['output']['encodingStyle'])) {
04088                 $encodingStyle = $opData['output']['encodingStyle'];
04089             } else {
04090                 $encodingStyle = '';
04091             }
04092             // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
04093             $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
04094         } else {
04095             $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
04096         }
04097         $this->debug("Leaving serialize_return");
04098     }
04099 
04110     function send_response() {
04111         $this->debug('Enter send_response');
04112         if ($this->fault) {
04113             $payload = $this->fault->serialize();
04114             $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
04115             $this->outgoing_headers[] = "Status: 500 Internal Server Error";
04116         } else {
04117             $payload = $this->responseSOAP;
04118             // Some combinations of PHP+Web server allow the Status
04119             // to come through as a header.  Since OK is the default
04120             // just do nothing.
04121             // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
04122             // $this->outgoing_headers[] = "Status: 200 OK";
04123         }
04124         // add debug data if in debug mode
04125         if(isset($this->debug_flag) && $this->debug_flag){
04126             $payload .= $this->getDebugAsXMLComment();
04127         }
04128         $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
04129         ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
04130         $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
04131         // Let the Web server decide about this
04132         //$this->outgoing_headers[] = "Connection: Close\r\n";
04133         $payload = $this->getHTTPBody($payload);
04134         $type = $this->getHTTPContentType();
04135         $charset = $this->getHTTPContentTypeCharset();
04136         $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
04137         //begin code to compress payload - by John
04138         // NOTE: there is no way to know whether the Web server will also compress
04139         // this data.
04140         if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { 
04141             if (strstr($this->headers['accept-encoding'], 'gzip')) {
04142                 if (function_exists('gzencode')) {
04143                     if (isset($this->debug_flag) && $this->debug_flag) {
04144                         $payload .= "<!-- Content being gzipped -->";
04145                     }
04146                     $this->outgoing_headers[] = "Content-Encoding: gzip";
04147                     $payload = gzencode($payload);
04148                 } else {
04149                     if (isset($this->debug_flag) && $this->debug_flag) {
04150                         $payload .= "<!-- Content will not be gzipped: no gzencode -->";
04151                     }
04152                 }
04153             } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
04154                 // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
04155                 // instead of gzcompress output,
04156                 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
04157                 if (function_exists('gzdeflate')) {
04158                     if (isset($this->debug_flag) && $this->debug_flag) {
04159                         $payload .= "<!-- Content being deflated -->";
04160                     }
04161                     $this->outgoing_headers[] = "Content-Encoding: deflate";
04162                     $payload = gzdeflate($payload);
04163                 } else {
04164                     if (isset($this->debug_flag) && $this->debug_flag) {
04165                         $payload .= "<!-- Content will not be deflated: no gzcompress -->";
04166                     }
04167                 }
04168             }
04169         }
04170         //end code
04171         $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
04172         reset($this->outgoing_headers);
04173         foreach($this->outgoing_headers as $hdr){
04174             header($hdr, false);
04175         }
04176         print $payload;
04177         $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
04178     }
04179 
04189     function verify_method($operation,$request){
04190         if(isset($this->wsdl) && is_object($this->wsdl)){
04191             if($this->wsdl->getOperationData($operation)){
04192                 return true;
04193             }
04194         } elseif(isset($this->operations[$operation])){
04195             return true;
04196         }
04197         return false;
04198     }
04199 
04208     function parseRequest($headers, $data) {
04209         $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
04210         if (!strstr($headers['content-type'], 'text/xml')) {
04211             $this->setError('Request not of type text/xml');
04212             return false;
04213         }
04214         if (strpos($headers['content-type'], '=')) {
04215             $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
04216             $this->debug('Got response encoding: ' . $enc);
04217             if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
04218                 $this->xml_encoding = strtoupper($enc);
04219             } else {
04220                 $this->xml_encoding = 'US-ASCII';
04221             }
04222         } else {
04223             // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
04224             $this->xml_encoding = 'ISO-8859-1';
04225         }
04226         $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
04227         // parse response, get soap parser obj
04228         $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
04229         // parser debug
04230         $this->debug("parser debug: \n".$parser->getDebug());
04231         // if fault occurred during message parsing
04232         if($err = $parser->getError()){
04233             $this->result = 'fault: error in msg parsing: '.$err;
04234             $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
04235         // else successfully parsed request into soapval object
04236         } else {
04237             // get/set methodname
04238             $this->methodURI = $parser->root_struct_namespace;
04239             $this->methodname = $parser->root_struct_name;
04240             $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
04241             $this->debug('calling parser->get_soapbody()');
04242             $this->methodparams = $parser->get_soapbody();
04243             // get SOAP headers
04244             $this->requestHeaders = $parser->getHeaders();
04245             // get SOAP Header
04246             $this->requestHeader = $parser->get_soapheader();
04247             // add document for doclit support
04248             $this->document = $parser->document;
04249         }
04250      }
04251 
04259     function getHTTPBody($soapmsg) {
04260         return $soapmsg;
04261     }
04262     
04271     function getHTTPContentType() {
04272         return 'text/xml';
04273     }
04274     
04284     function getHTTPContentTypeCharset() {
04285         return $this->soap_defencoding;
04286     }
04287 
04297     function add_to_map($methodname,$in,$out){
04298             $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
04299     }
04300 
04315     function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
04316         global $HTTP_SERVER_VARS;
04317 
04318         if($this->externalWSDLURL){
04319             die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
04320         }
04321         if (! $name) {
04322             die('You must specify a name when you register an operation');
04323         }
04324         if (!is_array($in)) {
04325             die('You must provide an array for operation inputs');
04326         }
04327         if (!is_array($out)) {
04328             die('You must provide an array for operation outputs');
04329         }
04330         if(false == $namespace) {
04331         }
04332         if(false == $soapaction) {
04333             if (isset($_SERVER)) {
04334                 $SERVER_NAME = $_SERVER['SERVER_NAME'];
04335                 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
04336                 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
04337             } elseif (isset($HTTP_SERVER_VARS)) {
04338                 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
04339                 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
04340                 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
04341             } else {
04342                 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
04343             }
04344             if ($HTTPS == '1' || $HTTPS == 'on') {
04345                 $SCHEME = 'https';
04346             } else {
04347                 $SCHEME = 'http';
04348             }
04349             $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
04350         }
04351         if(false == $style) {
04352             $style = "rpc";
04353         }
04354         if(false == $use) {
04355             $use = "encoded";
04356         }
04357         if ($use == 'encoded' && $encodingStyle = '') {
04358             $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
04359         }
04360 
04361         $this->operations[$name] = array(
04362         'name' => $name,
04363         'in' => $in,
04364         'out' => $out,
04365         'namespace' => $namespace,
04366         'soapaction' => $soapaction,
04367         'style' => $style);
04368         if($this->wsdl){
04369             $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
04370         }
04371         return true;
04372     }
04373 
04384     function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
04385         if ($faultdetail == '' && $this->debug_flag) {
04386             $faultdetail = $this->getDebug();
04387         }
04388         $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
04389         $this->fault->soap_defencoding = $this->soap_defencoding;
04390     }
04391 
04403     function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
04404     {
04405         global $HTTP_SERVER_VARS;
04406 
04407         if (isset($_SERVER)) {
04408             $SERVER_NAME = $_SERVER['SERVER_NAME'];
04409             $SERVER_PORT = $_SERVER['SERVER_PORT'];
04410             $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
04411             $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
04412         } elseif (isset($HTTP_SERVER_VARS)) {
04413             $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
04414             $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
04415             $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
04416             $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
04417         } else {
04418             $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
04419         }
04420         // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
04421         $colon = strpos($SERVER_NAME,":");
04422         if ($colon) {
04423             $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
04424         }
04425         if ($SERVER_PORT == 80) {
04426             $SERVER_PORT = '';
04427         } else {
04428             $SERVER_PORT = ':' . $SERVER_PORT;
04429         }
04430         if(false == $namespace) {
04431             $namespace = "http://$SERVER_NAME/soap/$serviceName";
04432         }
04433         
04434         if(false == $endpoint) {
04435             if ($HTTPS == '1' || $HTTPS == 'on') {
04436                 $SCHEME = 'https';
04437             } else {
04438                 $SCHEME = 'http';
04439             }
04440             $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
04441         }
04442         
04443         if(false == $schemaTargetNamespace) {
04444             $schemaTargetNamespace = $namespace;
04445         }
04446         
04447         $this->wsdl = new wsdl;
04448         $this->wsdl->serviceName = $serviceName;
04449         $this->wsdl->endpoint = $endpoint;
04450         $this->wsdl->namespaces['tns'] = $namespace;
04451         $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
04452         $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
04453         if ($schemaTargetNamespace != $namespace) {
04454             $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
04455         }
04456         $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
04457         if ($style == 'document') {
04458             $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
04459         }
04460         $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
04461         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
04462         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
04463         $this->wsdl->bindings[$serviceName.'Binding'] = array(
04464             'name'=>$serviceName.'Binding',
04465             'style'=>$style,
04466             'transport'=>$transport,
04467             'portType'=>$serviceName.'PortType');
04468         $this->wsdl->ports[$serviceName.'Port'] = array(
04469             'binding'=>$serviceName.'Binding',
04470             'location'=>$endpoint,
04471             'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
04472     }
04473 }
04474 
04478 class soap_server extends nusoap_server {
04479 }
04480 
04481 ?><?php
04482 
04483 
04484 
04494 class wsdl extends nusoap_base {
04495     // URL or filename of the root of this WSDL
04496     var $wsdl; 
04497     // define internal arrays of bindings, ports, operations, messages, etc.
04498     var $schemas = array();
04499     var $currentSchema;
04500     var $message = array();
04501     var $complexTypes = array();
04502     var $messages = array();
04503     var $currentMessage;
04504     var $currentOperation;
04505     var $portTypes = array();
04506     var $currentPortType;
04507     var $bindings = array();
04508     var $currentBinding;
04509     var $ports = array();
04510     var $currentPort;
04511     var $opData = array();
04512     var $status = '';
04513     var $documentation = false;
04514     var $endpoint = ''; 
04515     // array of wsdl docs to import
04516     var $import = array(); 
04517     // parser vars
04518     var $parser;
04519     var $position = 0;
04520     var $depth = 0;
04521     var $depth_array = array();
04522     // for getting wsdl
04523     var $proxyhost = '';
04524     var $proxyport = '';
04525     var $proxyusername = '';
04526     var $proxypassword = '';
04527     var $timeout = 0;
04528     var $response_timeout = 30;
04529     var $curl_options = array();    // User-specified cURL options
04530     var $use_curl = false;          // whether to always try to use cURL
04531     // for HTTP authentication
04532     var $username = '';             // Username for HTTP authentication
04533     var $password = '';             // Password for HTTP authentication
04534     var $authtype = '';             // Type of HTTP authentication
04535     var $certRequest = array();     // Certificate for HTTP SSL authentication
04536 
04551     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
04552         parent::nusoap_base();
04553         $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
04554         $this->proxyhost = $proxyhost;
04555         $this->proxyport = $proxyport;
04556         $this->proxyusername = $proxyusername;
04557         $this->proxypassword = $proxypassword;
04558         $this->timeout = $timeout;
04559         $this->response_timeout = $response_timeout;
04560         if (is_array($curl_options))
04561             $this->curl_options = $curl_options;
04562         $this->use_curl = $use_curl;
04563         $this->fetchWSDL($wsdl);
04564     }
04565 
04571     function fetchWSDL($wsdl) {
04572         $this->debug("parse and process WSDL path=$wsdl");
04573         $this->wsdl = $wsdl;
04574         // parse wsdl file
04575         if ($this->wsdl != "") {
04576             $this->parseWSDL($this->wsdl);
04577         }
04578         // imports
04579         // TODO: handle imports more properly, grabbing them in-line and nesting them
04580         $imported_urls = array();
04581         $imported = 1;
04582         while ($imported > 0) {
04583             $imported = 0;
04584             // Schema imports
04585             foreach ($this->schemas as $ns => $list) {
04586                 foreach ($list as $xs) {
04587                     $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
04588                     foreach ($xs->imports as $ns2 => $list2) {
04589                         for ($ii = 0; $ii < count($list2); $ii++) {
04590                             if (! $list2[$ii]['loaded']) {
04591                                 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
04592                                 $url = $list2[$ii]['location'];
04593                                 if ($url != '') {
04594                                     $urlparts = parse_url($url);
04595                                     if (!isset($urlparts['host'])) {
04596                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
04597                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
04598                                     }
04599                                     if (! in_array($url, $imported_urls)) {
04600                                         $this->parseWSDL($url);
04601                                         $imported++;
04602                                         $imported_urls[] = $url;
04603                                     }
04604                                 } else {
04605                                     $this->debug("Unexpected scenario: empty URL for unloaded import");
04606                                 }
04607                             }
04608                         }
04609                     } 
04610                 }
04611             }
04612             // WSDL imports
04613             $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
04614             foreach ($this->import as $ns => $list) {
04615                 for ($ii = 0; $ii < count($list); $ii++) {
04616                     if (! $list[$ii]['loaded']) {
04617                         $this->import[$ns][$ii]['loaded'] = true;
04618                         $url = $list[$ii]['location'];
04619                         if ($url != '') {
04620                             $urlparts = parse_url($url);
04621                             if (!isset($urlparts['host'])) {
04622                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
04623                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
04624                             }
04625                             if (! in_array($url, $imported_urls)) {
04626                                 $this->parseWSDL($url);
04627                                 $imported++;
04628                                 $imported_urls[] = $url;
04629                             }
04630                         } else {
04631                             $this->debug("Unexpected scenario: empty URL for unloaded import");
04632                         }
04633                     }
04634                 }
04635             } 
04636         }
04637         // add new data to operation data
04638         foreach($this->bindings as $binding => $bindingData) {
04639             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
04640                 foreach($bindingData['operations'] as $operation => $data) {
04641                     $this->debug('post-parse data gathering for ' . $operation);
04642                     $this->bindings[$binding]['operations'][$operation]['input'] = 
04643                         isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
04644                         array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
04645                         $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
04646                     $this->bindings[$binding]['operations'][$operation]['output'] = 
04647                         isset($this->bindings[$binding]['operations'][$operation]['output']) ?
04648                         array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
04649                         $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
04650                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
04651                         $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
04652                     }
04653                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
04654                         $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
04655                     }
04656                     // Set operation style if necessary, but do not override one already provided
04657                     if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
04658                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
04659                     }
04660                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
04661                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
04662                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
04663                 } 
04664             } 
04665         }
04666     }
04667 
04674     function parseWSDL($wsdl = '') {
04675         $this->debug("parse WSDL at path=$wsdl");
04676 
04677         if ($wsdl == '') {
04678             $this->debug('no wsdl passed to parseWSDL()!!');
04679             $this->setError('no wsdl passed to parseWSDL()!!');
04680             return false;
04681         }
04682         
04683         // parse $wsdl for url format
04684         $wsdl_props = parse_url($wsdl);
04685 
04686         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
04687             $this->debug('getting WSDL http(s) URL ' . $wsdl);
04688             // get wsdl
04689             $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
04690             $tr->request_method = 'GET';
04691             $tr->useSOAPAction = false;
04692             if($this->proxyhost && $this->proxyport){
04693                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
04694             }
04695             if ($this->authtype != '') {
04696                 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
04697             }
04698             $tr->setEncoding('gzip, deflate');
04699             $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
04700             //$this->debug("WSDL request\n" . $tr->outgoing_payload);
04701             //$this->debug("WSDL response\n" . $tr->incoming_payload);
04702             $this->appendDebug($tr->getDebug());
04703             // catch errors
04704             if($err = $tr->getError() ){
04705                 $errstr = 'HTTP ERROR: '.$err;
04706                 $this->debug($errstr);
04707                 $this->setError($errstr);
04708                 unset($tr);
04709                 return false;
04710             }
04711             unset($tr);
04712             $this->debug("got WSDL URL");
04713         } else {
04714             // $wsdl is not http(s), so treat it as a file URL or plain file path
04715             if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
04716                 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
04717             } else {
04718                 $path = $wsdl;
04719             }
04720             $this->debug('getting WSDL file ' . $path);
04721             if ($fp = @fopen($path, 'r')) {
04722                 $wsdl_string = '';
04723                 while ($data = fread($fp, 32768)) {
04724                     $wsdl_string .= $data;
04725                 } 
04726                 fclose($fp);
04727             } else {
04728                 $errstr = "Bad path to WSDL file $path";
04729                 $this->debug($errstr);
04730                 $this->setError($errstr);
04731                 return false;
04732             } 
04733         }
04734         $this->debug('Parse WSDL');
04735         // end new code added
04736         // Create an XML parser.
04737         $this->parser = xml_parser_create(); 
04738         // Set the options for parsing the XML data.
04739         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
04740         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
04741         // Set the object for the parser.
04742         xml_set_object($this->parser, $this); 
04743         // Set the element handlers for the parser.
04744         xml_set_element_handler($this->parser, 'start_element', 'end_element');
04745         xml_set_character_data_handler($this->parser, 'character_data');
04746         // Parse the XML file.
04747         if (!xml_parse($this->parser, $wsdl_string, true)) {
04748             // Display an error message.
04749             $errstr = sprintf(
04750                 'XML error parsing WSDL from %s on line %d: %s',
04751                 $wsdl,
04752                 xml_get_current_line_number($this->parser),
04753                 xml_error_string(xml_get_error_code($this->parser))
04754                 );
04755             $this->debug($errstr);
04756             $this->debug("XML payload:\n" . $wsdl_string);
04757             $this->setError($errstr);
04758             return false;
04759         } 
04760         // free the parser
04761         xml_parser_free($this->parser);
04762         $this->debug('Parsing WSDL done');
04763         // catch wsdl parse errors
04764         if($this->getError()){
04765             return false;
04766         }
04767         return true;
04768     } 
04769 
04778     function start_element($parser, $name, $attrs)
04779     {
04780         if ($this->status == 'schema') {
04781             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
04782             $this->appendDebug($this->currentSchema->getDebug());
04783             $this->currentSchema->clearDebug();
04784         } elseif (ereg('schema$', $name)) {
04785             $this->debug('Parsing WSDL schema');
04786             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
04787             $this->status = 'schema';
04788             $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
04789             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
04790             $this->appendDebug($this->currentSchema->getDebug());
04791             $this->currentSchema->clearDebug();
04792         } else {
04793             // position in the total number of elements, starting from 0
04794             $pos = $this->position++;
04795             $depth = $this->depth++; 
04796             // set self as current value for this depth
04797             $this->depth_array[$depth] = $pos;
04798             $this->message[$pos] = array('cdata' => ''); 
04799             // process attributes
04800             if (count($attrs) > 0) {
04801                 // register namespace declarations
04802                 foreach($attrs as $k => $v) {
04803                     if (ereg("^xmlns", $k)) {
04804                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
04805                             $this->namespaces[$ns_prefix] = $v;
04806                         } else {
04807                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
04808                         } 
04809                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
04810                             $this->XMLSchemaVersion = $v;
04811                             $this->namespaces['xsi'] = $v . '-instance';
04812                         } 
04813                     }
04814                 }
04815                 // expand each attribute prefix to its namespace
04816                 foreach($attrs as $k => $v) {
04817                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
04818                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
04819                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
04820                     } 
04821                     $eAttrs[$k] = $v;
04822                 } 
04823                 $attrs = $eAttrs;
04824             } else {
04825                 $attrs = array();
04826             } 
04827             // get element prefix, namespace and name
04828             if (ereg(':', $name)) {
04829                 // get ns prefix
04830                 $prefix = substr($name, 0, strpos($name, ':')); 
04831                 // get ns
04832                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 
04833                 // get unqualified name
04834                 $name = substr(strstr($name, ':'), 1);
04835             } 
04836             // process attributes, expanding any prefixes to namespaces
04837             // find status, register data
04838             switch ($this->status) {
04839                 case 'message':
04840                     if ($name == 'part') {
04841                         if (isset($attrs['type'])) {
04842                             $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
04843                             $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
04844                         } 
04845                         if (isset($attrs['element'])) {
04846                             $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
04847                             $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
04848                         } 
04849                     } 
04850                     break;
04851                 case 'portType':
04852                     switch ($name) {
04853                         case 'operation':
04854                             $this->currentPortOperation = $attrs['name'];
04855                             $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
04856                             if (isset($attrs['parameterOrder'])) {
04857                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
04858                             } 
04859                             break;
04860                         case 'documentation':
04861                             $this->documentation = true;
04862                             break; 
04863                         // merge input/output data
04864                         default:
04865                             $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
04866                             $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
04867                             break;
04868                     } 
04869                     break;
04870                 case 'binding':
04871                     switch ($name) {
04872                         case 'binding': 
04873                             // get ns prefix
04874                             if (isset($attrs['style'])) {
04875                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;
04876                             } 
04877                             $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
04878                             break;
04879                         case 'header':
04880                             $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
04881                             break;
04882                         case 'operation':
04883                             if (isset($attrs['soapAction'])) {
04884                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
04885                             } 
04886                             if (isset($attrs['style'])) {
04887                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
04888                             } 
04889                             if (isset($attrs['name'])) {
04890                                 $this->currentOperation = $attrs['name'];
04891                                 $this->debug("current binding operation: $this->currentOperation");
04892                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
04893                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
04894                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
04895                             } 
04896                             break;
04897                         case 'input':
04898                             $this->opStatus = 'input';
04899                             break;
04900                         case 'output':
04901                             $this->opStatus = 'output';
04902                             break;
04903                         case 'body':
04904                             if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
04905                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
04906                             } else {
04907                                 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
04908                             } 
04909                             break;
04910                     } 
04911                     break;
04912                 case 'service':
04913                     switch ($name) {
04914                         case 'port':
04915                             $this->currentPort = $attrs['name'];
04916                             $this->debug('current port: ' . $this->currentPort);
04917                             $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
04918                     
04919                             break;
04920                         case 'address':
04921                             $this->ports[$this->currentPort]['location'] = $attrs['location'];
04922                             $this->ports[$this->currentPort]['bindingType'] = $namespace;
04923                             $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
04924                             $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
04925                             break;
04926                     } 
04927                     break;
04928             } 
04929         // set status
04930         switch ($name) {
04931             case 'import':
04932                 if (isset($attrs['location'])) {
04933                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
04934                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
04935                 } else {
04936                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
04937                     if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
04938                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
04939                     }
04940                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
04941                 }
04942                 break;
04943             //wait for schema
04944             //case 'types':
04945             //  $this->status = 'schema';
04946             //  break;
04947             case 'message':
04948                 $this->status = 'message';
04949                 $this->messages[$attrs['name']] = array();
04950                 $this->currentMessage = $attrs['name'];
04951                 break;
04952             case 'portType':
04953                 $this->status = 'portType';
04954                 $this->portTypes[$attrs['name']] = array();
04955                 $this->currentPortType = $attrs['name'];
04956                 break;
04957             case "binding":
04958                 if (isset($attrs['name'])) {
04959                 // get binding name
04960                     if (strpos($attrs['name'], ':')) {
04961                         $this->currentBinding = $this->getLocalPart($attrs['name']);
04962                     } else {
04963                         $this->currentBinding = $attrs['name'];
04964                     } 
04965                     $this->status = 'binding';
04966                     $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
04967                     $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
04968                 } 
04969                 break;
04970             case 'service':
04971                 $this->serviceName = $attrs['name'];
04972                 $this->status = 'service';
04973                 $this->debug('current service: ' . $this->serviceName);
04974                 break;
04975             case 'definitions':
04976                 foreach ($attrs as $name => $value) {
04977                     $this->wsdl_info[$name] = $value;
04978                 } 
04979                 break;
04980             } 
04981         } 
04982     } 
04983 
04991     function end_element($parser, $name){ 
04992         // unset schema status
04993         if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
04994             $this->status = "";
04995             $this->appendDebug($this->currentSchema->getDebug());
04996             $this->currentSchema->clearDebug();
04997             $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
04998             $this->debug('Parsing WSDL schema done');
04999         } 
05000         if ($this->status == 'schema') {
05001             $this->currentSchema->schemaEndElement($parser, $name);
05002         } else {
05003             // bring depth down a notch
05004             $this->depth--;
05005         } 
05006         // end documentation
05007         if ($this->documentation) {
05008             //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
05009             //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
05010             $this->documentation = false;
05011         } 
05012     } 
05013 
05021     function character_data($parser, $data)
05022     {
05023         $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
05024         if (isset($this->message[$pos]['cdata'])) {
05025             $this->message[$pos]['cdata'] .= $data;
05026         } 
05027         if ($this->documentation) {
05028             $this->documentation .= $data;
05029         } 
05030     } 
05031     
05041     function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
05042         $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
05043         $this->appendDebug($this->varDump($certRequest));
05044         $this->username = $username;
05045         $this->password = $password;
05046         $this->authtype = $authtype;
05047         $this->certRequest = $certRequest;
05048     }
05049     
05050     function getBindingData($binding)
05051     {
05052         if (is_array($this->bindings[$binding])) {
05053             return $this->bindings[$binding];
05054         } 
05055     }
05056     
05064     function getOperations($bindingType = 'soap') {
05065         $ops = array();
05066         if ($bindingType == 'soap') {
05067             $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
05068         } elseif ($bindingType == 'soap12') {
05069             $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
05070         }
05071         // loop thru ports
05072         foreach($this->ports as $port => $portData) {
05073             // binding type of port matches parameter
05074             if ($portData['bindingType'] == $bindingType) {
05075                 //$this->debug("getOperations for port $port");
05076                 //$this->debug("port data: " . $this->varDump($portData));
05077                 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
05078                 // merge bindings
05079                 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
05080                     $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
05081                 }
05082             }
05083         } 
05084         return $ops;
05085     } 
05086     
05095     function getOperationData($operation, $bindingType = 'soap')
05096     {
05097         if ($bindingType == 'soap') {
05098             $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
05099         } elseif ($bindingType == 'soap12') {
05100             $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
05101         }
05102         // loop thru ports
05103         foreach($this->ports as $port => $portData) {
05104             // binding type of port matches parameter
05105             if ($portData['bindingType'] == $bindingType) {
05106                 // get binding
05107                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
05108                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
05109                     // note that we could/should also check the namespace here
05110                     if ($operation == $bOperation) {
05111                         $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
05112                         return $opData;
05113                     } 
05114                 } 
05115             }
05116         } 
05117     }
05118     
05127     function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
05128         if ($bindingType == 'soap') {
05129             $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
05130         } elseif ($bindingType == 'soap12') {
05131             $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
05132         }
05133         // loop thru ports
05134         foreach($this->ports as $port => $portData) {
05135             // binding type of port matches parameter
05136             if ($portData['bindingType'] == $bindingType) {
05137                 // loop through operations for the binding
05138                 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
05139                     if ($opData['soapAction'] == $soapAction) {
05140                         return $opData;
05141                     } 
05142                 } 
05143             }
05144         } 
05145     }
05146     
05165     function getTypeDef($type, $ns) {
05166         $this->debug("in getTypeDef: type=$type, ns=$ns");
05167         if ((! $ns) && isset($this->namespaces['tns'])) {
05168             $ns = $this->namespaces['tns'];
05169             $this->debug("in getTypeDef: type namespace forced to $ns");
05170         }
05171         if (!isset($this->schemas[$ns])) {
05172             foreach ($this->schemas as $ns0 => $schema0) {
05173                 if (strcasecmp($ns, $ns0) == 0) {
05174                     $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
05175                     $ns = $ns0;
05176                     break;
05177                 }
05178             }
05179         }
05180         if (isset($this->schemas[$ns])) {
05181             $this->debug("in getTypeDef: have schema for namespace $ns");
05182             for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
05183                 $xs = &$this->schemas[$ns][$i];
05184                 $t = $xs->getTypeDef($type);
05185                 //$this->appendDebug($xs->getDebug());
05186                 //$xs->clearDebug();
05187                 if ($t) {
05188                     if (!isset($t['phpType'])) {
05189                         // get info for type to tack onto the element
05190                         $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
05191                         $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
05192                         $etype = $this->getTypeDef($uqType, $ns);
05193                         if ($etype) {
05194                             $this->debug("found type for [element] $type:");
05195                             $this->debug($this->varDump($etype));
05196                             if (isset($etype['phpType'])) {
05197                                 $t['phpType'] = $etype['phpType'];
05198                             }
05199                             if (isset($etype['elements'])) {
05200                                 $t['elements'] = $etype['elements'];
05201                             }
05202                             if (isset($etype['attrs'])) {
05203                                 $t['attrs'] = $etype['attrs'];
05204                             }
05205                         }
05206                     }
05207                     return $t;
05208                 }
05209             }
05210         } else {
05211             $this->debug("in getTypeDef: do not have schema for namespace $ns");
05212         }
05213         return false;
05214     }
05215 
05221     function webDescription(){
05222         global $HTTP_SERVER_VARS;
05223 
05224         if (isset($_SERVER)) {
05225             $PHP_SELF = $_SERVER['PHP_SELF'];
05226         } elseif (isset($HTTP_SERVER_VARS)) {
05227             $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
05228         } else {
05229             $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
05230         }
05231 
05232         $b = '
05233         <html><head><title>NuSOAP: '.$this->serviceName.'</title>
05234         <style type="text/css">
05235             body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
05236             p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
05237             pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
05238             ul      { margin-top: 10px; margin-left: 20px; }
05239             li      { list-style-type: none; margin-top: 10px; color: #000000; }
05240             .content{
05241             margin-left: 0px; padding-bottom: 2em; }
05242             .nav {
05243             padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
05244             margin-top: 10px; margin-left: 0px; color: #000000;
05245             background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
05246             .title {
05247             font-family: arial; font-size: 26px; color: #ffffff;
05248             background-color: #999999; width: 105%; margin-left: 0px;
05249             padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
05250             .hidden {
05251             position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
05252             font-family: arial; overflow: hidden; width: 600;
05253             padding: 20px; font-size: 10px; background-color: #999999;
05254             layer-background-color:#FFFFFF; }
05255             a,a:active  { color: charcoal; font-weight: bold; }
05256             a:visited   { color: #666666; font-weight: bold; }
05257             a:hover     { color: cc3300; font-weight: bold; }
05258         </style>
05259         <script language="JavaScript" type="text/javascript">
05260         <!--
05261         // POP-UP CAPTIONS...
05262         function lib_bwcheck(){ //Browsercheck (needed)
05263             this.ver=navigator.appVersion
05264             this.agent=navigator.userAgent
05265             this.dom=document.getElementById?1:0
05266             this.opera5=this.agent.indexOf("Opera 5")>-1
05267             this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
05268             this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
05269             this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
05270             this.ie=this.ie4||this.ie5||this.ie6
05271             this.mac=this.agent.indexOf("Mac")>-1
05272             this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
05273             this.ns4=(document.layers && !this.dom)?1:0;
05274             this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
05275             return this
05276         }
05277         var bw = new lib_bwcheck()
05278         //Makes crossbrowser object.
05279         function makeObj(obj){
05280             this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
05281             if(!this.evnt) return false
05282             this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
05283             this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
05284             this.writeIt=b_writeIt;
05285             return this
05286         }
05287         // A unit of measure that will be added when setting the position of a layer.
05288         //var px = bw.ns4||window.opera?"":"px";
05289         function b_writeIt(text){
05290             if (bw.ns4){this.wref.write(text);this.wref.close()}
05291             else this.wref.innerHTML = text
05292         }
05293         //Shows the messages
05294         var oDesc;
05295         function popup(divid){
05296             if(oDesc = new makeObj(divid)){
05297             oDesc.css.visibility = "visible"
05298             }
05299         }
05300         function popout(){ // Hides message
05301             if(oDesc) oDesc.css.visibility = "hidden"
05302         }
05303         //-->
05304         </script>
05305         </head>
05306         <body>
05307         <div class=content>
05308             <br><br>
05309             <div class=title>'.$this->serviceName.'</div>
05310             <div class=nav>
05311                 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
05312                 Click on an operation name to view it&apos;s details.</p>
05313                 <ul>';
05314                 foreach($this->getOperations() as $op => $data){
05315                     $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
05316                     // create hidden div
05317                     $b .= "<div id='$op' class='hidden'>
05318                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
05319                     foreach($data as $donnie => $marie){ // loop through opdata
05320                         if($donnie == 'input' || $donnie == 'output'){ // show input/output data
05321                             $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
05322                             foreach($marie as $captain => $tenille){ // loop through data
05323                                 if($captain == 'parts'){ // loop thru parts
05324                                     $b .= "&nbsp;&nbsp;$captain:<br>";
05325                                     //if(is_array($tenille)){
05326                                         foreach($tenille as $joanie => $chachi){
05327                                             $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
05328                                         }
05329                                     //}
05330                                 } else {
05331                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
05332                                 }
05333                             }
05334                         } else {
05335                             $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
05336                         }
05337                     }
05338                     $b .= '</div>';
05339                 }
05340                 $b .= '
05341                 <ul>
05342             </div>
05343         </div></body></html>';
05344         return $b;
05345     }
05346 
05354     function serialize($debug = 0)
05355     {
05356         $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
05357         $xml .= "\n<definitions";
05358         foreach($this->namespaces as $k => $v) {
05359             $xml .= " xmlns:$k=\"$v\"";
05360         } 
05361         // 10.9.02 - add poulter fix for wsdl and tns declarations
05362         if (isset($this->namespaces['wsdl'])) {
05363             $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
05364         } 
05365         if (isset($this->namespaces['tns'])) {
05366             $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
05367         } 
05368         $xml .= '>'; 
05369         // imports
05370         if (sizeof($this->import) > 0) {
05371             foreach($this->import as $ns => $list) {
05372                 foreach ($list as $ii) {
05373                     if ($ii['location'] != '') {
05374                         $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
05375                     } else {
05376                         $xml .= '<import namespace="' . $ns . '" />';
05377                     }
05378                 }
05379             } 
05380         } 
05381         // types
05382         if (count($this->schemas)>=1) {
05383             $xml .= "\n<types>\n";
05384             foreach ($this->schemas as $ns => $list) {
05385                 foreach ($list as $xs) {
05386                     $xml .= $xs->serializeSchema();
05387                 }
05388             }
05389             $xml .= '</types>';
05390         } 
05391         // messages
05392         if (count($this->messages) >= 1) {
05393             foreach($this->messages as $msgName => $msgParts) {
05394                 $xml .= "\n<message name=\"" . $msgName . '">';
05395                 if(is_array($msgParts)){
05396                     foreach($msgParts as $partName => $partType) {
05397                         // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
05398                         if (strpos($partType, ':')) {
05399                             $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
05400                         } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
05401                             // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
05402                             $typePrefix = 'xsd';
05403                         } else {
05404                             foreach($this->typemap as $ns => $types) {
05405                                 if (isset($types[$partType])) {
05406                                     $typePrefix = $this->getPrefixFromNamespace($ns);
05407                                 } 
05408                             } 
05409                             if (!isset($typePrefix)) {
05410                                 die("$partType has no namespace!");
05411                             } 
05412                         }
05413                         $ns = $this->getNamespaceFromPrefix($typePrefix);
05414                         $localPart = $this->getLocalPart($partType);
05415                         $typeDef = $this->getTypeDef($localPart, $ns);
05416                         if ($typeDef['typeClass'] == 'element') {
05417                             $elementortype = 'element';
05418                             if (substr($localPart, -1) == '^') {
05419                                 $localPart = substr($localPart, 0, -1);
05420                             }
05421                         } else {
05422                             $elementortype = 'type';
05423                         }
05424                         $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
05425                     }
05426                 }
05427                 $xml .= '</message>';
05428             } 
05429         } 
05430         // bindings & porttypes
05431         if (count($this->bindings) >= 1) {
05432             $binding_xml = '';
05433             $portType_xml = '';
05434             foreach($this->bindings as $bindingName => $attrs) {
05435                 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
05436                 $binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
05437                 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
05438                 foreach($attrs['operations'] as $opName => $opParts) {
05439                     $binding_xml .= "\n" . '  <operation name="' . $opName . '">';
05440                     $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
05441                     if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
05442                         $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
05443                     } else {
05444                         $enc_style = '';
05445                     }
05446                     $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
05447                     if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
05448                         $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
05449                     } else {
05450                         $enc_style = '';
05451                     }
05452                     $binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
05453                     $binding_xml .= "\n" . '  </operation>';
05454                     $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
05455                     if (isset($opParts['parameterOrder'])) {
05456                         $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
05457                     } 
05458                     $portType_xml .= '>';
05459                     if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
05460                         $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
05461                     }
05462                     $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';
05463                     $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';
05464                     $portType_xml .= "\n" . '  </operation>';
05465                 } 
05466                 $portType_xml .= "\n" . '</portType>';
05467                 $binding_xml .= "\n" . '</binding>';
05468             } 
05469             $xml .= $portType_xml . $binding_xml;
05470         } 
05471         // services
05472         $xml .= "\n<service name=\"" . $this->serviceName . '">';
05473         if (count($this->ports) >= 1) {
05474             foreach($this->ports as $pName => $attrs) {
05475                 $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
05476                 $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
05477                 $xml .= "\n" . '  </port>';
05478             } 
05479         } 
05480         $xml .= "\n" . '</service>';
05481         return $xml . "\n</definitions>";
05482     } 
05483 
05493     function parametersMatchWrapped($type, &$parameters) {
05494         $this->debug("in parametersMatchWrapped type=$type, parameters=");
05495         $this->appendDebug($this->varDump($parameters));
05496 
05497         // split type into namespace:unqualified-type
05498         if (strpos($type, ':')) {
05499             $uqType = substr($type, strrpos($type, ':') + 1);
05500             $ns = substr($type, 0, strrpos($type, ':'));
05501             $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
05502             if ($this->getNamespaceFromPrefix($ns)) {
05503                 $ns = $this->getNamespaceFromPrefix($ns);
05504                 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
05505             }
05506         } else {
05507             // TODO: should the type be compared to types in XSD, and the namespace
05508             // set to XSD if the type matches?
05509             $this->debug("in parametersMatchWrapped: No namespace for type $type");
05510             $ns = '';
05511             $uqType = $type;
05512         }
05513 
05514         // get the type information
05515         if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
05516             $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
05517             return false;
05518         }
05519         $this->debug("in parametersMatchWrapped: found typeDef=");
05520         $this->appendDebug($this->varDump($typeDef));
05521         if (substr($uqType, -1) == '^') {
05522             $uqType = substr($uqType, 0, -1);
05523         }
05524         $phpType = $typeDef['phpType'];
05525         $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
05526         $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
05527         
05528         // we expect a complexType or element of complexType
05529         if ($phpType != 'struct') {
05530             $this->debug("in parametersMatchWrapped: not a struct");
05531             return false;
05532         }
05533 
05534         // see whether the parameter names match the elements
05535         if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
05536             $elements = 0;
05537             $matches = 0;
05538             $change = false;
05539             if ($this->isArraySimpleOrStruct($parameters) == 'arraySimple' && count($parameters) == count($typeDef['elements'])) {
05540                 $this->debug("in parametersMatchWrapped: (wrapped return value kludge) correct number of elements in simple array, so change array and wrap");
05541                 $change = true;
05542             }
05543             foreach ($typeDef['elements'] as $name => $attrs) {
05544                 if ($change) {
05545                     $this->debug("in parametersMatchWrapped: change parameter $element to name $name");
05546                     $parameters[$name] = $parameters[$elements];
05547                     unset($parameters[$elements]);
05548                     $matches++;
05549                 } elseif (isset($parameters[$name])) {
05550                     $this->debug("in parametersMatchWrapped: have parameter named $name");
05551                     $matches++;
05552                 } else {
05553                     $this->debug("in parametersMatchWrapped: do not have parameter named $name");
05554                 }
05555                 $elements++;
05556             }
05557 
05558             $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
05559             if ($matches == 0) {
05560                 return false;
05561             }
05562             return true;
05563         }
05564 
05565         // since there are no elements for the type, if the user passed no
05566         // parameters, the parameters match wrapped.
05567         $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
05568         return count($parameters) == 0;
05569     }
05570 
05586     function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
05587         $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
05588         $this->appendDebug('parameters=' . $this->varDump($parameters));
05589         
05590         if ($direction != 'input' && $direction != 'output') {
05591             $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
05592             $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
05593             return false;
05594         } 
05595         if (!$opData = $this->getOperationData($operation, $bindingType)) {
05596             $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
05597             $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
05598             return false;
05599         }
05600         $this->debug('in serializeRPCParameters: opData:');
05601         $this->appendDebug($this->varDump($opData));
05602 
05603         // Get encoding style for output and set to current
05604         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
05605         if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
05606             $encodingStyle = $opData['output']['encodingStyle'];
05607             $enc_style = $encodingStyle;
05608         }
05609 
05610         // set input params
05611         $xml = '';
05612         if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
05613             $parts = &$opData[$direction]['parts'];
05614             $part_count = sizeof($parts);
05615             $style = $opData['style'];
05616             $use = $opData[$direction]['use'];
05617             $this->debug("have $part_count part(s) to serialize using $style/$use");
05618             if (is_array($parameters)) {
05619                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
05620                 $parameter_count = count($parameters);
05621                 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
05622                 // check for Microsoft-style wrapped parameters
05623                 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
05624                     $this->debug('check whether the caller has wrapped the parameters');
05625                     if ((($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) || ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1)) {
05626                         $this->debug('check whether caller\'s parameters match the wrapped ones');
05627                         if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
05628                             $this->debug('wrap the parameters for the caller');
05629                             $parameters = array('parameters' => $parameters);
05630                             $parameter_count = 1;
05631                         }
05632                     }
05633                 }
05634                 foreach ($parts as $name => $type) {
05635                     $this->debug("serializing part $name of type $type");
05636                     // Track encoding style
05637                     if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
05638                         $encodingStyle = $opData[$direction]['encodingStyle'];          
05639                         $enc_style = $encodingStyle;
05640                     } else {
05641                         $enc_style = false;
05642                     }
05643                     // NOTE: add error handling here
05644                     // if serializeType returns false, then catch global error and fault
05645                     if ($parametersArrayType == 'arraySimple') {
05646                         $p = array_shift($parameters);
05647                         $this->debug('calling serializeType w/indexed param');
05648                         $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
05649                     } elseif (isset($parameters[$name])) {
05650                         $this->debug('calling serializeType w/named param');
05651                         $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
05652                     } else {
05653                         // TODO: only send nillable
05654                         $this->debug('calling serializeType w/null param');
05655                         $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
05656                     }
05657                 }
05658             } else {
05659                 $this->debug('no parameters passed.');
05660             }
05661         }
05662         $this->debug("serializeRPCParameters returning: $xml");
05663         return $xml;
05664     } 
05665     
05680     function serializeParameters($operation, $direction, $parameters)
05681     {
05682         $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 
05683         $this->appendDebug('parameters=' . $this->varDump($parameters));
05684         
05685         if ($direction != 'input' && $direction != 'output') {
05686             $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
05687             $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
05688             return false;
05689         } 
05690         if (!$opData = $this->getOperationData($operation)) {
05691             $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
05692             $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
05693             return false;
05694         }
05695         $this->debug('opData:');
05696         $this->appendDebug($this->varDump($opData));
05697         
05698         // Get encoding style for output and set to current
05699         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
05700         if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
05701             $encodingStyle = $opData['output']['encodingStyle'];
05702             $enc_style = $encodingStyle;
05703         }
05704         
05705         // set input params
05706         $xml = '';
05707         if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
05708             
05709             $use = $opData[$direction]['use'];
05710             $this->debug("use=$use");
05711             $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
05712             if (is_array($parameters)) {
05713                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
05714                 $this->debug('have ' . $parametersArrayType . ' parameters');
05715                 foreach($opData[$direction]['parts'] as $name => $type) {
05716                     $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
05717                     // Track encoding style
05718                     if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
05719                         $encodingStyle = $opData[$direction]['encodingStyle'];          
05720                         $enc_style = $encodingStyle;
05721                     } else {
05722                         $enc_style = false;
05723                     }
05724                     // NOTE: add error handling here
05725                     // if serializeType returns false, then catch global error and fault
05726                     if ($parametersArrayType == 'arraySimple') {
05727                         $p = array_shift($parameters);
05728                         $this->debug('calling serializeType w/indexed param');
05729                         $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
05730                     } elseif (isset($parameters[$name])) {
05731                         $this->debug('calling serializeType w/named param');
05732                         $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
05733                     } else {
05734                         // TODO: only send nillable
05735                         $this->debug('calling serializeType w/null param');
05736                         $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
05737                     }
05738                 }
05739             } else {
05740                 $this->debug('no parameters passed.');
05741             }
05742         }
05743         $this->debug("serializeParameters returning: $xml");
05744         return $xml;
05745     } 
05746     
05759     function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
05760     {
05761         $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
05762         $this->appendDebug("value=" . $this->varDump($value));
05763         if($use == 'encoded' && $encodingStyle) {
05764             $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
05765         }
05766 
05767         // if a soapval has been supplied, let its type override the WSDL
05768         if (is_object($value) && get_class($value) == 'soapval') {
05769             if ($value->type_ns) {
05770                 $type = $value->type_ns . ':' . $value->type;
05771                 $forceType = true;
05772                 $this->debug("in serializeType: soapval overrides type to $type");
05773             } elseif ($value->type) {
05774                 $type = $value->type;
05775                 $forceType = true;
05776                 $this->debug("in serializeType: soapval overrides type to $type");
05777             } else {
05778                 $forceType = false;
05779                 $this->debug("in serializeType: soapval does not override type");
05780             }
05781             $attrs = $value->attributes;
05782             $value = $value->value;
05783             $this->debug("in serializeType: soapval overrides value to $value");
05784             if ($attrs) {
05785                 if (!is_array($value)) {
05786                     $value['!'] = $value;
05787                 }
05788                 foreach ($attrs as $n => $v) {
05789                     $value['!' . $n] = $v;
05790                 }
05791                 $this->debug("in serializeType: soapval provides attributes");
05792             }
05793         } else {
05794             $forceType = false;
05795         }
05796 
05797         $xml = '';
05798         if (strpos($type, ':')) {
05799             $uqType = substr($type, strrpos($type, ':') + 1);
05800             $ns = substr($type, 0, strrpos($type, ':'));
05801             $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
05802             if ($this->getNamespaceFromPrefix($ns)) {
05803                 $ns = $this->getNamespaceFromPrefix($ns);
05804                 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
05805             }
05806 
05807             if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
05808                 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
05809                 if ($unqualified && $use == 'literal') {
05810                     $elementNS = " xmlns=\"\"";
05811                 } else {
05812                     $elementNS = '';
05813                 }
05814                 if (is_null($value)) {
05815                     if ($use == 'literal') {
05816                         // TODO: depends on minOccurs
05817                         $xml = "<$name$elementNS/>";
05818                     } else {
05819                         // TODO: depends on nillable, which should be checked before calling this method
05820                         $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
05821                     }
05822                     $this->debug("in serializeType: returning: $xml");
05823                     return $xml;
05824                 }
05825                 if ($uqType == 'Array') {
05826                     // JBoss/Axis does this sometimes
05827                     return $this->serialize_val($value, $name, false, false, false, false, $use);
05828                 }
05829                 if ($uqType == 'boolean') {
05830                     if ((is_string($value) && $value == 'false') || (! $value)) {
05831                         $value = 'false';
05832                     } else {
05833                         $value = 'true';
05834                     }
05835                 } 
05836                 if ($uqType == 'string' && gettype($value) == 'string') {
05837                     $value = $this->expandEntities($value);
05838                 }
05839                 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
05840                     $value = sprintf("%.0lf", $value);
05841                 }
05842                 // it's a scalar
05843                 // TODO: what about null/nil values?
05844                 // check type isn't a custom type extending xmlschema namespace
05845                 if (!$this->getTypeDef($uqType, $ns)) {
05846                     if ($use == 'literal') {
05847                         if ($forceType) {
05848                             $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
05849                         } else {
05850                             $xml = "<$name$elementNS>$value</$name>";
05851                         }
05852                     } else {
05853                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
05854                     }
05855                     $this->debug("in serializeType: returning: $xml");
05856                     return $xml;
05857                 }
05858                 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
05859             } else if ($ns == 'http://xml.apache.org/xml-soap') {
05860                 $this->debug('in serializeType: appears to be Apache SOAP type');
05861                 if ($uqType == 'Map') {
05862                     $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
05863                     if (! $tt_prefix) {
05864                         $this->debug('in serializeType: Add namespace for Apache SOAP type');
05865                         $tt_prefix = 'ns' . rand(1000, 9999);
05866                         $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
05867                         // force this to be added to usedNamespaces
05868                         $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
05869                     }
05870                     $contents = '';
05871                     foreach($value as $k => $v) {
05872                         $this->debug("serializing map element: key $k, value $v");
05873                         $contents .= '<item>';
05874                         $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
05875                         $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
05876                         $contents .= '</item>';
05877                     }
05878                     if ($use == 'literal') {
05879                         if ($forceType) {
05880                             $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
05881                         } else {
05882                             $xml = "<$name>$contents</$name>";
05883                         }
05884                     } else {
05885                         $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
05886                     }
05887                     $this->debug("in serializeType: returning: $xml");
05888                     return $xml;
05889                 }
05890                 $this->debug('in serializeType: Apache SOAP type, but only support Map');
05891             }
05892         } else {
05893             // TODO: should the type be compared to types in XSD, and the namespace
05894             // set to XSD if the type matches?
05895             $this->debug("in serializeType: No namespace for type $type");
05896             $ns = '';
05897             $uqType = $type;
05898         }
05899         if(!$typeDef = $this->getTypeDef($uqType, $ns)){
05900             $this->setError("$type ($uqType) is not a supported type.");
05901             $this->debug("in serializeType: $type ($uqType) is not a supported type.");
05902             return false;
05903         } else {
05904             $this->debug("in serializeType: found typeDef");
05905             $this->appendDebug('typeDef=' . $this->varDump($typeDef));
05906             if (substr($uqType, -1) == '^') {
05907                 $uqType = substr($uqType, 0, -1);
05908             }
05909         }
05910         $phpType = $typeDef['phpType'];
05911         $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 
05912         // if php type == struct, map value to the <all> element names
05913         if ($phpType == 'struct') {
05914             if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
05915                 $elementName = $uqType;
05916                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
05917                     $elementNS = " xmlns=\"$ns\"";
05918                 } else {
05919                     $elementNS = " xmlns=\"\"";
05920                 }
05921             } else {
05922                 $elementName = $name;
05923                 if ($unqualified) {
05924                     $elementNS = " xmlns=\"\"";
05925                 } else {
05926                     $elementNS = '';
05927                 }
05928             }
05929             if (is_null($value)) {
05930                 if ($use == 'literal') {
05931                     // TODO: depends on minOccurs
05932                     $xml = "<$elementName$elementNS/>";
05933                 } else {
05934                     $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
05935                 }
05936                 $this->debug("in serializeType: returning: $xml");
05937                 return $xml;
05938             }
05939             if (is_object($value)) {
05940                 $value = get_object_vars($value);
05941             }
05942             if (is_array($value)) {
05943                 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
05944                 if ($use == 'literal') {
05945                     if ($forceType) {
05946                         $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
05947                     } else {
05948                         $xml = "<$elementName$elementNS$elementAttrs>";
05949                     }
05950                 } else {
05951                     $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
05952                 }
05953     
05954                 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
05955                 $xml .= "</$elementName>";
05956             } else {
05957                 $this->debug("in serializeType: phpType is struct, but value is not an array");
05958                 $this->setError("phpType is struct, but value is not an array: see debug output for details");
05959                 $xml = '';
05960             }
05961         } elseif ($phpType == 'array') {
05962             if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
05963                 $elementNS = " xmlns=\"$ns\"";
05964             } else {
05965                 if ($unqualified) {
05966                     $elementNS = " xmlns=\"\"";
05967                 } else {
05968                     $elementNS = '';
05969                 }
05970             }
05971             if (is_null($value)) {
05972                 if ($use == 'literal') {
05973                     // TODO: depends on minOccurs
05974                     $xml = "<$name$elementNS/>";
05975                 } else {
05976                     $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
05977                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
05978                         ":Array\" " .
05979                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
05980                         ':arrayType="' .
05981                         $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
05982                         ':' .
05983                         $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
05984                 }
05985                 $this->debug("in serializeType: returning: $xml");
05986                 return $xml;
05987             }
05988             if (isset($typeDef['multidimensional'])) {
05989                 $nv = array();
05990                 foreach($value as $v) {
05991                     $cols = ',' . sizeof($v);
05992                     $nv = array_merge($nv, $v);
05993                 } 
05994                 $value = $nv;
05995             } else {
05996                 $cols = '';
05997             } 
05998             if (is_array($value) && sizeof($value) >= 1) {
05999                 $rows = sizeof($value);
06000                 $contents = '';
06001                 foreach($value as $k => $v) {
06002                     $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
06003                     //if (strpos($typeDef['arrayType'], ':') ) {
06004                     if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
06005                         $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
06006                     } else {
06007                         $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
06008                     } 
06009                 }
06010             } else {
06011                 $rows = 0;
06012                 $contents = null;
06013             }
06014             // TODO: for now, an empty value will be serialized as a zero element
06015             // array.  Revisit this when coding the handling of null/nil values.
06016             if ($use == 'literal') {
06017                 $xml = "<$name$elementNS>"
06018                     .$contents
06019                     ."</$name>";
06020             } else {
06021                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
06022                     $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
06023                     .':arrayType="'
06024                     .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
06025                     .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
06026                     .$contents
06027                     ."</$name>";
06028             }
06029         } elseif ($phpType == 'scalar') {
06030             if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
06031                 $elementNS = " xmlns=\"$ns\"";
06032             } else {
06033                 if ($unqualified) {
06034                     $elementNS = " xmlns=\"\"";
06035                 } else {
06036                     $elementNS = '';
06037                 }
06038             }
06039             if ($use == 'literal') {
06040                 if ($forceType) {
06041                     $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
06042                 } else {
06043                     $xml = "<$name$elementNS>$value</$name>";
06044                 }
06045             } else {
06046                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
06047             }
06048         }
06049         $this->debug("in serializeType: returning: $xml");
06050         return $xml;
06051     }
06052     
06063     function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
06064         $xml = '';
06065         if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
06066             $this->debug("serialize attributes for XML Schema type $ns:$uqType");
06067             if (is_array($value)) {
06068                 $xvalue = $value;
06069             } elseif (is_object($value)) {
06070                 $xvalue = get_object_vars($value);
06071             } else {
06072                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
06073                 $xvalue = array();
06074             }
06075             foreach ($typeDef['attrs'] as $aName => $attrs) {
06076                 if (isset($xvalue['!' . $aName])) {
06077                     $xname = '!' . $aName;
06078                     $this->debug("value provided for attribute $aName with key $xname");
06079                 } elseif (isset($xvalue[$aName])) {
06080                     $xname = $aName;
06081                     $this->debug("value provided for attribute $aName with key $xname");
06082                 } elseif (isset($attrs['default'])) {
06083                     $xname = '!' . $aName;
06084                     $xvalue[$xname] = $attrs['default'];
06085                     $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
06086                 } else {
06087                     $xname = '';
06088                     $this->debug("no value provided for attribute $aName");
06089                 }
06090                 if ($xname) {
06091                     $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
06092                 }
06093             } 
06094         } else {
06095             $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
06096         }
06097         if (isset($typeDef['extensionBase'])) {
06098             $ns = $this->getPrefix($typeDef['extensionBase']);
06099             $uqType = $this->getLocalPart($typeDef['extensionBase']);
06100             if ($this->getNamespaceFromPrefix($ns)) {
06101                 $ns = $this->getNamespaceFromPrefix($ns);
06102             }
06103             if ($typeDef = $this->getTypeDef($uqType, $ns)) {
06104                 $this->debug("serialize attributes for extension base $ns:$uqType");
06105                 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
06106             } else {
06107                 $this->debug("extension base $ns:$uqType is not a supported type");
06108             }
06109         }
06110         return $xml;
06111     }
06112 
06125     function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
06126         $xml = '';
06127         if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
06128             $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
06129             if (is_array($value)) {
06130                 $xvalue = $value;
06131             } elseif (is_object($value)) {
06132                 $xvalue = get_object_vars($value);
06133             } else {
06134                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
06135                 $xvalue = array();
06136             }
06137             // toggle whether all elements are present - ideally should validate against schema
06138             if (count($typeDef['elements']) != count($xvalue)){
06139                 $optionals = true;
06140             }
06141             foreach ($typeDef['elements'] as $eName => $attrs) {
06142                 if (!isset($xvalue[$eName])) {
06143                     if (isset($attrs['default'])) {
06144                         $xvalue[$eName] = $attrs['default'];
06145                         $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
06146                     }
06147                 }
06148                 // if user took advantage of a minOccurs=0, then only serialize named parameters
06149                 if (isset($optionals)
06150                     && (!isset($xvalue[$eName])) 
06151                     && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
06152                     ){
06153                     if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
06154                         $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
06155                     }
06156                     // do nothing
06157                     $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
06158                 } else {
06159                     // get value
06160                     if (isset($xvalue[$eName])) {
06161                         $v = $xvalue[$eName];
06162                     } else {
06163                         $v = null;
06164                     }
06165                     if (isset($attrs['form'])) {
06166                         $unqualified = ($attrs['form'] == 'unqualified');
06167                     } else {
06168                         $unqualified = false;
06169                     }
06170                     if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
06171                         $vv = $v;
06172                         foreach ($vv as $k => $v) {
06173                             if (isset($attrs['type']) || isset($attrs['ref'])) {
06174                                 // serialize schema-defined type
06175                                 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
06176                             } else {
06177                                 // serialize generic type (can this ever really happen?)
06178                                 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
06179                                 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
06180                             }
06181                         }
06182                     } else {
06183                         if (isset($attrs['type']) || isset($attrs['ref'])) {
06184                             // serialize schema-defined type
06185                             $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
06186                         } else {
06187                             // serialize generic type (can this ever really happen?)
06188                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
06189                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
06190                         }
06191                     }
06192                 }
06193             } 
06194         } else {
06195             $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
06196         }
06197         if (isset($typeDef['extensionBase'])) {
06198             $ns = $this->getPrefix($typeDef['extensionBase']);
06199             $uqType = $this->getLocalPart($typeDef['extensionBase']);
06200             if ($this->getNamespaceFromPrefix($ns)) {
06201                 $ns = $this->getNamespaceFromPrefix($ns);
06202             }
06203             if ($typeDef = $this->getTypeDef($uqType, $ns)) {
06204                 $this->debug("serialize elements for extension base $ns:$uqType");
06205                 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
06206             } else {
06207                 $this->debug("extension base $ns:$uqType is not a supported type");
06208             }
06209         }
06210         return $xml;
06211     }
06212 
06227     function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
06228         if (count($elements) > 0) {
06229             $eElements = array();
06230             foreach($elements as $n => $e){
06231                 // expand each element
06232                 $ee = array();
06233                 foreach ($e as $k => $v) {
06234                     $k = strpos($k,':') ? $this->expandQname($k) : $k;
06235                     $v = strpos($v,':') ? $this->expandQname($v) : $v;
06236                     $ee[$k] = $v;
06237                 }
06238                 $eElements[$n] = $ee;
06239             }
06240             $elements = $eElements;
06241         }
06242         
06243         if (count($attrs) > 0) {
06244             foreach($attrs as $n => $a){
06245                 // expand each attribute
06246                 foreach ($a as $k => $v) {
06247                     $k = strpos($k,':') ? $this->expandQname($k) : $k;
06248                     $v = strpos($v,':') ? $this->expandQname($v) : $v;
06249                     $aa[$k] = $v;
06250                 }
06251                 $eAttrs[$n] = $aa;
06252             }
06253             $attrs = $eAttrs;
06254         }
06255 
06256         $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
06257         $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
06258 
06259         $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
06260         $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
06261     }
06262 
06274     function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
06275         $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
06276 
06277         $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
06278         $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
06279     }
06280 
06288     function addElement($attrs) {
06289         $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
06290         $this->schemas[$typens][0]->addElement($attrs);
06291     }
06292 
06307     function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
06308         if ($use == 'encoded' && $encodingStyle == '') {
06309             $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
06310         }
06311 
06312         if ($style == 'document') {
06313             $elements = array();
06314             foreach ($in as $n => $t) {
06315                 $elements[$n] = array('name' => $n, 'type' => $t);
06316             }
06317             $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
06318             $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
06319             $in = array('parameters' => 'tns:' . $name . '^');
06320 
06321             $elements = array();
06322             foreach ($out as $n => $t) {
06323                 $elements[$n] = array('name' => $n, 'type' => $t);
06324             }
06325             $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
06326             $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
06327             $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
06328         }
06329 
06330         // get binding
06331         $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
06332         array(
06333         'name' => $name,
06334         'binding' => $this->serviceName . 'Binding',
06335         'endpoint' => $this->endpoint,
06336         'soapAction' => $soapaction,
06337         'style' => $style,
06338         'input' => array(
06339             'use' => $use,
06340             'namespace' => $namespace,
06341             'encodingStyle' => $encodingStyle,
06342             'message' => $name . 'Request',
06343             'parts' => $in),
06344         'output' => array(
06345             'use' => $use,
06346             'namespace' => $namespace,
06347             'encodingStyle' => $encodingStyle,
06348             'message' => $name . 'Response',
06349             'parts' => $out),
06350         'namespace' => $namespace,
06351         'transport' => 'http://schemas.xmlsoap.org/soap/http',
06352         'documentation' => $documentation); 
06353         // add portTypes
06354         // add messages
06355         if($in)
06356         {
06357             foreach($in as $pName => $pType)
06358             {
06359                 if(strpos($pType,':')) {
06360                     $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
06361                 }
06362                 $this->messages[$name.'Request'][$pName] = $pType;
06363             }
06364         } else {
06365             $this->messages[$name.'Request']= '0';
06366         }
06367         if($out)
06368         {
06369             foreach($out as $pName => $pType)
06370             {
06371                 if(strpos($pType,':')) {
06372                     $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
06373                 }
06374                 $this->messages[$name.'Response'][$pName] = $pType;
06375             }
06376         } else {
06377             $this->messages[$name.'Response']= '0';
06378         }
06379         return true;
06380     } 
06381 }
06382 ?><?php
06383 
06384 
06385 
06395 class nusoap_parser extends nusoap_base {
06396 
06397     var $xml = '';
06398     var $xml_encoding = '';
06399     var $method = '';
06400     var $root_struct = '';
06401     var $root_struct_name = '';
06402     var $root_struct_namespace = '';
06403     var $root_header = '';
06404     var $document = '';         // incoming SOAP body (text)
06405     // determines where in the message we are (envelope,header,body,method)
06406     var $status = '';
06407     var $position = 0;
06408     var $depth = 0;
06409     var $default_namespace = '';
06410     var $namespaces = array();
06411     var $message = array();
06412     var $parent = '';
06413     var $fault = false;
06414     var $fault_code = '';
06415     var $fault_str = '';
06416     var $fault_detail = '';
06417     var $depth_array = array();
06418     var $debug_flag = true;
06419     var $soapresponse = NULL;   // parsed SOAP Body
06420     var $soapheader = NULL;     // parsed SOAP Header
06421     var $responseHeaders = '';  // incoming SOAP headers (text)
06422     var $body_position = 0;
06423     // for multiref parsing:
06424     // array of id => pos
06425     var $ids = array();
06426     // array of id => hrefs => pos
06427     var $multirefs = array();
06428     // toggle for auto-decoding element content
06429     var $decode_utf8 = true;
06430 
06440     function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
06441         parent::nusoap_base();
06442         $this->xml = $xml;
06443         $this->xml_encoding = $encoding;
06444         $this->method = $method;
06445         $this->decode_utf8 = $decode_utf8;
06446 
06447         // Check whether content has been read.
06448         if(!empty($xml)){
06449             // Check XML encoding
06450             $pos_xml = strpos($xml, '<?xml');
06451             if ($pos_xml !== FALSE) {
06452                 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
06453                 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
06454                     $xml_encoding = $res[1];
06455                     if (strtoupper($xml_encoding) != $encoding) {
06456                         $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
06457                         $this->debug($err);
06458                         if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
06459                             $this->setError($err);
06460                             return;
06461                         }
06462                         // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
06463                     } else {
06464                         $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
06465                     }
06466                 } else {
06467                     $this->debug('No encoding specified in XML declaration');
06468                 }
06469             } else {
06470                 $this->debug('No XML declaration');
06471             }
06472             $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
06473             // Create an XML parser - why not xml_parser_create_ns?
06474             $this->parser = xml_parser_create($this->xml_encoding);
06475             // Set the options for parsing the XML data.
06476             //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
06477             xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
06478             xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
06479             // Set the object for the parser.
06480             xml_set_object($this->parser, $this);
06481             // Set the element handlers for the parser.
06482             xml_set_element_handler($this->parser, 'start_element','end_element');
06483             xml_set_character_data_handler($this->parser,'character_data');
06484 
06485             // Parse the XML file.
06486             if(!xml_parse($this->parser,$xml,true)){
06487                 // Display an error message.
06488                 $err = sprintf('XML error parsing SOAP payload on line %d: %s',
06489                 xml_get_current_line_number($this->parser),
06490                 xml_error_string(xml_get_error_code($this->parser)));
06491                 $this->debug($err);
06492                 $this->debug("XML payload:\n" . $xml);
06493                 $this->setError($err);
06494             } else {
06495                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
06496                 // get final value
06497                 $this->soapresponse = $this->message[$this->root_struct]['result'];
06498                 // get header value
06499                 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
06500                     $this->soapheader = $this->message[$this->root_header]['result'];
06501                 }
06502                 // resolve hrefs/ids
06503                 if(sizeof($this->multirefs) > 0){
06504                     foreach($this->multirefs as $id => $hrefs){
06505                         $this->debug('resolving multirefs for id: '.$id);
06506                         $idVal = $this->buildVal($this->ids[$id]);
06507                         if (is_array($idVal) && isset($idVal['!id'])) {
06508                             unset($idVal['!id']);
06509                         }
06510                         foreach($hrefs as $refPos => $ref){
06511                             $this->debug('resolving href at pos '.$refPos);
06512                             $this->multirefs[$id][$refPos] = $idVal;
06513                         }
06514                     }
06515                 }
06516             }
06517             xml_parser_free($this->parser);
06518         } else {
06519             $this->debug('xml was empty, didn\'t parse!');
06520             $this->setError('xml was empty, didn\'t parse!');
06521         }
06522     }
06523 
06532     function start_element($parser, $name, $attrs) {
06533         // position in a total number of elements, starting from 0
06534         // update class level pos
06535         $pos = $this->position++;
06536         // and set mine
06537         $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
06538         // depth = how many levels removed from root?
06539         // set mine as current global depth and increment global depth value
06540         $this->message[$pos]['depth'] = $this->depth++;
06541 
06542         // else add self as child to whoever the current parent is
06543         if($pos != 0){
06544             $this->message[$this->parent]['children'] .= '|'.$pos;
06545         }
06546         // set my parent
06547         $this->message[$pos]['parent'] = $this->parent;
06548         // set self as current parent
06549         $this->parent = $pos;
06550         // set self as current value for this depth
06551         $this->depth_array[$this->depth] = $pos;
06552         // get element prefix
06553         if(strpos($name,':')){
06554             // get ns prefix
06555             $prefix = substr($name,0,strpos($name,':'));
06556             // get unqualified name
06557             $name = substr(strstr($name,':'),1);
06558         }
06559         // set status
06560         if($name == 'Envelope'){
06561             $this->status = 'envelope';
06562         } elseif($name == 'Header' && $this->status = 'envelope'){
06563             $this->root_header = $pos;
06564             $this->status = 'header';
06565         } elseif($name == 'Body' && $this->status = 'envelope'){
06566             $this->status = 'body';
06567             $this->body_position = $pos;
06568         // set method
06569         } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
06570             $this->status = 'method';
06571             $this->root_struct_name = $name;
06572             $this->root_struct = $pos;
06573             $this->message[$pos]['type'] = 'struct';
06574             $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
06575         }
06576         // set my status
06577         $this->message[$pos]['status'] = $this->status;
06578         // set name
06579         $this->message[$pos]['name'] = htmlspecialchars($name);
06580         // set attrs
06581         $this->message[$pos]['attrs'] = $attrs;
06582 
06583         // loop through atts, logging ns and type declarations
06584         $attstr = '';
06585         foreach($attrs as $key => $value){
06586             $key_prefix = $this->getPrefix($key);
06587             $key_localpart = $this->getLocalPart($key);
06588             // if ns declarations, add to class level array of valid namespaces
06589             if($key_prefix == 'xmlns'){
06590                 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
06591                     $this->XMLSchemaVersion = $value;
06592                     $this->namespaces['xsd'] = $this->XMLSchemaVersion;
06593                     $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
06594                 }
06595                 $this->namespaces[$key_localpart] = $value;
06596                 // set method namespace
06597                 if($name == $this->root_struct_name){
06598                     $this->methodNamespace = $value;
06599                 }
06600             // if it's a type declaration, set type
06601         } elseif($key_localpart == 'type'){
06602                 if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
06603                     // do nothing: already processed arrayType
06604                 } else {
06605                     $value_prefix = $this->getPrefix($value);
06606                     $value_localpart = $this->getLocalPart($value);
06607                     $this->message[$pos]['type'] = $value_localpart;
06608                     $this->message[$pos]['typePrefix'] = $value_prefix;
06609                     if(isset($this->namespaces[$value_prefix])){
06610                         $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
06611                     } else if(isset($attrs['xmlns:'.$value_prefix])) {
06612                         $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
06613                     }
06614                     // should do something here with the namespace of specified type?
06615                 }
06616             } elseif($key_localpart == 'arrayType'){
06617                 $this->message[$pos]['type'] = 'array';
06618                 /* do arrayType ereg here
06619                 [1]    arrayTypeValue    ::=    atype asize
06620                 [2]    atype    ::=    QName rank*
06621                 [3]    rank    ::=    '[' (',')* ']'
06622                 [4]    asize    ::=    '[' length~ ']'
06623                 [5]    length    ::=    nextDimension* Digit+
06624                 [6]    nextDimension    ::=    Digit+ ','
06625                 */
06626                 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
06627                 if(ereg($expr,$value,$regs)){
06628                     $this->message[$pos]['typePrefix'] = $regs[1];
06629                     $this->message[$pos]['arrayTypePrefix'] = $regs[1];
06630                     if (isset($this->namespaces[$regs[1]])) {
06631                         $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
06632                     } else if (isset($attrs['xmlns:'.$regs[1]])) {
06633                         $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
06634                     }
06635                     $this->message[$pos]['arrayType'] = $regs[2];
06636                     $this->message[$pos]['arraySize'] = $regs[3];
06637                     $this->message[$pos]['arrayCols'] = $regs[4];
06638                 }
06639             // specifies nil value (or not)
06640             } elseif ($key_localpart == 'nil'){
06641                 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
06642             // some other attribute
06643             } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
06644                 $this->message[$pos]['xattrs']['!' . $key] = $value;
06645             }
06646 
06647             if ($key == 'xmlns') {
06648                 $this->default_namespace = $value;
06649             }
06650             // log id
06651             if($key == 'id'){
06652                 $this->ids[$value] = $pos;
06653             }
06654             // root
06655             if($key_localpart == 'root' && $value == 1){
06656                 $this->status = 'method';
06657                 $this->root_struct_name = $name;
06658                 $this->root_struct = $pos;
06659                 $this->debug("found root struct $this->root_struct_name, pos $pos");
06660             }
06661             // for doclit
06662             $attstr .= " $key=\"$value\"";
06663         }
06664         // get namespace - must be done after namespace atts are processed
06665         if(isset($prefix)){
06666             $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
06667             $this->default_namespace = $this->namespaces[$prefix];
06668         } else {
06669             $this->message[$pos]['namespace'] = $this->default_namespace;
06670         }
06671         if($this->status == 'header'){
06672             if ($this->root_header != $pos) {
06673                 $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
06674             }
06675         } elseif($this->root_struct_name != ''){
06676             $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
06677         }
06678     }
06679 
06687     function end_element($parser, $name) {
06688         // position of current element is equal to the last value left in depth_array for my depth
06689         $pos = $this->depth_array[$this->depth--];
06690 
06691         // get element prefix
06692         if(strpos($name,':')){
06693             // get ns prefix
06694             $prefix = substr($name,0,strpos($name,':'));
06695             // get unqualified name
06696             $name = substr(strstr($name,':'),1);
06697         }
06698         
06699         // build to native type
06700         if(isset($this->body_position) && $pos > $this->body_position){
06701             // deal w/ multirefs
06702             if(isset($this->message[$pos]['attrs']['href'])){
06703                 // get id
06704                 $id = substr($this->message[$pos]['attrs']['href'],1);
06705                 // add placeholder to href array
06706                 $this->multirefs[$id][$pos] = 'placeholder';
06707                 // add set a reference to it as the result value
06708                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
06709             // build complexType values
06710             } elseif($this->message[$pos]['children'] != ''){
06711                 // if result has already been generated (struct/array)
06712                 if(!isset($this->message[$pos]['result'])){
06713                     $this->message[$pos]['result'] = $this->buildVal($pos);
06714                 }
06715             // build complexType values of attributes and possibly simpleContent
06716             } elseif (isset($this->message[$pos]['xattrs'])) {
06717                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
06718                     $this->message[$pos]['xattrs']['!'] = null;
06719                 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
06720                     if (isset($this->message[$pos]['type'])) {
06721                         $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
06722                     } else {
06723                         $parent = $this->message[$pos]['parent'];
06724                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
06725                             $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
06726                         } else {
06727                             $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
06728                         }
06729                     }
06730                 }
06731                 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
06732             // set value of simpleType (or nil complexType)
06733             } else {
06734                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
06735                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
06736                     $this->message[$pos]['xattrs']['!'] = null;
06737                 } elseif (isset($this->message[$pos]['type'])) {
06738                     $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
06739                 } else {
06740                     $parent = $this->message[$pos]['parent'];
06741                     if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
06742                         $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
06743                     } else {
06744                         $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
06745                     }
06746                 }
06747 
06748                 /* add value to parent's result, if parent is struct/array
06749                 $parent = $this->message[$pos]['parent'];
06750                 if($this->message[$parent]['type'] != 'map'){
06751                     if(strtolower($this->message[$parent]['type']) == 'array'){
06752                         $this->message[$parent]['result'][] = $this->message[$pos]['result'];
06753                     } else {
06754                         $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
06755                     }
06756                 }
06757                 */
06758             }
06759         }
06760         
06761         // for doclit
06762         if($this->status == 'header'){
06763             if ($this->root_header != $pos) {
06764                 $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
06765             }
06766         } elseif($pos >= $this->root_struct){
06767             $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
06768         }
06769         // switch status
06770         if($pos == $this->root_struct){
06771             $this->status = 'body';
06772             $this->root_struct_namespace = $this->message[$pos]['namespace'];
06773         } elseif($name == 'Body'){
06774             $this->status = 'envelope';
06775          } elseif($name == 'Header'){
06776             $this->status = 'envelope';
06777         } elseif($name == 'Envelope'){
06778             //
06779         }
06780         // set parent back to my parent
06781         $this->parent = $this->message[$pos]['parent'];
06782     }
06783 
06791     function character_data($parser, $data){
06792         $pos = $this->depth_array[$this->depth];
06793         if ($this->xml_encoding=='UTF-8'){
06794             // TODO: add an option to disable this for folks who want
06795             // raw UTF-8 that, e.g., might not map to iso-8859-1
06796             // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
06797             if($this->decode_utf8){
06798                 $data = utf8_decode($data);
06799             }
06800         }
06801         $this->message[$pos]['cdata'] .= $data;
06802         // for doclit
06803         if($this->status == 'header'){
06804             $this->responseHeaders .= $data;
06805         } else {
06806             $this->document .= $data;
06807         }
06808     }
06809 
06817     function get_response(){
06818         return $this->soapresponse;
06819     }
06820 
06827     function get_soapbody(){
06828         return $this->soapresponse;
06829     }
06830 
06837     function get_soapheader(){
06838         return $this->soapheader;
06839     }
06840 
06847     function getHeaders(){
06848         return $this->responseHeaders;
06849     }
06850 
06860     function decodeSimple($value, $type, $typens) {
06861         // TODO: use the namespace!
06862         if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
06863             return (string) $value;
06864         }
06865         if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
06866             return (int) $value;
06867         }
06868         if ($type == 'float' || $type == 'double' || $type == 'decimal') {
06869             return (double) $value;
06870         }
06871         if ($type == 'boolean') {
06872             if (strtolower($value) == 'false' || strtolower($value) == 'f') {
06873                 return false;
06874             }
06875             return (boolean) $value;
06876         }
06877         if ($type == 'base64' || $type == 'base64Binary') {
06878             $this->debug('Decode base64 value');
06879             return base64_decode($value);
06880         }
06881         // obscure numeric types
06882         if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
06883             || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
06884             || $type == 'unsignedInt'
06885             || $type == 'unsignedShort' || $type == 'unsignedByte') {
06886             return (int) $value;
06887         }
06888         // bogus: parser treats array with no elements as a simple type
06889         if ($type == 'array') {
06890             return array();
06891         }
06892         // everything else
06893         return (string) $value;
06894     }
06895 
06904     function buildVal($pos){
06905         if(!isset($this->message[$pos]['type'])){
06906             $this->message[$pos]['type'] = '';
06907         }
06908         $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
06909         // if there are children...
06910         if($this->message[$pos]['children'] != ''){
06911             $this->debug('in buildVal, there are children');
06912             $children = explode('|',$this->message[$pos]['children']);
06913             array_shift($children); // knock off empty
06914             // md array
06915             if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
06916                 $r=0; // rowcount
06917                 $c=0; // colcount
06918                 foreach($children as $child_pos){
06919                     $this->debug("in buildVal, got an MD array element: $r, $c");
06920                     $params[$r][] = $this->message[$child_pos]['result'];
06921                     $c++;
06922                     if($c == $this->message[$pos]['arrayCols']){
06923                         $c = 0;
06924                         $r++;
06925                     }
06926                 }
06927             // array
06928             } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
06929                 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
06930                 foreach($children as $child_pos){
06931                     $params[] = &$this->message[$child_pos]['result'];
06932                 }
06933             // apache Map type: java hashtable
06934             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
06935                 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
06936                 foreach($children as $child_pos){
06937                     $kv = explode("|",$this->message[$child_pos]['children']);
06938                     $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
06939                 }
06940             // generic compound type
06941             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
06942             } else {
06943                 // Apache Vector type: treat as an array
06944                 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
06945                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
06946                     $notstruct = 1;
06947                 } else {
06948                     $notstruct = 0;
06949                 }
06950                 //
06951                 foreach($children as $child_pos){
06952                     if($notstruct){
06953                         $params[] = &$this->message[$child_pos]['result'];
06954                     } else {
06955                         if (isset($params[$this->message[$child_pos]['name']])) {
06956                             // de-serialize repeated element name into an array
06957                             if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
06958                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
06959                             }
06960                             $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
06961                         } else {
06962                             $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
06963                         }
06964                     }
06965                 }
06966             }
06967             if (isset($this->message[$pos]['xattrs'])) {
06968                 $this->debug('in buildVal, handling attributes');
06969                 foreach ($this->message[$pos]['xattrs'] as $n => $v) {
06970                     $params[$n] = $v;
06971                 }
06972             }
06973             // handle simpleContent
06974             if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
06975                 $this->debug('in buildVal, handling simpleContent');
06976                 if (isset($this->message[$pos]['type'])) {
06977                     $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
06978                 } else {
06979                     $parent = $this->message[$pos]['parent'];
06980                     if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
06981                         $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
06982                     } else {
06983                         $params['!'] = $this->message[$pos]['cdata'];
06984                     }
06985                 }
06986             }
06987             $ret = is_array($params) ? $params : array();
06988             $this->debug('in buildVal, return:');
06989             $this->appendDebug($this->varDump($ret));
06990             return $ret;
06991         } else {
06992             $this->debug('in buildVal, no children, building scalar');
06993             $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
06994             if (isset($this->message[$pos]['type'])) {
06995                 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
06996                 $this->debug("in buildVal, return: $ret");
06997                 return $ret;
06998             }
06999             $parent = $this->message[$pos]['parent'];
07000             if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
07001                 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
07002                 $this->debug("in buildVal, return: $ret");
07003                 return $ret;
07004             }
07005             $ret = $this->message[$pos]['cdata'];
07006             $this->debug("in buildVal, return: $ret");
07007             return $ret;
07008         }
07009     }
07010 }
07011 
07015 class soap_parser extends nusoap_parser {
07016 }
07017 
07018 ?><?php
07019 
07020 
07021 
07042 class nusoap_client extends nusoap_base  {
07043 
07044     var $username = '';             // Username for HTTP authentication
07045     var $password = '';             // Password for HTTP authentication
07046     var $authtype = '';             // Type of HTTP authentication
07047     var $certRequest = array();     // Certificate for HTTP SSL authentication
07048     var $requestHeaders = false;    // SOAP headers in request (text)
07049     var $responseHeaders = '';      // SOAP headers from response (incomplete namespace resolution) (text)
07050     var $responseHeader = NULL;     // SOAP Header from response (parsed)
07051     var $document = '';             // SOAP body response portion (incomplete namespace resolution) (text)
07052     var $endpoint;
07053     var $forceEndpoint = '';        // overrides WSDL endpoint
07054     var $proxyhost = '';
07055     var $proxyport = '';
07056     var $proxyusername = '';
07057     var $proxypassword = '';
07058     var $xml_encoding = '';         // character set encoding of incoming (response) messages
07059     var $http_encoding = false;
07060     var $timeout = 0;               // HTTP connection timeout
07061     var $response_timeout = 30;     // HTTP response timeout
07062     var $endpointType = '';         // soap|wsdl, empty for WSDL initialization error
07063     var $persistentConnection = false;
07064     var $defaultRpcParams = false;  // This is no longer used
07065     var $request = '';              // HTTP request
07066     var $response = '';             // HTTP response
07067     var $responseData = '';         // SOAP payload of response
07068     var $cookies = array();         // Cookies from response or for request
07069     var $decode_utf8 = true;        // toggles whether the parser decodes element content w/ utf8_decode()
07070     var $operations = array();      // WSDL operations, empty for WSDL initialization error
07071     var $curl_options = array();    // User-specified cURL options
07072     var $bindingType = '';          // WSDL operation binding type
07073     var $use_curl = false;          // whether to always try to use cURL
07074 
07075     /*
07076      * fault related variables
07077      */
07082     var $fault;
07087     var $faultcode;
07092     var $faultstring;
07097     var $faultdetail;
07098 
07113     function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
07114         parent::nusoap_base();
07115         $this->endpoint = $endpoint;
07116         $this->proxyhost = $proxyhost;
07117         $this->proxyport = $proxyport;
07118         $this->proxyusername = $proxyusername;
07119         $this->proxypassword = $proxypassword;
07120         $this->timeout = $timeout;
07121         $this->response_timeout = $response_timeout;
07122 
07123         $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
07124         $this->appendDebug('endpoint=' . $this->varDump($endpoint));
07125 
07126         // make values
07127         if($wsdl){
07128             if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
07129                 $this->wsdl = $endpoint;
07130                 $this->endpoint = $this->wsdl->wsdl;
07131                 $this->wsdlFile = $this->endpoint;
07132                 $this->debug('existing wsdl instance created from ' . $this->endpoint);
07133                 $this->checkWSDL();
07134             } else {
07135                 $this->wsdlFile = $this->endpoint;
07136                 $this->wsdl = null;
07137                 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
07138             }
07139             $this->endpointType = 'wsdl';
07140         } else {
07141             $this->debug("instantiate SOAP with endpoint at $endpoint");
07142             $this->endpointType = 'soap';
07143         }
07144     }
07145 
07171     function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
07172         $this->operation = $operation;
07173         $this->fault = false;
07174         $this->setError('');
07175         $this->request = '';
07176         $this->response = '';
07177         $this->responseData = '';
07178         $this->faultstring = '';
07179         $this->faultcode = '';
07180         $this->opData = array();
07181         
07182         $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
07183         $this->appendDebug('params=' . $this->varDump($params));
07184         $this->appendDebug('headers=' . $this->varDump($headers));
07185         if ($headers) {
07186             $this->requestHeaders = $headers;
07187         }
07188         if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
07189             $this->loadWSDL();
07190             if ($this->getError())
07191                 return false;
07192         }
07193         // serialize parameters
07194         if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
07195             // use WSDL for operation
07196             $this->opData = $opData;
07197             $this->debug("found operation");
07198             $this->appendDebug('opData=' . $this->varDump($opData));
07199             if (isset($opData['soapAction'])) {
07200                 $soapAction = $opData['soapAction'];
07201             }
07202             if (! $this->forceEndpoint) {
07203                 $this->endpoint = $opData['endpoint'];
07204             } else {
07205                 $this->endpoint = $this->forceEndpoint;
07206             }
07207             $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
07208             $style = $opData['style'];
07209             $use = $opData['input']['use'];
07210             // add ns to ns array
07211             if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
07212                 $nsPrefix = 'ns' . rand(1000, 9999);
07213                 $this->wsdl->namespaces[$nsPrefix] = $namespace;
07214             }
07215             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
07216             // serialize payload
07217             if (is_string($params)) {
07218                 $this->debug("serializing param string for WSDL operation $operation");
07219                 $payload = $params;
07220             } elseif (is_array($params)) {
07221                 $this->debug("serializing param array for WSDL operation $operation");
07222                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
07223             } else {
07224                 $this->debug('params must be array or string');
07225                 $this->setError('params must be array or string');
07226                 return false;
07227             }
07228             $usedNamespaces = $this->wsdl->usedNamespaces;
07229             if (isset($opData['input']['encodingStyle'])) {
07230                 $encodingStyle = $opData['input']['encodingStyle'];
07231             } else {
07232                 $encodingStyle = '';
07233             }
07234             $this->appendDebug($this->wsdl->getDebug());
07235             $this->wsdl->clearDebug();
07236             if ($errstr = $this->wsdl->getError()) {
07237                 $this->debug('got wsdl error: '.$errstr);
07238                 $this->setError('wsdl error: '.$errstr);
07239                 return false;
07240             }
07241         } elseif($this->endpointType == 'wsdl') {
07242             // operation not in WSDL
07243             $this->appendDebug($this->wsdl->getDebug());
07244             $this->wsdl->clearDebug();
07245             $this->setError( 'operation '.$operation.' not present.');
07246             $this->debug("operation '$operation' not present.");
07247             return false;
07248         } else {
07249             // no WSDL
07250             //$this->namespaces['ns1'] = $namespace;
07251             $nsPrefix = 'ns' . rand(1000, 9999);
07252             // serialize 
07253             $payload = '';
07254             if (is_string($params)) {
07255                 $this->debug("serializing param string for operation $operation");
07256                 $payload = $params;
07257             } elseif (is_array($params)) {
07258                 $this->debug("serializing param array for operation $operation");
07259                 foreach($params as $k => $v){
07260                     $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
07261                 }
07262             } else {
07263                 $this->debug('params must be array or string');
07264                 $this->setError('params must be array or string');
07265                 return false;
07266             }
07267             $usedNamespaces = array();
07268             if ($use == 'encoded') {
07269                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
07270             } else {
07271                 $encodingStyle = '';
07272             }
07273         }
07274         // wrap RPC calls with method element
07275         if ($style == 'rpc') {
07276             if ($use == 'literal') {
07277                 $this->debug("wrapping RPC request with literal method element");
07278                 if ($namespace) {
07279                     // 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
07280                     $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
07281                                 $payload .
07282                                 "</$nsPrefix:$operation>";
07283                 } else {
07284                     $payload = "<$operation>" . $payload . "</$operation>";
07285                 }
07286             } else {
07287                 $this->debug("wrapping RPC request with encoded method element");
07288                 if ($namespace) {
07289                     $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
07290                                 $payload .
07291                                 "</$nsPrefix:$operation>";
07292                 } else {
07293                     $payload = "<$operation>" .
07294                                 $payload .
07295                                 "</$operation>";
07296                 }
07297             }
07298         }
07299         // serialize envelope
07300         $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
07301         $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
07302         $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
07303         // send
07304         $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
07305         if($errstr = $this->getError()){
07306             $this->debug('Error: '.$errstr);
07307             return false;
07308         } else {
07309             $this->return = $return;
07310             $this->debug('sent message successfully and got a(n) '.gettype($return));
07311             $this->appendDebug('return=' . $this->varDump($return));
07312             
07313             // fault?
07314             if(is_array($return) && isset($return['faultcode'])){
07315                 $this->debug('got fault');
07316                 $this->setError($return['faultcode'].': '.$return['faultstring']);
07317                 $this->fault = true;
07318                 foreach($return as $k => $v){
07319                     $this->$k = $v;
07320                     $this->debug("$k = $v<br>");
07321                 }
07322                 return $return;
07323             } elseif ($style == 'document') {
07324                 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
07325                 // we are only going to return the first part here...sorry about that
07326                 return $return;
07327             } else {
07328                 // array of return values
07329                 if(is_array($return)){
07330                     // multiple 'out' parameters, which we return wrapped up
07331                     // in the array
07332                     if(sizeof($return) > 1){
07333                         return $return;
07334                     }
07335                     // single 'out' parameter (normally the return value)
07336                     $return = array_shift($return);
07337                     $this->debug('return shifted value: ');
07338                     $this->appendDebug($this->varDump($return));
07339                     return $return;
07340                 // nothing returned (ie, echoVoid)
07341                 } else {
07342                     return "";
07343                 }
07344             }
07345         }
07346     }
07347 
07353     function checkWSDL() {
07354         $this->appendDebug($this->wsdl->getDebug());
07355         $this->wsdl->clearDebug();
07356         $this->debug('checkWSDL');
07357         // catch errors
07358         if ($errstr = $this->wsdl->getError()) {
07359             $this->debug('got wsdl error: '.$errstr);
07360             $this->setError('wsdl error: '.$errstr);
07361         } elseif ($this->operations = $this->wsdl->getOperations('soap')) {
07362             $this->bindingType = 'soap';
07363             $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
07364         } elseif ($this->operations = $this->wsdl->getOperations('soap12')) {
07365             $this->bindingType = 'soap12';
07366             $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
07367             $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
07368         } else {
07369             $this->debug('getOperations returned false');
07370             $this->setError('no operations defined in the WSDL document!');
07371         }
07372     }
07373 
07379     function loadWSDL() {
07380         $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
07381         $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
07382         $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
07383         $this->wsdl->fetchWSDL($this->wsdlFile);
07384         $this->checkWSDL();
07385     }
07386 
07394     function getOperationData($operation){
07395         if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
07396             $this->loadWSDL();
07397             if ($this->getError())
07398                 return false;
07399         }
07400         if(isset($this->operations[$operation])){
07401             return $this->operations[$operation];
07402         }
07403         $this->debug("No data for operation: $operation");
07404     }
07405 
07420     function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
07421         $this->checkCookies();
07422         // detect transport
07423         switch(true){
07424             // http(s)
07425             case ereg('^http',$this->endpoint):
07426                 $this->debug('transporting via HTTP');
07427                 if($this->persistentConnection == true && is_object($this->persistentConnection)){
07428                     $http =& $this->persistentConnection;
07429                 } else {
07430                     $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
07431                     if ($this->persistentConnection) {
07432                         $http->usePersistentConnection();
07433                     }
07434                 }
07435                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
07436                 $http->setSOAPAction($soapaction);
07437                 if($this->proxyhost && $this->proxyport){
07438                     $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
07439                 }
07440                 if($this->authtype != '') {
07441                     $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
07442                 }
07443                 if($this->http_encoding != ''){
07444                     $http->setEncoding($this->http_encoding);
07445                 }
07446                 $this->debug('sending message, length='.strlen($msg));
07447                 if(ereg('^http:',$this->endpoint)){
07448                 //if(strpos($this->endpoint,'http:')){
07449                     $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
07450                 } elseif(ereg('^https',$this->endpoint)){
07451                 //} elseif(strpos($this->endpoint,'https:')){
07452                     //if(phpversion() == '4.3.0-dev'){
07453                         //$response = $http->send($msg,$timeout,$response_timeout);
07454                         //$this->request = $http->outgoing_payload;
07455                         //$this->response = $http->incoming_payload;
07456                     //} else
07457                     $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
07458                 } else {
07459                     $this->setError('no http/s in endpoint url');
07460                 }
07461                 $this->request = $http->outgoing_payload;
07462                 $this->response = $http->incoming_payload;
07463                 $this->appendDebug($http->getDebug());
07464                 $this->UpdateCookies($http->incoming_cookies);
07465 
07466                 // save transport object if using persistent connections
07467                 if ($this->persistentConnection) {
07468                     $http->clearDebug();
07469                     if (!is_object($this->persistentConnection)) {
07470                         $this->persistentConnection = $http;
07471                     }
07472                 }
07473                 
07474                 if($err = $http->getError()){
07475                     $this->setError('HTTP Error: '.$err);
07476                     return false;
07477                 } elseif($this->getError()){
07478                     return false;
07479                 } else {
07480                     $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
07481                     return $this->parseResponse($http->incoming_headers, $this->responseData);
07482                 }
07483             break;
07484             default:
07485                 $this->setError('no transport found, or selected transport is not yet supported!');
07486             return false;
07487             break;
07488         }
07489     }
07490 
07499     function parseResponse($headers, $data) {
07500         $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
07501         $this->appendDebug($this->varDump($headers));
07502         if (!strstr($headers['content-type'], 'text/xml')) {
07503             $this->setError('Response not of type text/xml: ' . $headers['content-type']);
07504             return false;
07505         }
07506         if (strpos($headers['content-type'], '=')) {
07507             $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
07508             $this->debug('Got response encoding: ' . $enc);
07509             if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
07510                 $this->xml_encoding = strtoupper($enc);
07511             } else {
07512                 $this->xml_encoding = 'US-ASCII';
07513             }
07514         } else {
07515             // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
07516             $this->xml_encoding = 'ISO-8859-1';
07517         }
07518         $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
07519         $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
07520         // add parser debug data to our debug
07521         $this->appendDebug($parser->getDebug());
07522         // if parse errors
07523         if($errstr = $parser->getError()){
07524             $this->setError( $errstr);
07525             // destroy the parser object
07526             unset($parser);
07527             return false;
07528         } else {
07529             // get SOAP headers
07530             $this->responseHeaders = $parser->getHeaders();
07531             // get SOAP headers
07532             $this->responseHeader = $parser->get_soapheader();
07533             // get decoded message
07534             $return = $parser->get_soapbody();
07535             // add document for doclit support
07536             $this->document = $parser->document;
07537             // destroy the parser object
07538             unset($parser);
07539             // return decode message
07540             return $return;
07541         }
07542      }
07543 
07551     function setCurlOption($option, $value) {
07552         $this->debug("setCurlOption option=$option, value=");
07553         $this->appendDebug($this->varDump($value));
07554         $this->curl_options[$option] = $value;
07555     }
07556 
07563     function setEndpoint($endpoint) {
07564         $this->debug("setEndpoint(\"$endpoint\")");
07565         $this->forceEndpoint = $endpoint;
07566     }
07567 
07574     function setHeaders($headers){
07575         $this->debug("setHeaders headers=");
07576         $this->appendDebug($this->varDump($headers));
07577         $this->requestHeaders = $headers;
07578     }
07579 
07586     function getHeaders(){
07587         return $this->responseHeaders;
07588     }
07589 
07596     function getHeader(){
07597         return $this->responseHeader;
07598     }
07599 
07609     function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
07610         $this->proxyhost = $proxyhost;
07611         $this->proxyport = $proxyport;
07612         $this->proxyusername = $proxyusername;
07613         $this->proxypassword = $proxypassword;
07614     }
07615 
07625     function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
07626         $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
07627         $this->appendDebug($this->varDump($certRequest));
07628         $this->username = $username;
07629         $this->password = $password;
07630         $this->authtype = $authtype;
07631         $this->certRequest = $certRequest;
07632     }
07633     
07640     function setHTTPEncoding($enc='gzip, deflate'){
07641         $this->debug("setHTTPEncoding(\"$enc\")");
07642         $this->http_encoding = $enc;
07643     }
07644     
07651     function setUseCURL($use) {
07652         $this->debug("setUseCURL($use)");
07653         $this->use_curl = $use;
07654     }
07655 
07661     function useHTTPPersistentConnection(){
07662         $this->debug("useHTTPPersistentConnection");
07663         $this->persistentConnection = true;
07664     }
07665     
07677     function getDefaultRpcParams() {
07678         return $this->defaultRpcParams;
07679     }
07680 
07692     function setDefaultRpcParams($rpcParams) {
07693         $this->defaultRpcParams = $rpcParams;
07694     }
07695     
07703     function getProxy() {
07704         $r = rand();
07705         $evalStr = $this->_getProxyClassCode($r);
07706         //$this->debug("proxy class: $evalStr");
07707         if ($this->getError()) {
07708             $this->debug("Error from _getProxyClassCode, so return NULL");
07709             return null;
07710         }
07711         // eval the class
07712         eval($evalStr);
07713         // instantiate proxy object
07714         eval("\$proxy = new nusoap_proxy_$r('');");
07715         // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
07716         $proxy->endpointType = 'wsdl';
07717         $proxy->wsdlFile = $this->wsdlFile;
07718         $proxy->wsdl = $this->wsdl;
07719         $proxy->operations = $this->operations;
07720         $proxy->defaultRpcParams = $this->defaultRpcParams;
07721         // transfer other state
07722         $proxy->soap_defencoding = $this->soap_defencoding;
07723         $proxy->username = $this->username;
07724         $proxy->password = $this->password;
07725         $proxy->authtype = $this->authtype;
07726         $proxy->certRequest = $this->certRequest;
07727         $proxy->requestHeaders = $this->requestHeaders;
07728         $proxy->endpoint = $this->endpoint;
07729         $proxy->forceEndpoint = $this->forceEndpoint;
07730         $proxy->proxyhost = $this->proxyhost;
07731         $proxy->proxyport = $this->proxyport;
07732         $proxy->proxyusername = $this->proxyusername;
07733         $proxy->proxypassword = $this->proxypassword;
07734         $proxy->http_encoding = $this->http_encoding;
07735         $proxy->timeout = $this->timeout;
07736         $proxy->response_timeout = $this->response_timeout;
07737         $proxy->persistentConnection = &$this->persistentConnection;
07738         $proxy->decode_utf8 = $this->decode_utf8;
07739         $proxy->curl_options = $this->curl_options;
07740         $proxy->bindingType = $this->bindingType;
07741         $proxy->use_curl = $this->use_curl;
07742         return $proxy;
07743     }
07744 
07751     function _getProxyClassCode($r) {
07752         $this->debug("in getProxy endpointType=$this->endpointType");
07753         $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
07754         if ($this->endpointType != 'wsdl') {
07755             $evalStr = 'A proxy can only be created for a WSDL client';
07756             $this->setError($evalStr);
07757             $evalStr = "echo \"$evalStr\";";
07758             return $evalStr;
07759         }
07760         if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
07761             $this->loadWSDL();
07762             if ($this->getError()) {
07763                 return "echo \"" . $this->getError() . "\";";
07764             }
07765         }
07766         $evalStr = '';
07767         foreach ($this->operations as $operation => $opData) {
07768             if ($operation != '') {
07769                 // create param string and param comment string
07770                 if (sizeof($opData['input']['parts']) > 0) {
07771                     $paramStr = '';
07772                     $paramArrayStr = '';
07773                     $paramCommentStr = '';
07774                     foreach ($opData['input']['parts'] as $name => $type) {
07775                         $paramStr .= "\$$name, ";
07776                         $paramArrayStr .= "'$name' => \$$name, ";
07777                         $paramCommentStr .= "$type \$$name, ";
07778                     }
07779                     $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
07780                     $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
07781                     $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
07782                 } else {
07783                     $paramStr = '';
07784                     $paramArrayStr = '';
07785                     $paramCommentStr = 'void';
07786                 }
07787                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
07788                 $evalStr .= "// $paramCommentStr
07789     function " . str_replace('.', '__', $operation) . "($paramStr) {
07790         \$params = array($paramArrayStr);
07791         return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
07792     }
07793     ";
07794                 unset($paramStr);
07795                 unset($paramCommentStr);
07796             }
07797         }
07798         $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
07799     '.$evalStr.'
07800 }';
07801         return $evalStr;
07802     }
07803 
07810     function getProxyClassCode() {
07811         $r = rand();
07812         return $this->_getProxyClassCode($r);
07813     }
07814 
07822     function getHTTPBody($soapmsg) {
07823         return $soapmsg;
07824     }
07825     
07834     function getHTTPContentType() {
07835         return 'text/xml';
07836     }
07837     
07847     function getHTTPContentTypeCharset() {
07848         return $this->soap_defencoding;
07849     }
07850 
07851     /*
07852     * whether or not parser should decode utf8 element content
07853     *
07854     * @return   always returns true
07855     * @access   public
07856     */
07857     function decodeUTF8($bool){
07858         $this->decode_utf8 = $bool;
07859         return true;
07860     }
07861 
07870     function setCookie($name, $value) {
07871         if (strlen($name) == 0) {
07872             return false;
07873         }
07874         $this->cookies[] = array('name' => $name, 'value' => $value);
07875         return true;
07876     }
07877 
07884     function getCookies() {
07885         return $this->cookies;
07886     }
07887 
07894     function checkCookies() {
07895         if (sizeof($this->cookies) == 0) {
07896             return true;
07897         }
07898         $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
07899         $curr_cookies = $this->cookies;
07900         $this->cookies = array();
07901         foreach ($curr_cookies as $cookie) {
07902             if (! is_array($cookie)) {
07903                 $this->debug('Remove cookie that is not an array');
07904                 continue;
07905             }
07906             if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
07907                 if (strtotime($cookie['expires']) > time()) {
07908                     $this->cookies[] = $cookie;
07909                 } else {
07910                     $this->debug('Remove expired cookie ' . $cookie['name']);
07911                 }
07912             } else {
07913                 $this->cookies[] = $cookie;
07914             }
07915         }
07916         $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
07917         return true;
07918     }
07919 
07927     function UpdateCookies($cookies) {
07928         if (sizeof($this->cookies) == 0) {
07929             // no existing cookies: take whatever is new
07930             if (sizeof($cookies) > 0) {
07931                 $this->debug('Setting new cookie(s)');
07932                 $this->cookies = $cookies;
07933             }
07934             return true;
07935         }
07936         if (sizeof($cookies) == 0) {
07937             // no new cookies: keep what we've got
07938             return true;
07939         }
07940         // merge
07941         foreach ($cookies as $newCookie) {
07942             if (!is_array($newCookie)) {
07943                 continue;
07944             }
07945             if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
07946                 continue;
07947             }
07948             $newName = $newCookie['name'];
07949 
07950             $found = false;
07951             for ($i = 0; $i < count($this->cookies); $i++) {
07952                 $cookie = $this->cookies[$i];
07953                 if (!is_array($cookie)) {
07954                     continue;
07955                 }
07956                 if (!isset($cookie['name'])) {
07957                     continue;
07958                 }
07959                 if ($newName != $cookie['name']) {
07960                     continue;
07961                 }
07962                 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
07963                 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
07964                 if ($newDomain != $domain) {
07965                     continue;
07966                 }
07967                 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
07968                 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
07969                 if ($newPath != $path) {
07970                     continue;
07971                 }
07972                 $this->cookies[$i] = $newCookie;
07973                 $found = true;
07974                 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
07975                 break;
07976             }
07977             if (! $found) {
07978                 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
07979                 $this->cookies[] = $newCookie;
07980             }
07981         }
07982         return true;
07983     }
07984 }
07985 
07986 if (!extension_loaded('soap')) {
07990     class soapclient extends nusoap_client {
07991     }
07992 }
07993 ?>