"Fossies" - the Fresh Open Source Software Archive

Member "4.6.1/vendor/nusoap/nusoap.php" (8 Apr 2021, 298109 Bytes) of package /linux/www/studip-4.6.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "nusoap.php": 4.5.2_vs_4.6.

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