"TYPO3 4.0.1: typo3_src-4.0.1/typo3/mod/tools/em/class.nusoap.php Source File", "datetime" => "Sat Dec 2 19:22:21 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>

class.nusoap.php

00001 <?php
00002 /*
00003 $Id: class.nusoap.php 1421 2006-04-10 09:27:15Z mundaun $
00004 
00005 NuSOAP - Web Services Toolkit for PHP
00006 
00007 Copyright (c) 2002 NuSphere Corporation
00008 
00009 This library is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU Lesser General Public
00011 License as published by the Free Software Foundation; either
00012 version 2.1 of the License, or (at your option) any later version.
00013 
00014 This library is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public
00020 License along with this library; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 §§§§§
00023 If you have any questions or comments, please email:
00024 
00025 Dietrich Ayala
00026 dietrich@ganx4.com
00027 http://dietrich.ganx4.com/nusoap
00028 
00029 NuSphere Corporation
00030 http://www.nusphere.com
00031 
00032 */
00033 
00034 /* load classes
00035 
00036 // necessary classes
00037 require_once('class.soapclient.php');
00038 require_once('class.soap_val.php');
00039 require_once('class.soap_parser.php');
00040 require_once('class.soap_fault.php');
00041 
00042 // transport classes
00043 require_once('class.soap_transport_http.php');
00044 
00045 // optional add-on classes
00046 require_once('class.xmlschema.php');
00047 require_once('class.wsdl.php');
00048 */
00049 
00050 // class variable emulation
00051 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
00052 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
00053 
00062 class nusoap_base {
00069         var $title = 'NuSOAP';
00076         var $version = '0.7.2';
00083         var $revision = '$Revision: 1421 $';
00090         var $error_str = '';
00097     var $debug_str = '';
00105         var $charencoding = true;
00112         var $debugLevel;
00113 
00120         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
00121 
00128     var $soap_defencoding = 'ISO-8859-1';
00129         //var $soap_defencoding = 'UTF-8';
00130 
00139         var $namespaces = array(
00140                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
00141                 'xsd' => 'http://www.w3.org/2001/XMLSchema',
00142                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
00143                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
00144                 );
00145 
00152         var $usedNamespaces = array();
00153 
00161         var $typemap = array(
00162         'http://www.w3.org/2001/XMLSchema' => array(
00163                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
00164                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
00165                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
00166                 // abstract "any" types
00167                 'anyType'=>'string','anySimpleType'=>'string',
00168                 // derived datatypes
00169                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
00170                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
00171                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
00172                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
00173         'http://www.w3.org/2000/10/XMLSchema' => array(
00174                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00175                 'float'=>'double','dateTime'=>'string',
00176                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00177         'http://www.w3.org/1999/XMLSchema' => array(
00178                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00179                 'float'=>'double','dateTime'=>'string',
00180                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00181         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
00182         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
00183     'http://xml.apache.org/xml-soap' => array('Map')
00184         );
00185 
00194         var $xmlEntities = array('quot' => '"','amp' => '&',
00195                 'lt' => '<','gt' => '>','apos' => "'");
00196 
00202         function nusoap_base() {
00203                 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
00204         }
00205 
00212         function getGlobalDebugLevel() {
00213                 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
00214         }
00215 
00222         function setGlobalDebugLevel($level) {
00223                 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
00224         }
00225 
00232         function getDebugLevel() {
00233                 return $this->debugLevel;
00234         }
00235 
00242         function setDebugLevel($level) {
00243                 $this->debugLevel = $level;
00244         }
00245 
00252         function debug($string){
00253                 if ($this->debugLevel > 0) {
00254                         $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
00255                 }
00256         }
00257 
00264         function appendDebug($string){
00265                 if ($this->debugLevel > 0) {
00266                         // it would be nice to use a memory stream here to use
00267                         // memory more efficiently
00268                         $this->debug_str .= $string;
00269                 }
00270         }
00271 
00277         function clearDebug() {
00278                 // it would be nice to use a memory stream here to use
00279                 // memory more efficiently
00280                 $this->debug_str = '';
00281         }
00282 
00289         function &getDebug() {
00290                 // it would be nice to use a memory stream here to use
00291                 // memory more efficiently
00292                 return $this->debug_str;
00293         }
00294 
00302         function &getDebugAsXMLComment() {
00303                 // it would be nice to use a memory stream here to use
00304                 // memory more efficiently
00305                 while (strpos($this->debug_str, '--')) {
00306                         $this->debug_str = str_replace('--', '- -', $this->debug_str);
00307                 }
00308         return "<!--\n" . $this->debug_str . "\n-->";
00309         }
00310 
00317         function expandEntities($val) {
00318                 if ($this->charencoding) {
00319                 $val = str_replace('&', '&amp;', $val);
00320                 $val = str_replace("'", '&apos;', $val);
00321                 $val = str_replace('"', '&quot;', $val);
00322                 $val = str_replace('<', '&lt;', $val);
00323                 $val = str_replace('>', '&gt;', $val);
00324             }
00325             return $val;
00326         }
00327 
00334         function getError(){
00335                 if($this->error_str != ''){
00336                         return $this->error_str;
00337                 }
00338                 return false;
00339         }
00340 
00347         function setError($str){
00348                 $this->error_str = $str;
00349         }
00350 
00358         function isArraySimpleOrStruct($val) {
00359         $keyList = array_keys($val);
00360                 foreach ($keyList as $keyListValue) {
00361                         if (!is_int($keyListValue)) {
00362                                 return 'arrayStruct';
00363                         }
00364                 }
00365                 return 'arraySimple';
00366         }
00367 
00382         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
00383                 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
00384                 $this->appendDebug('value=' . $this->varDump($val));
00385                 $this->appendDebug('attributes=' . $this->varDump($attributes));
00386 
00387         if(is_object($val) && get_class($val) == 'soapval'){
00388                 return $val->serialize($use);
00389         }
00390                 // force valid name if necessary
00391                 if (is_numeric($name)) {
00392                         $name = '__numeric_' . $name;
00393                 } elseif (! $name) {
00394                         $name = 'noname';
00395                 }
00396                 // if name has ns, add ns prefix to name
00397                 $xmlns = '';
00398         if($name_ns){
00399                         $prefix = 'nu'.rand(1000,9999);
00400                         $name = $prefix.':'.$name;
00401                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";
00402                 }
00403                 // if type is prefixed, create type prefix
00404                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
00405                         // need to fix this. shouldn't default to xsd if no ns specified
00406                     // w/o checking against typemap
00407                         $type_prefix = 'xsd';
00408                 } elseif($type_ns){
00409                         $type_prefix = 'ns'.rand(1000,9999);
00410                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
00411                 }
00412                 // serialize attributes if present
00413                 $atts = '';
00414                 if($attributes){
00415                         foreach($attributes as $k => $v){
00416                                 $atts .= " $k=\"".$this->expandEntities($v).'"';
00417                         }
00418                 }
00419                 // serialize null value
00420                 if (is_null($val)) {
00421                         if ($use == 'literal') {
00422                                 // TODO: depends on minOccurs
00423                         return "<$name$xmlns $atts/>";
00424                 } else {
00425                                 if (isset($type) && isset($type_prefix)) {
00426                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00427                                 } else {
00428                                         $type_str = '';
00429                                 }
00430                         return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
00431                 }
00432                 }
00433         // serialize if an xsd built-in primitive type
00434         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
00435                 if (is_bool($val)) {
00436                         if ($type == 'boolean') {
00437                                 $val = $val ? 'true' : 'false';
00438                         } elseif (! $val) {
00439                                 $val = 0;
00440                         }
00441                         } else if (is_string($val)) {
00442                                 $val = $this->expandEntities($val);
00443                         }
00444                         if ($use == 'literal') {
00445                         return "<$name$xmlns $atts>$val</$name>";
00446                 } else {
00447                         return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>";
00448                 }
00449         }
00450                 // detect type and serialize
00451                 $xml = '';
00452                 switch(true) {
00453                         case (is_bool($val) || $type == 'boolean'):
00454                         if ($type == 'boolean') {
00455                                 $val = $val ? 'true' : 'false';
00456                         } elseif (! $val) {
00457                                 $val = 0;
00458                         }
00459                                 if ($use == 'literal') {
00460                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00461                                 } else {
00462                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
00463                                 }
00464                                 break;
00465                         case (is_int($val) || is_long($val) || $type == 'int'):
00466                                 if ($use == 'literal') {
00467                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00468                                 } else {
00469                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
00470                                 }
00471                                 break;
00472                         case (is_float($val)|| is_double($val) || $type == 'float'):
00473                                 if ($use == 'literal') {
00474                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00475                                 } else {
00476                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
00477                                 }
00478                                 break;
00479                         case (is_string($val) || $type == 'string'):
00480                                 $val = $this->expandEntities($val);
00481                                 if ($use == 'literal') {
00482                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00483                                 } else {
00484                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
00485                                 }
00486                                 break;
00487                         case is_object($val):
00488                                 if (! $name) {
00489                                         $name = get_class($val);
00490                                         $this->debug("In serialize_val, used class name $name as element name");
00491                                 } else {
00492                                         $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
00493                                 }
00494                                 foreach(get_object_vars($val) as $k => $v){
00495                                         $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
00496                                 }
00497                                 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
00498                                 break;
00499                         break;
00500                         case (is_array($val) || $type):
00501                                 // detect if struct or array
00502                                 $valueType = $this->isArraySimpleOrStruct($val);
00503                 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
00504                                         $i = 0;
00505                                         if(is_array($val) && count($val)> 0){
00506                                                 foreach($val as $v){
00507                                 if(is_object($v) && get_class($v) ==  'soapval'){
00508                                                                 $tt_ns = $v->type_ns;
00509                                                                 $tt = $v->type;
00510                                                         } elseif (is_array($v)) {
00511                                                                 $tt = $this->isArraySimpleOrStruct($v);
00512                                                         } else {
00513                                                                 $tt = gettype($v);
00514                                 }
00515                                                         $array_types[$tt] = 1;
00516                                                         // TODO: for literal, the name should be $name
00517                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
00518                                                         ++$i;
00519                                                 }
00520                                                 if(count($array_types) > 1){
00521                                                         $array_typename = 'xsd:anyType';
00522                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
00523                                                         if ($tt == 'integer') {
00524                                                                 $tt = 'int';
00525                                                         }
00526                                                         $array_typename = 'xsd:'.$tt;
00527                                                 } elseif(isset($tt) && $tt == 'arraySimple'){
00528                                                         $array_typename = 'SOAP-ENC:Array';
00529                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){
00530                                                         $array_typename = 'unnamed_struct_use_soapval';
00531                                                 } else {
00532                                                         // if type is prefixed, create type prefix
00533                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
00534                                                                  $array_typename = 'xsd:' . $tt;
00535                                                         } elseif ($tt_ns) {
00536                                                                 $tt_prefix = 'ns' . rand(1000, 9999);
00537                                                                 $array_typename = "$tt_prefix:$tt";
00538                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
00539                                                         } else {
00540                                                                 $array_typename = $tt;
00541                                                         }
00542                                                 }
00543                                                 $array_type = $i;
00544                                                 if ($use == 'literal') {
00545                                                         $type_str = '';
00546                                                 } else if (isset($type) && isset($type_prefix)) {
00547                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00548                                                 } else {
00549                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
00550                                                 }
00551                                         // empty array
00552                                         } else {
00553                                                 if ($use == 'literal') {
00554                                                         $type_str = '';
00555                                                 } else if (isset($type) && isset($type_prefix)) {
00556                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00557                                                 } else {
00558                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
00559                                                 }
00560                                         }
00561                                         // TODO: for array in literal, there is no wrapper here
00562                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
00563                                 } else {
00564                                         // got a struct
00565                                         if(isset($type) && isset($type_prefix)){
00566                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";
00567                                         } else {
00568                                                 $type_str = '';
00569                                         }
00570                                         if ($use == 'literal') {
00571                                                 $xml .= "<$name$xmlns $atts>";
00572                                         } else {
00573                                                 $xml .= "<$name$xmlns$type_str$atts>";
00574                                         }
00575                                         foreach($val as $k => $v){
00576                                                 // Apache Map
00577                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
00578                                                         $xml .= '<item>';
00579                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
00580                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
00581                                                         $xml .= '</item>';
00582                                                 } else {
00583                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
00584                                                 }
00585                                         }
00586                                         $xml .= "</$name>";
00587                                 }
00588                                 break;
00589                         default:
00590                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
00591                                 break;
00592                 }
00593                 return $xml;
00594         }
00595 
00608     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
00609     // TODO: add an option to automatically run utf8_encode on $body and $headers
00610     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
00611     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
00612 
00613         $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
00614         $this->debug("headers:");
00615         $this->appendDebug($this->varDump($headers));
00616         $this->debug("namespaces:");
00617         $this->appendDebug($this->varDump($namespaces));
00618 
00619         // serialize namespaces
00620     $ns_string = '';
00621         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
00622                 $ns_string .= " xmlns:$k=\"$v\"";
00623         }
00624         if($encodingStyle) {
00625                 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
00626         }
00627 
00628         // serialize headers
00629         if($headers){
00630                 if (is_array($headers)) {
00631                         $xml = '';
00632                         foreach ($headers as $header) {
00633                                 $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
00634                         }
00635                         $headers = $xml;
00636                         $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
00637                 }
00638                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
00639         }
00640         // serialize envelope
00641         return
00642         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
00643         '<SOAP-ENV:Envelope'.$ns_string.">".
00644         $headers.
00645         "<SOAP-ENV:Body>".
00646                 $body.
00647         "</SOAP-ENV:Body>".
00648         "</SOAP-ENV:Envelope>";
00649     }
00650 
00659     function formatDump($str){
00660                 $str = htmlspecialchars($str);
00661                 return nl2br($str);
00662     }
00663 
00671         function contractQname($qname){
00672                 // get element namespace
00673                 //$this->xdebug("Contract $qname");
00674                 if (strrpos($qname, ':')) {
00675                         // get unqualified name
00676                         $name = substr($qname, strrpos($qname, ':') + 1);
00677                         // get ns
00678                         $ns = substr($qname, 0, strrpos($qname, ':'));
00679                         $p = $this->getPrefixFromNamespace($ns);
00680                         if ($p) {
00681                                 return $p . ':' . $name;
00682                         }
00683                         return $qname;
00684                 } else {
00685                         return $qname;
00686                 }
00687         }
00688 
00696         function expandQname($qname){
00697                 // get element prefix
00698                 if(strpos($qname,':') && !ereg('^http://',$qname)){
00699                         // get unqualified name
00700                         $name = substr(strstr($qname,':'),1);
00701                         // get ns prefix
00702                         $prefix = substr($qname,0,strpos($qname,':'));
00703                         if(isset($this->namespaces[$prefix])){
00704                                 return $this->namespaces[$prefix].':'.$name;
00705                         } else {
00706                                 return $qname;
00707                         }
00708                 } else {
00709                         return $qname;
00710                 }
00711         }
00712 
00721         function getLocalPart($str){
00722                 if($sstr = strrchr($str,':')){
00723                         // get unqualified name
00724                         return substr( $sstr, 1 );
00725                 } else {
00726                         return $str;
00727                 }
00728         }
00729 
00738         function getPrefix($str){
00739                 if($pos = strrpos($str,':')){
00740                         // get prefix
00741                         return substr($str,0,$pos);
00742                 }
00743                 return false;
00744         }
00745 
00753         function getNamespaceFromPrefix($prefix){
00754                 if (isset($this->namespaces[$prefix])) {
00755                         return $this->namespaces[$prefix];
00756                 }
00757                 //$this->setError("No namespace registered for prefix '$prefix'");
00758                 return false;
00759         }
00760 
00769         function getPrefixFromNamespace($ns) {
00770                 foreach ($this->namespaces as $p => $n) {
00771                         if ($ns == $n || $ns == $p) {
00772                             $this->usedNamespaces[$p] = $n;
00773                                 return $p;
00774                         }
00775                 }
00776                 return false;
00777         }
00778 
00785         function getmicrotime() {
00786                 if (function_exists('gettimeofday')) {
00787                         $tod = gettimeofday();
00788                         $sec = $tod['sec'];
00789                         $usec = $tod['usec'];
00790                 } else {
00791                         $sec = time();
00792                         $usec = 0;
00793                 }
00794                 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
00795         }
00796 
00804     function varDump($data) {
00805                 ob_start();
00806                 var_dump($data);
00807                 $ret_val = ob_get_contents();
00808                 ob_end_clean();
00809                 return $ret_val;
00810         }
00811 }
00812 
00813 // XML Schema Datatype Helper Functions
00814 
00815 //xsd:dateTime helpers
00816 
00823 function timestamp_to_iso8601($timestamp,$utc=true){
00824         $datestr = date('Y-m-d\TH:i:sO',$timestamp);
00825         if($utc){
00826                 $eregStr =
00827                 '([0-9]{4})-'.  // centuries & years CCYY-
00828                 '([0-9]{2})-'.  // months MM-
00829                 '([0-9]{2})'.   // days DD
00830                 'T'.                    // separator T
00831                 '([0-9]{2}):'.  // hours hh:
00832                 '([0-9]{2}):'.  // minutes mm:
00833                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
00834                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00835 
00836                 if(ereg($eregStr,$datestr,$regs)){
00837                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
00838                 }
00839                 return false;
00840         } else {
00841                 return $datestr;
00842         }
00843 }
00844 
00851 function iso8601_to_timestamp($datestr){
00852         $eregStr =
00853         '([0-9]{4})-'.  // centuries & years CCYY-
00854         '([0-9]{2})-'.  // months MM-
00855         '([0-9]{2})'.   // days DD
00856         'T'.                    // separator T
00857         '([0-9]{2}):'.  // hours hh:
00858         '([0-9]{2}):'.  // minutes mm:
00859         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
00860         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00861         if(ereg($eregStr,$datestr,$regs)){
00862                 // not utc
00863                 if($regs[8] != 'Z'){
00864                         $op = substr($regs[8],0,1);
00865                         $h = substr($regs[8],1,2);
00866                         $m = substr($regs[8],strlen($regs[8])-2,2);
00867                         if($op == '-'){
00868                                 $regs[4] = $regs[4] + $h;
00869                                 $regs[5] = $regs[5] + $m;
00870                         } elseif($op == '+'){
00871                                 $regs[4] = $regs[4] - $h;
00872                                 $regs[5] = $regs[5] - $m;
00873                         }
00874                 }
00875                 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
00876         } else {
00877                 return false;
00878         }
00879 }
00880 
00888 function usleepWindows($usec)
00889 {
00890         $start = gettimeofday();
00891 
00892         do
00893         {
00894                 $stop = gettimeofday();
00895                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
00896                 + $stop['usec'] - $start['usec'];
00897         }
00898         while ($timePassed < $usec);
00899 }
00900 
00901 
00902 
00911 class soap_fault extends nusoap_base {
00917         var $faultcode;
00923         var $faultactor;
00929         var $faultstring;
00935         var $faultdetail;
00936 
00945         function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
00946                 parent::nusoap_base();
00947                 $this->faultcode = $faultcode;
00948                 $this->faultactor = $faultactor;
00949                 $this->faultstring = $faultstring;
00950                 $this->faultdetail = $faultdetail;
00951         }
00952 
00959         function serialize(){
00960                 $ns_string = '';
00961                 foreach($this->namespaces as $k => $v){
00962                         $ns_string .= "\n  xmlns:$k=\"$v\"";
00963                 }
00964                 $return_msg =
00965                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
00966                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
00967                                 '<SOAP-ENV:Body>'.
00968                                 '<SOAP-ENV:Fault>'.
00969                                         $this->serialize_val($this->faultcode, 'faultcode').
00970                                         $this->serialize_val($this->faultactor, 'faultactor').
00971                                         $this->serialize_val($this->faultstring, 'faultstring').
00972                                         $this->serialize_val($this->faultdetail, 'detail').
00973                                 '</SOAP-ENV:Fault>'.
00974                                 '</SOAP-ENV:Body>'.
00975                         '</SOAP-ENV:Envelope>';
00976                 return $return_msg;
00977         }
00978 }
00979 
00980 
00981 
00993 class XMLSchema extends nusoap_base  {
00994 
00995         // files
00996         var $schema = '';
00997         var $xml = '';
00998         // namespaces
00999         var $enclosingNamespaces;
01000         // schema info
01001         var $schemaInfo = array();
01002         var $schemaTargetNamespace = '';
01003         // types, elements, attributes defined by the schema
01004         var $attributes = array();
01005         var $complexTypes = array();
01006         var $complexTypeStack = array();
01007         var $currentComplexType = null;
01008         var $elements = array();
01009         var $elementStack = array();
01010         var $currentElement = null;
01011         var $simpleTypes = array();
01012         var $simpleTypeStack = array();
01013         var $currentSimpleType = null;
01014         // imports
01015         var $imports = array();
01016         // parser vars
01017         var $parser;
01018         var $position = 0;
01019         var $depth = 0;
01020         var $depth_array = array();
01021         var $message = array();
01022         var $defaultNamespace = array();
01023 
01032         function XMLSchema($schema='',$xml='',$namespaces=array()){
01033                 parent::nusoap_base();
01034                 $this->debug('xmlschema class instantiated, inside constructor');
01035                 // files
01036                 $this->schema = $schema;
01037                 $this->xml = $xml;
01038 
01039                 // namespaces
01040                 $this->enclosingNamespaces = $namespaces;
01041                 $this->namespaces = array_merge($this->namespaces, $namespaces);
01042 
01043                 // parse schema file
01044                 if($schema != ''){
01045                         $this->debug('initial schema file: '.$schema);
01046                         $this->parseFile($schema, 'schema');
01047                 }
01048 
01049                 // parse xml file
01050                 if($xml != ''){
01051                         $this->debug('initial xml file: '.$xml);
01052                         $this->parseFile($xml, 'xml');
01053                 }
01054 
01055         }
01056 
01065         function parseFile($xml,$type){
01066                 // parse xml file
01067                 if($xml != ""){
01068                         $xmlStr = @join("",@file($xml));
01069                         if($xmlStr == ""){
01070                                 $msg = 'Error reading XML from '.$xml;
01071                                 $this->setError($msg);
01072                                 $this->debug($msg);
01073                         return false;
01074                         } else {
01075                                 $this->debug("parsing $xml");
01076                                 $this->parseString($xmlStr,$type);
01077                                 $this->debug("done parsing $xml");
01078                         return true;
01079                         }
01080                 }
01081                 return false;
01082         }
01083 
01091         function parseString($xml,$type){
01092                 // parse xml string
01093                 if($xml != ""){
01094 
01095                 // Create an XML parser.
01096                 $this->parser = xml_parser_create();
01097                 // Set the options for parsing the XML data.
01098                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
01099 
01100                 // Set the object for the parser.
01101                 xml_set_object($this->parser, $this);
01102 
01103                 // Set the element handlers for the parser.
01104                         if($type == "schema"){
01105                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
01106                         xml_set_character_data_handler($this->parser,'schemaCharacterData');
01107                         } elseif($type == "xml"){
01108                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
01109                         xml_set_character_data_handler($this->parser,'xmlCharacterData');
01110                         }
01111 
01112                     // Parse the XML file.
01113                     if(!xml_parse($this->parser,$xml,true)){
01114                         // Display an error message.
01115                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
01116                                 xml_get_current_line_number($this->parser),
01117                                 xml_error_string(xml_get_error_code($this->parser))
01118                                 );
01119                                 $this->debug($errstr);
01120                                 $this->debug("XML payload:\n" . $xml);
01121                                 $this->setError($errstr);
01122                 }
01123 
01124                         xml_parser_free($this->parser);
01125                 } else{
01126                         $this->debug('no xml passed to parseString()!!');
01127                         $this->setError('no xml passed to parseString()!!');
01128                 }
01129         }
01130 
01139         function schemaStartElement($parser, $name, $attrs) {
01140 
01141                 // position in the total number of elements, starting from 0
01142                 $pos = $this->position++;
01143                 $depth = $this->depth++;
01144                 // set self as current value for this depth
01145                 $this->depth_array[$depth] = $pos;
01146                 $this->message[$pos] = array('cdata' => '');
01147                 if ($depth > 0) {
01148                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
01149                 } else {
01150                         $this->defaultNamespace[$pos] = false;
01151                 }
01152 
01153                 // get element prefix
01154                 if($prefix = $this->getPrefix($name)){
01155                         // get unqualified name
01156                         $name = $this->getLocalPart($name);
01157                 } else {
01158                 $prefix = '';
01159         }
01160 
01161         // loop thru attributes, expanding, and registering namespace declarations
01162         if(count($attrs) > 0){
01163                 foreach($attrs as $k => $v){
01164                 // if ns declarations, add to class level array of valid namespaces
01165                                 if(ereg("^xmlns",$k)){
01166                         //$this->xdebug("$k: $v");
01167                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
01168                         if($ns_prefix = substr(strrchr($k,':'),1)){
01169                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");
01170                                                 $this->namespaces[$ns_prefix] = $v;
01171                                         } else {
01172                                                 $this->defaultNamespace[$pos] = $v;
01173                                                 if (! $this->getPrefixFromNamespace($v)) {
01174                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
01175                                                 }
01176                                         }
01177                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
01178                                                 $this->XMLSchemaVersion = $v;
01179                                                 $this->namespaces['xsi'] = $v.'-instance';
01180                                         }
01181                                 }
01182                 }
01183                 foreach($attrs as $k => $v){
01184                 // expand each attribute
01185                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
01186                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
01187                         $eAttrs[$k] = $v;
01188                 }
01189                 $attrs = $eAttrs;
01190         } else {
01191                 $attrs = array();
01192         }
01193                 // find status, register data
01194                 switch($name){
01195                         case 'all':                     // (optional) compositor content for a complexType
01196                         case 'choice':
01197                         case 'group':
01198                         case 'sequence':
01199                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
01200                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
01201                                 //if($name == 'all' || $name == 'sequence'){
01202                                 //      $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01203                                 //}
01204                         break;
01205                         case 'attribute':       // complexType attribute
01206                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
01207                 $this->xdebug("parsing attribute:");
01208                 $this->appendDebug($this->varDump($attrs));
01209                                 if (!isset($attrs['form'])) {
01210                                         $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
01211                                 }
01212                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01213                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01214                                         if (!strpos($v, ':')) {
01215                                                 // no namespace in arrayType attribute value...
01216                                                 if ($this->defaultNamespace[$pos]) {
01217                                                         // ...so use the default
01218                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01219                                                 }
01220                                         }
01221                 }
01222                 if(isset($attrs['name'])){
01223                                         $this->attributes[$attrs['name']] = $attrs;
01224                                         $aname = $attrs['name'];
01225                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
01226                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01227                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01228                         } else {
01229                                 $aname = '';
01230                         }
01231                                 } elseif(isset($attrs['ref'])){
01232                                         $aname = $attrs['ref'];
01233                     $this->attributes[$attrs['ref']] = $attrs;
01234                                 }
01235 
01236                                 if($this->currentComplexType){  // This should *always* be
01237                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
01238                                 }
01239                                 // arrayType attribute
01240                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
01241                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01242                         $prefix = $this->getPrefix($aname);
01243                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
01244                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01245                                         } else {
01246                                                 $v = '';
01247                                         }
01248                     if(strpos($v,'[,]')){
01249                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
01250                     }
01251                     $v = substr($v,0,strpos($v,'[')); // clip the []
01252                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
01253                         $v = $this->XMLSchemaVersion.':'.$v;
01254                     }
01255                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
01256                                 }
01257                         break;
01258                         case 'complexContent':  // (optional) content for a complexType
01259                         break;
01260                         case 'complexType':
01261                                 array_push($this->complexTypeStack, $this->currentComplexType);
01262                                 if(isset($attrs['name'])){
01263                                         $this->xdebug('processing named complexType '.$attrs['name']);
01264                                         //$this->currentElement = false;
01265                                         $this->currentComplexType = $attrs['name'];
01266                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01267                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01268                                         // This is for constructs like
01269                                         //           <complexType name="ListOfString" base="soap:Array">
01270                                         //                <sequence>
01271                                         //                    <element name="string" type="xsd:string"
01272                                         //                        minOccurs="0" maxOccurs="unbounded" />
01273                                         //                </sequence>
01274                                         //            </complexType>
01275                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01276                                                 $this->xdebug('complexType is unusual array');
01277                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01278                                         } else {
01279                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01280                                         }
01281                                 }else{
01282                                         $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
01283                                         $this->currentComplexType = $this->currentElement . '_ContainedType';
01284                                         //$this->currentElement = false;
01285                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01286                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01287                                         // This is for constructs like
01288                                         //           <complexType name="ListOfString" base="soap:Array">
01289                                         //                <sequence>
01290                                         //                    <element name="string" type="xsd:string"
01291                                         //                        minOccurs="0" maxOccurs="unbounded" />
01292                                         //                </sequence>
01293                                         //            </complexType>
01294                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01295                                                 $this->xdebug('complexType is unusual array');
01296                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01297                                         } else {
01298                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01299                                         }
01300                                 }
01301                         break;
01302                         case 'element':
01303                                 array_push($this->elementStack, $this->currentElement);
01304                                 // elements defined as part of a complex type should
01305                                 // not really be added to $this->elements, but for some
01306                                 // reason, they are
01307                                 if (!isset($attrs['form'])) {
01308                                         $attrs['form'] = $this->schemaInfo['elementFormDefault'];
01309                                 }
01310                                 if(isset($attrs['type'])){
01311                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
01312                                         if (! $this->getPrefix($attrs['type'])) {
01313                                                 if ($this->defaultNamespace[$pos]) {
01314                                                         $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
01315                                                         $this->xdebug('used default namespace to make type ' . $attrs['type']);
01316                                                 }
01317                                         }
01318                                         // This is for constructs like
01319                                         //           <complexType name="ListOfString" base="soap:Array">
01320                                         //                <sequence>
01321                                         //                    <element name="string" type="xsd:string"
01322                                         //                        minOccurs="0" maxOccurs="unbounded" />
01323                                         //                </sequence>
01324                                         //            </complexType>
01325                                         if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
01326                                                 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
01327                                                 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
01328                                         }
01329                                         $this->currentElement = $attrs['name'];
01330                                         $this->elements[ $attrs['name'] ] = $attrs;
01331                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01332                                         $ename = $attrs['name'];
01333                                 } elseif(isset($attrs['ref'])){
01334                                         $this->xdebug("processing element as ref to ".$attrs['ref']);
01335                                         $this->currentElement = "ref to ".$attrs['ref'];
01336                                         $ename = $this->getLocalPart($attrs['ref']);
01337                                 } else {
01338                                         $this->xdebug("processing untyped element ".$attrs['name']);
01339                                         $this->currentElement = $attrs['name'];
01340                                         $this->elements[ $attrs['name'] ] = $attrs;
01341                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01342                                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
01343                                         $this->elements[ $attrs['name'] ]['type'] = $attrs['type'];
01344                                         $ename = $attrs['name'];
01345                                 }
01346                                 if(isset($ename) && $this->currentComplexType){
01347                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
01348                                 }
01349                         break;
01350                         case 'enumeration':     //      restriction value list member
01351                                 $this->xdebug('enumeration ' . $attrs['value']);
01352                                 if ($this->currentSimpleType) {
01353                                         $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
01354                                 } elseif ($this->currentComplexType) {
01355                                         $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
01356                                 }
01357                         break;
01358                         case 'extension':       // simpleContent or complexContent type extension
01359                                 $this->xdebug('extension ' . $attrs['base']);
01360                                 if ($this->currentComplexType) {
01361                                         $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
01362                                 }
01363                         break;
01364                         case 'import':
01365                             if (isset($attrs['schemaLocation'])) {
01366                                         //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
01367                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
01368                                 } else {
01369                                         //$this->xdebug('import namespace ' . $attrs['namespace']);
01370                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
01371                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
01372                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
01373                                         }
01374                                 }
01375                         break;
01376                         case 'list':    // simpleType value list
01377                         break;
01378                         case 'restriction':     // simpleType, simpleContent or complexContent value restriction
01379                                 $this->xdebug('restriction ' . $attrs['base']);
01380                                 if($this->currentSimpleType){
01381                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
01382                                 } elseif($this->currentComplexType){
01383                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
01384                                         if(strstr($attrs['base'],':') == ':Array'){
01385                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01386                                         }
01387                                 }
01388                         break;
01389                         case 'schema':
01390                                 $this->schemaInfo = $attrs;
01391                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
01392                                 if (isset($attrs['targetNamespace'])) {
01393                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];
01394                                 }
01395                                 if (!isset($attrs['elementFormDefault'])) {
01396                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';
01397                                 }
01398                                 if (!isset($attrs['attributeFormDefault'])) {
01399                                         $this->schemaInfo['attributeFormDefault'] = 'unqualified';
01400                                 }
01401                         break;
01402                         case 'simpleContent':   // (optional) content for a complexType
01403                         break;
01404                         case 'simpleType':
01405                                 array_push($this->simpleTypeStack, $this->currentSimpleType);
01406                                 if(isset($attrs['name'])){
01407                                         $this->xdebug("processing simpleType for name " . $attrs['name']);
01408                                         $this->currentSimpleType = $attrs['name'];
01409                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;
01410                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
01411                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
01412                                 } else {
01413                                         $this->xdebug('processing unnamed simpleType for element '.$this->currentElement);
01414                                         $this->currentSimpleType = $this->currentElement . '_ContainedType';
01415                                         //$this->currentElement = false;
01416                                         $this->simpleTypes[$this->currentSimpleType] = $attrs;
01417                                         $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
01418                                 }
01419                         break;
01420                         case 'union':   // simpleType type list
01421                         break;
01422                         default:
01423                                 //$this->xdebug("do not have anything to do for element $name");
01424                 }
01425         }
01426 
01434         function schemaEndElement($parser, $name) {
01435                 // bring depth down a notch
01436                 $this->depth--;
01437                 // position of current element is equal to the last value left in depth_array for my depth
01438                 if(isset($this->depth_array[$this->depth])){
01439                 $pos = $this->depth_array[$this->depth];
01440         }
01441                 // get element prefix
01442                 if ($prefix = $this->getPrefix($name)){
01443                         // get unqualified name
01444                         $name = $this->getLocalPart($name);
01445                 } else {
01446                 $prefix = '';
01447         }
01448                 // move on...
01449                 if($name == 'complexType'){
01450                         $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
01451                         $this->currentComplexType = array_pop($this->complexTypeStack);
01452                         //$this->currentElement = false;
01453                 }
01454                 if($name == 'element'){
01455                         $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
01456                         $this->currentElement = array_pop($this->elementStack);
01457                 }
01458                 if($name == 'simpleType'){
01459                         $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
01460                         $this->currentSimpleType = array_pop($this->simpleTypeStack);
01461                 }
01462         }
01463 
01471         function schemaCharacterData($parser, $data){
01472                 $pos = $this->depth_array[$this->depth - 1];
01473                 $this->message[$pos]['cdata'] .= $data;
01474         }
01475 
01481         function serializeSchema(){
01482 
01483                 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
01484                 $xml = '';
01485                 // imports
01486                 if (sizeof($this->imports) > 0) {
01487                         foreach($this->imports as $ns => $list) {
01488                                 foreach ($list as $ii) {
01489                                         if ($ii['location'] != '') {
01490                                                 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
01491                                         } else {
01492                                                 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
01493                                         }
01494                                 }
01495                         }
01496                 }
01497                 // complex types
01498                 foreach($this->complexTypes as $typeName => $attrs){
01499                         $contentStr = '';
01500                         // serialize child elements
01501                         if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
01502                                 foreach($attrs['elements'] as $element => $eParts){
01503                                         if(isset($eParts['ref'])){
01504                                                 $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
01505                                         } else {
01506                                                 $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
01507                                                 foreach ($eParts as $aName => $aValue) {
01508                                                         // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
01509                                                         if ($aName != 'name' && $aName != 'type') {
01510                                                                 $contentStr .= " $aName=\"$aValue\"";
01511                                                         }
01512                                                 }
01513                                                 $contentStr .= "/>\n";
01514                                         }
01515                                 }
01516                                 // compositor wraps elements
01517                                 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
01518                                         $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
01519                                 }
01520                         }
01521                         // attributes
01522                         if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
01523                                 foreach($attrs['attrs'] as $attr => $aParts){
01524                                         $contentStr .= "    <$schemaPrefix:attribute";
01525                                         foreach ($aParts as $a => $v) {
01526                                                 if ($a == 'ref' || $a == 'type') {
01527                                                         $contentStr .= " $a=\"".$this->contractQName($v).'"';
01528                                                 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
01529                                                         $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
01530                                                         $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
01531                                                 } else {
01532                                                         $contentStr .= " $a=\"$v\"";
01533                                                 }
01534                                         }
01535                                         $contentStr .= "/>\n";
01536                                 }
01537                         }
01538                         // if restriction
01539                         if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
01540                                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
01541                                 // complex or simple content
01542                                 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
01543                                         $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
01544                                 }
01545                         }
01546                         // finalize complex type
01547                         if($contentStr != ''){
01548                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
01549                         } else {
01550                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
01551                         }
01552                         $xml .= $contentStr;
01553                 }
01554                 // simple types
01555                 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
01556                         foreach($this->simpleTypes as $typeName => $eParts){
01557                                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n";
01558                                 if (isset($eParts['enumeration'])) {
01559                                         foreach ($eParts['enumeration'] as $e) {
01560                                                 $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
01561                                         }
01562                                 }
01563                                 $xml .= " </$schemaPrefix:simpleType>";
01564                         }
01565                 }
01566                 // elements
01567                 if(isset($this->elements) && count($this->elements) > 0){
01568                         foreach($this->elements as $element => $eParts){
01569                                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
01570                         }
01571                 }
01572                 // attributes
01573                 if(isset($this->attributes) && count($this->attributes) > 0){
01574                         foreach($this->attributes as $attr => $aParts){
01575                                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
01576                         }
01577                 }
01578                 // finish 'er up
01579                 $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
01580                 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
01581                         $el .= " xmlns:$nsp=\"$ns\"\n";
01582                 }
01583                 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
01584                 return $xml;
01585         }
01586 
01593         function xdebug($string){
01594                 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
01595         }
01596 
01609         function getPHPType($type,$ns){
01610                 if(isset($this->typemap[$ns][$type])){
01611                         //print "found type '$type' and ns $ns in typemap<br>";
01612                         return $this->typemap[$ns][$type];
01613                 } elseif(isset($this->complexTypes[$type])){
01614                         //print "getting type '$type' and ns $ns from complexTypes array<br>";
01615                         return $this->complexTypes[$type]['phpType'];
01616                 }
01617                 return false;
01618         }
01619 
01642         function getTypeDef($type){
01643                 //$this->debug("in getTypeDef for type $type");
01644                 if(isset($this->complexTypes[$type])){
01645                         $this->xdebug("in getTypeDef, found complexType $type");
01646                         return $this->complexTypes[$type];
01647                 } elseif(isset($this->simpleTypes[$type])){
01648                         $this->xdebug("in getTypeDef, found simpleType $type");
01649                         if (!isset($this->simpleTypes[$type]['phpType'])) {
01650                                 // get info for type to tack onto the simple type
01651                                 // TODO: can this ever really apply (i.e. what is a simpleType really?)
01652                                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
01653                                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
01654                                 $etype = $this->getTypeDef($uqType);
01655                                 if ($etype) {
01656                                         $this->xdebug("in getTypeDef, found type for simpleType $type:");
01657                                         $this->xdebug($this->varDump($etype));
01658                                         if (isset($etype['phpType'])) {
01659                                                 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
01660                                         }
01661                                         if (isset($etype['elements'])) {
01662                                                 $this->simpleTypes[$type]['elements'] = $etype['elements'];
01663                                         }
01664                                 }
01665                         }
01666                         return $this->simpleTypes[$type];
01667                 } elseif(isset($this->elements[$type])){
01668                         $this->xdebug("in getTypeDef, found element $type");
01669                         if (!isset($this->elements[$type]['phpType'])) {
01670                                 // get info for type to tack onto the element
01671                                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
01672                                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
01673                                 $etype = $this->getTypeDef($uqType);
01674                                 if ($etype) {
01675                                         $this->xdebug("in getTypeDef, found type for element $type:");
01676                                         $this->xdebug($this->varDump($etype));
01677                                         if (isset($etype['phpType'])) {
01678                                                 $this->elements[$type]['phpType'] = $etype['phpType'];
01679                                         }
01680                                         if (isset($etype['elements'])) {
01681                                                 $this->elements[$type]['elements'] = $etype['elements'];
01682                                         }
01683                                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
01684                                         $this->xdebug("in getTypeDef, element $type is an XSD type");
01685                                         $this->elements[$type]['phpType'] = 'scalar';
01686                                 }
01687                         }
01688                         return $this->elements[$type];
01689                 } elseif(isset($this->attributes[$type])){
01690                         $this->xdebug("in getTypeDef, found attribute $type");
01691                         return $this->attributes[$type];
01692                 } elseif (ereg('_ContainedType$', $type)) {
01693                         $this->xdebug("in getTypeDef, have an untyped element $type");
01694                         $typeDef['typeClass'] = 'simpleType';
01695                         $typeDef['phpType'] = 'scalar';
01696                         $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
01697                         return $typeDef;
01698                 }
01699                 $this->xdebug("in getTypeDef, did not find $type");
01700                 return false;
01701         }
01702 
01711     function serializeTypeDef($type){
01712         //print "in sTD() for type $type<br>";
01713         if($typeDef = $this->getTypeDef($type)){
01714                 $str .= '<'.$type;
01715             if(is_array($typeDef['attrs'])){
01716                 foreach($attrs as $attName => $data){
01717                     $str .= " $attName=\"{type = ".$data['type']."}\"";
01718                 }
01719             }
01720             $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
01721             if(count($typeDef['elements']) > 0){
01722                 $str .= ">";
01723                 foreach($typeDef['elements'] as $element => $eData){
01724                     $str .= $this->serializeTypeDef($element);
01725                 }
01726                 $str .= "</$type>";
01727             } elseif($typeDef['typeClass'] == 'element') {
01728                 $str .= "></$type>";
01729             } else {
01730                 $str .= "/>";
01731             }
01732                         return $str;
01733         }
01734         return false;
01735     }
01736 
01747         function typeToForm($name,$type){
01748                 // get typedef
01749                 if($typeDef = $this->getTypeDef($type)){
01750                         // if struct
01751                         if($typeDef['phpType'] == 'struct'){
01752                                 $buffer .= '<table>';
01753                                 foreach($typeDef['elements'] as $child => $childDef){
01754                                         $buffer .= "
01755                                         <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
01756                                         <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
01757                                 }
01758                                 $buffer .= '</table>';
01759                         // if array
01760                         } elseif($typeDef['phpType'] == 'array'){
01761                                 $buffer .= '<table>';
01762                                 for($i=0;$i < 3; $i++){
01763                                         $buffer .= "
01764                                         <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
01765                                         <td><input type='text' name='parameters[".$name."][]'></td></tr>";
01766                                 }
01767                                 $buffer .= '</table>';
01768                         // if scalar
01769                         } else {
01770                                 $buffer .= "<input type='text' name='parameters[$name]'>";
01771                         }
01772                 } else {
01773                         $buffer .= "<input type='text' name='parameters[$name]'>";
01774                 }
01775                 return $buffer;
01776         }
01777 
01819         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
01820                 $this->complexTypes[$name] = array(
01821             'name'              => $name,
01822             'typeClass' => $typeClass,
01823             'phpType'   => $phpType,
01824                 'compositor'=> $compositor,
01825             'restrictionBase' => $restrictionBase,
01826                 'elements'      => $elements,
01827             'attrs'             => $attrs,
01828             'arrayType' => $arrayType
01829                 );
01830 
01831                 $this->xdebug("addComplexType $name:");
01832                 $this->appendDebug($this->varDump($this->complexTypes[$name]));
01833         }
01834 
01847         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
01848                 $this->simpleTypes[$name] = array(
01849             'name'                      => $name,
01850             'typeClass'         => $typeClass,
01851             'phpType'           => $phpType,
01852             'type'                      => $restrictionBase,
01853             'enumeration'       => $enumeration
01854                 );
01855 
01856                 $this->xdebug("addSimpleType $name:");
01857                 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
01858         }
01859 
01867         function addElement($attrs) {
01868                 if (! $this->getPrefix($attrs['type'])) {
01869                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
01870                 }
01871                 $this->elements[ $attrs['name'] ] = $attrs;
01872                 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01873 
01874                 $this->xdebug("addElement " . $attrs['name']);
01875                 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
01876         }
01877 }
01878 
01879 
01880 
01892 class soapval extends nusoap_base {
01899         var $name;
01906         var $type;
01913         var $value;
01920         var $element_ns;
01927         var $type_ns;
01934         var $attributes;
01935 
01947         function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
01948                 parent::nusoap_base();
01949                 $this->name = $name;
01950                 $this->type = $type;
01951                 $this->value = $value;
01952                 $this->element_ns = $element_ns;
01953                 $this->type_ns = $type_ns;
01954                 $this->attributes = $attributes;
01955     }
01956 
01964         function serialize($use='encoded') {
01965                 return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
01966     }
01967 
01974         function decode(){
01975                 return $this->value;
01976         }
01977 }
01978 
01979 
01980 
01989 class soap_transport_http extends nusoap_base {
01990 
01991         var $url = '';
01992         var $uri = '';
01993         var $digest_uri = '';
01994         var $scheme = '';
01995         var $host = '';
01996         var $port = '';
01997         var $path = '';
01998         var $request_method = 'POST';
01999         var $protocol_version = '1.0';
02000         var $encoding = '';
02001         var $outgoing_headers = array();
02002         var $incoming_headers = array();
02003         var $incoming_cookies = array();
02004         var $outgoing_payload = '';
02005         var $incoming_payload = '';
02006         var $useSOAPAction = true;
02007         var $persistentConnection = false;
02008         var $ch = false;        // cURL handle
02009         var $username = '';
02010         var $password = '';
02011         var $authtype = '';
02012         var $digestRequest = array();
02013         var $certRequest = array();     // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional)
02014                                                                 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
02015                                                                 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
02016                                                                 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
02017                                                                 // passphrase: SSL key password/passphrase
02018                                                                 // verifypeer: default is 1
02019                                                                 // verifyhost: default is 1
02020 
02024         function soap_transport_http($url){
02025                 parent::nusoap_base();
02026                 $this->setURL($url);
02027                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
02028                 $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
02029                 $this->debug('set User-Agent: ' . $this->outgoing_headers['User-Agent']);
02030         }
02031 
02032         function setURL($url) {
02033                 $this->url = $url;
02034 
02035                 $u = parse_url($url);
02036                 foreach($u as $k => $v){
02037                         $this->debug("$k = $v");
02038                         $this->$k = $v;
02039                 }
02040 
02041                 // add any GET params to path
02042                 if(isset($u['query']) && $u['query'] != ''){
02043             $this->path .= '?' . $u['query'];
02044                 }
02045 
02046                 // set default port
02047                 if(!isset($u['port'])){
02048                         if($u['scheme'] == 'https'){
02049                                 $this->port = 443;
02050                         } else {
02051                                 $this->port = 80;
02052                         }
02053                 }
02054 
02055                 $this->uri = $this->path;
02056                 $this->digest_uri = $this->uri;
02057 
02058                 // build headers
02059                 if (!isset($u['port'])) {
02060                         $this->outgoing_headers['Host'] = $this->host;
02061                 } else {
02062                         $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
02063                 }
02064                 $this->debug('set Host: ' . $this->outgoing_headers['Host']);
02065 
02066                 if (isset($u['user']) && $u['user'] != '') {
02067                         $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
02068                 }
02069         }
02070 
02071         function connect($connection_timeout=0,$response_timeout=30){
02072                 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
02073                 // "regular" socket.
02074                 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
02075                 //       loaded), and until PHP5 stream_get_wrappers is not available.
02076 //              if ($this->scheme == 'https') {
02077 //                      if (version_compare(phpversion(), '4.3.0') >= 0) {
02078 //                              if (extension_loaded('openssl')) {
02079 //                                      $this->scheme = 'ssl';
02080 //                                      $this->debug('Using SSL over OpenSSL');
02081 //                              }
02082 //                      }
02083 //              }
02084                 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
02085           if ($this->scheme == 'http' || $this->scheme == 'ssl') {
02086                 // use persistent connection
02087                 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
02088                         if (!feof($this->fp)) {
02089                                 $this->debug('Re-use persistent connection');
02090                                 return true;
02091                         }
02092                         fclose($this->fp);
02093                         $this->debug('Closed persistent connection at EOF');
02094                 }
02095 
02096                 // munge host if using OpenSSL
02097                 if ($this->scheme == 'ssl') {
02098                         $host = 'ssl://' . $this->host;
02099                 } else {
02100                         $host = $this->host;
02101                 }
02102                 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
02103 
02104                 // open socket
02105                 if($connection_timeout > 0){
02106                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
02107                 } else {
02108                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
02109                 }
02110 
02111                 // test pointer
02112                 if(!$this->fp) {
02113                         $msg = 'Couldn\'t open socket connection to server ' . $this->url;
02114                         if ($this->errno) {
02115                                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
02116                         } else {
02117                                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';
02118                         }
02119                         $this->debug($msg);
02120                         $this->setError($msg);
02121                         return false;
02122                 }
02123 
02124                 // set response timeout
02125                 $this->debug('set response timeout to ' . $response_timeout);
02126                 socket_set_timeout( $this->fp, $response_timeout);
02127 
02128                 $this->debug('socket connected');
02129                 return true;
02130           } else if ($this->scheme == 'https') {
02131                 if (!extension_loaded('curl')) {
02132                         $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
02133                         return false;
02134                 }
02135                 $this->debug('connect using https');
02136                 // init CURL
02137                 $this->ch = curl_init();
02138                 // set url
02139                 $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
02140                 // add path
02141                 $hostURL .= $this->path;
02142                 curl_setopt($this->ch, CURLOPT_URL, $hostURL);
02143                 // follow location headers (re-directs)
02144                 curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1);
02145                 // ask for headers in the response output
02146                 curl_setopt($this->ch, CURLOPT_HEADER, 1);
02147                 // ask for the response output as the return value
02148                 curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
02149                 // encode
02150                 // We manage this ourselves through headers and encoding
02151 //              if(function_exists('gzuncompress')){
02152 //                      curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
02153 //              }
02154                 // persistent connection
02155                 if ($this->persistentConnection) {
02156                         // The way we send data, we cannot use persistent connections, since
02157                         // there will be some "junk" at the end of our request.
02158                         //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
02159                         $this->persistentConnection = false;
02160                         $this->outgoing_headers['Connection'] = 'close';
02161                         $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
02162                 }
02163                 // set timeout
02164                 if ($connection_timeout != 0) {
02165                         curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
02166                 }
02167                 // TODO: cURL has added a connection timeout separate from the response timeout
02168                 //if ($connection_timeout != 0) {
02169                 //      curl_setopt($this->ch, CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
02170                 //}
02171                 //if ($response_timeout != 0) {
02172                 //      curl_setopt($this->ch, CURLOPT_TIMEOUT, $response_timeout);
02173                 //}
02174 
02175                 // recent versions of cURL turn on peer/host checking by default,
02176                 // while PHP binaries are not compiled with a default location for the
02177                 // CA cert bundle, so disable peer/host checking.
02178 //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
02179                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
02180                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
02181 
02182                 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
02183                 if ($this->authtype == 'certificate') {
02184                         if (isset($this->certRequest['cainfofile'])) {
02185                                 curl_setopt($this->ch, CURLOPT_CAINFO, $this->certRequest['cainfofile']);
02186                         }
02187                         if (isset($this->certRequest['verifypeer'])) {
02188                                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
02189                         } else {
02190                                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
02191                         }
02192                         if (isset($this->certRequest['verifyhost'])) {
02193                                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
02194                         } else {
02195                                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
02196                         }
02197                         if (isset($this->certRequest['sslcertfile'])) {
02198                                 curl_setopt($this->ch, CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
02199                         }
02200                         if (isset($this->certRequest['sslkeyfile'])) {
02201                                 curl_setopt($this->ch, CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
02202                         }
02203                         if (isset($this->certRequest['passphrase'])) {
02204                                 curl_setopt($this->ch, CURLOPT_SSLKEYPASSWD , $this->certRequest['passphrase']);
02205                         }
02206                 }
02207                 $this->debug('cURL connection set up');
02208                 return true;
02209           } else {
02210                 $this->setError('Unknown scheme ' . $this->scheme);
02211                 $this->debug('Unknown scheme ' . $this->scheme);
02212                 return false;
02213           }
02214         }
02215 
02226         function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
02227 
02228                 $this->debug('entered send() with data of length: '.strlen($data));
02229 
02230                 $this->tryagain = true;
02231                 $tries = 0;
02232                 while ($this->tryagain) {
02233                         $this->tryagain = false;
02234                         if ($tries++ < 2) {
02235                                 // make connnection
02236                                 if (!$this->connect($timeout, $response_timeout)){
02237                                         return false;
02238                                 }
02239 
02240                                 // send request
02241                                 if (!$this->sendRequest($data, $cookies)){
02242                                         return false;
02243                                 }
02244 
02245                                 // get response
02246                                 $respdata = $this->getResponse();
02247                         } else {
02248                                 $this->setError('Too many tries to get an OK response');
02249                         }
02250                 }
02251                 $this->debug('end of send()');
02252                 return $respdata;
02253         }
02254 
02255 
02266         function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
02267                 return $this->send($data, $timeout, $response_timeout, $cookies);
02268         }
02269 
02280         function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
02281                 $this->debug("Set credentials for authtype $authtype");
02282                 // cf. RFC 2617
02283                 if ($authtype == 'basic') {
02284                         $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode(str_replace(':','',$username).':'.$password);
02285                 } elseif ($authtype == 'digest') {
02286                         if (isset($digestRequest['nonce'])) {
02287                                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
02288 
02289                                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
02290 
02291                                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
02292                                 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
02293 
02294                                 // H(A1) = MD5(A1)
02295                                 $HA1 = md5($A1);
02296 
02297                                 // A2 = Method ":" digest-uri-value
02298                                 $A2 = 'POST:' . $this->digest_uri;
02299 
02300                                 // H(A2)
02301                                 $HA2 =  md5($A2);
02302 
02303                                 // KD(secret, data) = H(concat(secret, ":", data))
02304                                 // if qop == auth:
02305                                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
02306                                 //                              ":" nc-value
02307                                 //                              ":" unq(cnonce-value)
02308                                 //                              ":" unq(qop-value)
02309                                 //                              ":" H(A2)
02310                                 //                            ) <">
02311                                 // if qop is missing,
02312                                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
02313 
02314                                 $unhashedDigest = '';
02315                                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
02316                                 $cnonce = $nonce;
02317                                 if ($digestRequest['qop'] != '') {
02318                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
02319                                 } else {
02320                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
02321                                 }
02322 
02323                                 $hashedDigest = md5($unhashedDigest);
02324 
02325                                 $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"';
02326                         }
02327                 } elseif ($authtype == 'certificate') {
02328                         $this->certRequest = $certRequest;
02329                 }
02330                 $this->username = $username;
02331                 $this->password = $password;
02332                 $this->authtype = $authtype;
02333                 $this->digestRequest = $digestRequest;
02334 
02335                 if (isset($this->outgoing_headers['Authorization'])) {
02336                         $this->debug('set Authorization: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
02337                 } else {
02338                         $this->debug('Authorization header not set');
02339                 }
02340         }
02341 
02348         function setSOAPAction($soapaction) {
02349                 $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
02350                 $this->debug('set SOAPAction: ' . $this->outgoing_headers['SOAPAction']);
02351         }
02352 
02359         function setEncoding($enc='gzip, deflate') {
02360                 if (function_exists('gzdeflate')) {
02361                         $this->protocol_version = '1.1';
02362                         $this->outgoing_headers['Accept-Encoding'] = $enc;
02363                         $this->debug('set Accept-Encoding: ' . $this->outgoing_headers['Accept-Encoding']);
02364                         if (!isset($this->outgoing_headers['Connection'])) {
02365                                 $this->outgoing_headers['Connection'] = 'close';
02366                                 $this->persistentConnection = false;
02367                                 $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
02368                         }
02369                         set_magic_quotes_runtime(0);
02370                         // deprecated
02371                         $this->encoding = $enc;
02372                 }
02373         }
02374 
02384         function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
02385                 $this->uri = $this->url;
02386                 $this->host = $proxyhost;
02387                 $this->port = $proxyport;
02388                 if ($proxyusername != '' && $proxypassword != '') {
02389                         $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
02390                         $this->debug('set Proxy-Authorization: ' . $this->outgoing_headers['Proxy-Authorization']);
02391                 }
02392         }
02393 
02404         function decodeChunked($buffer, $lb){
02405                 // length := 0
02406                 $length = 0;
02407                 $new = '';
02408 
02409                 // read chunk-size, chunk-extension (if any) and CRLF
02410                 // get the position of the linebreak
02411                 $chunkend = strpos($buffer, $lb);
02412                 if ($chunkend == FALSE) {
02413                         $this->debug('no linebreak found in decodeChunked');
02414                         return $new;
02415                 }
02416                 $temp = substr($buffer,0,$chunkend);
02417                 $chunk_size = hexdec( trim($temp) );
02418                 $chunkstart = $chunkend + strlen($lb);
02419                 // while (chunk-size > 0) {
02420                 while ($chunk_size > 0) {
02421                         $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
02422                         $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
02423 
02424                         // Just in case we got a broken connection
02425                         if ($chunkend == FALSE) {
02426                             $chunk = substr($buffer,$chunkstart);
02427                                 // append chunk-data to entity-body
02428                         $new .= $chunk;
02429                             $length += strlen($chunk);
02430                             break;
02431                         }
02432 
02433                         // read chunk-data and CRLF
02434                         $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
02435                         // append chunk-data to entity-body
02436                         $new .= $chunk;
02437                         // length := length + chunk-size
02438                         $length += strlen($chunk);
02439                         // read chunk-size and CRLF
02440                         $chunkstart = $chunkend + strlen($lb);
02441 
02442                         $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
02443                         if ($chunkend == FALSE) {
02444                                 break; //Just in case we got a broken connection
02445                         }
02446                         $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
02447                         $chunk_size = hexdec( trim($temp) );
02448                         $chunkstart = $chunkend;
02449                 }
02450                 return $new;
02451         }
02452 
02453         /*
02454          *      Writes payload, including HTTP headers, to $this->outgoing_payload.
02455          */
02456         function buildPayload($data, $cookie_str = '') {
02457                 // add content-length header
02458                 $this->outgoing_headers['Content-Length'] = strlen($data);
02459                 $this->debug('set Content-Length: ' . $this->outgoing_headers['Content-Length']);
02460 
02461                 // start building outgoing payload:
02462                 $req = "$this->request_method $this->uri HTTP/$this->protocol_version";
02463                 $this->debug("HTTP request: $req");
02464                 $this->outgoing_payload = "$req\r\n";
02465 
02466                 // loop thru headers, serializing
02467                 foreach($this->outgoing_headers as $k => $v){
02468                         $hdr = $k.': '.$v;
02469                         $this->debug("HTTP header: $hdr");
02470                         $this->outgoing_payload .= "$hdr\r\n";
02471                 }
02472 
02473                 // add any cookies
02474                 if ($cookie_str != '') {
02475                         $hdr = 'Cookie: '.$cookie_str;
02476                         $this->debug("HTTP header: $hdr");
02477                         $this->outgoing_payload .= "$hdr\r\n";
02478                 }
02479 
02480                 // header/body separator
02481                 $this->outgoing_payload .= "\r\n";
02482 
02483                 // add data
02484                 $this->outgoing_payload .= $data;
02485         }
02486 
02487         function sendRequest($data, $cookies = NULL) {
02488                 // build cookie string
02489                 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
02490 
02491                 // build payload
02492                 $this->buildPayload($data, $cookie_str);
02493 
02494           if ($this->scheme == 'http' || $this->scheme == 'ssl') {
02495                 // send payload
02496                 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
02497                         $this->setError('couldn\'t write message data to socket');
02498                         $this->debug('couldn\'t write message data to socket');
02499                         return false;
02500                 }
02501                 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
02502                 return true;
02503           } else if ($this->scheme == 'https') {
02504                 // set payload
02505                 // TODO: cURL does say this should only be the verb, and in fact it
02506                 // turns out that the URI and HTTP version are appended to this, which
02507                 // some servers refuse to work with
02508                 //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
02509                 foreach($this->outgoing_headers as $k => $v){
02510                         $curl_headers[] = "$k: $v";
02511                 }
02512                 if ($cookie_str != '') {
02513                         $curl_headers[] = 'Cookie: ' . $cookie_str;
02514                 }
02515                 curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
02516                 if ($this->request_method == "POST") {
02517                         curl_setopt($this->ch, CURLOPT_POST, 1);
02518                         curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
02519                 } else {
02520                 }
02521                 $this->debug('set cURL payload');
02522                 return true;
02523           }
02524         }
02525 
02526         function getResponse(){
02527                 $this->incoming_payload = '';
02528 
02529           if ($this->scheme == 'http' || $this->scheme == 'ssl') {
02530             // loop until headers have been retrieved
02531             $data = '';
02532             while (!isset($lb)){
02533 
02534                         // We might EOF during header read.
02535                         if(feof($this->fp)) {
02536                                 $this->incoming_payload = $data;
02537                                 $this->debug('found no headers before EOF after length ' . strlen($data));
02538                                 $this->debug("received before EOF:\n" . $data);
02539                                 $this->setError('server failed to send headers');
02540                                 return false;
02541                         }
02542 
02543                         $tmp = fgets($this->fp, 256);
02544                         $tmplen = strlen($tmp);
02545                         $this->debug("read line of $tmplen bytes: " . trim($tmp));
02546 
02547                         if ($tmplen == 0) {
02548                                 $this->incoming_payload = $data;
02549                                 $this->debug('socket read of headers timed out after length ' . strlen($data));
02550                                 $this->debug("read before timeout: " . $data);
02551                                 $this->setError('socket read of headers timed out');
02552                                 return false;
02553                         }
02554 
02555                         $data .= $tmp;
02556                         $pos = strpos($data,"\r\n\r\n");
02557                         if($pos > 1){
02558                                 $lb = "\r\n";
02559                         } else {
02560                                 $pos = strpos($data,"\n\n");
02561                                 if($pos > 1){
02562                                         $lb = "\n";
02563                                 }
02564                         }
02565                         // remove 100 header
02566                         if(isset($lb) && ereg('^HTTP/1.1 100',$data)){
02567                                 unset($lb);
02568                                 $data = '';
02569                         }//
02570                 }
02571                 // store header data
02572                 $this->incoming_payload .= $data;
02573                 $this->debug('found end of headers after length ' . strlen($data));
02574                 // process headers
02575                 $header_data = trim(substr($data,0,$pos));
02576                 $header_array = explode($lb,$header_data);
02577                 $this->incoming_headers = array();
02578                 $this->incoming_cookies = array();
02579                 foreach($header_array as $header_line){
02580                         $arr = explode(':',$header_line, 2);
02581                         if(count($arr) > 1){
02582                                 $header_name = strtolower(trim($arr[0]));
02583                                 $this->incoming_headers[$header_name] = trim($arr[1]);
02584                                 if ($header_name == 'set-cookie') {
02585                                         // TODO: allow multiple cookies from parseCookie
02586                                         $cookie = $this->parseCookie(trim($arr[1]));
02587                                         if ($cookie) {
02588                                                 $this->incoming_cookies[] = $cookie;
02589                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
02590                                         } else {
02591                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
02592                                         }
02593                         }
02594                         } else if (isset($header_name)) {
02595                                 // append continuation line to previous header
02596                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
02597                         }
02598                 }
02599 
02600                 // loop until msg has been received
02601                 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
02602                         $content_length =  2147483647;  // ignore any content-length header
02603                         $chunked = true;
02604                         $this->debug("want to read chunked content");
02605                 } elseif (isset($this->incoming_headers['content-length'])) {
02606                         $content_length = $this->incoming_headers['content-length'];
02607                         $chunked = false;
02608                         $this->debug("want to read content of length $content_length");
02609                 } else {
02610                         $content_length =  2147483647;
02611                         $chunked = false;
02612                         $this->debug("want to read content to EOF");
02613                 }
02614                 $data = '';
02615                 do {
02616                         if ($chunked) {
02617                                 $tmp = fgets($this->fp, 256);
02618                                 $tmplen = strlen($tmp);
02619                                 $this->debug("read chunk line of $tmplen bytes");
02620                                 if ($tmplen == 0) {
02621                                         $this->incoming_payload = $data;
02622                                         $this->debug('socket read of chunk length timed out after length ' . strlen($data));
02623                                         $this->debug("read before timeout:\n" . $data);
02624                                         $this->setError('socket read of chunk length timed out');
02625                                         return false;
02626                                 }
02627                                 $content_length = hexdec(trim($tmp));
02628                                 $this->debug("chunk length $content_length");
02629                         }
02630                         $strlen = 0;
02631                     while (($strlen < $content_length) && (!feof($this->fp))) {
02632                         $readlen = min(8192, $content_length - $strlen);
02633                                 $tmp = fread($this->fp, $readlen);
02634                                 $tmplen = strlen($tmp);
02635                                 $this->debug("read buffer of $tmplen bytes");
02636                                 if (($tmplen == 0) && (!feof($this->fp))) {
02637                                         $this->incoming_payload = $data;
02638                                         $this->debug('socket read of body timed out after length ' . strlen($data));
02639                                         $this->debug("read before timeout:\n" . $data);
02640                                         $this->setError('socket read of body timed out');
02641                                         return false;
02642                                 }
02643                                 $strlen += $tmplen;
02644                                 $data .= $tmp;
02645                         }
02646                         if ($chunked && ($content_length > 0)) {
02647                                 $tmp = fgets($this->fp, 256);
02648                                 $tmplen = strlen($tmp);
02649                                 $this->debug("read chunk terminator of $tmplen bytes");
02650                                 if ($tmplen == 0) {
02651                                         $this->incoming_payload = $data;
02652                                         $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
02653                                         $this->debug("read before timeout:\n" . $data);
02654                                         $this->setError('socket read of chunk terminator timed out');
02655                                         return false;
02656                                 }
02657                         }
02658                 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
02659                 if (feof($this->fp)) {
02660                         $this->debug('read to EOF');
02661                 }
02662                 $this->debug('read body of length ' . strlen($data));
02663                 $this->incoming_payload .= $data;
02664                 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
02665 
02666                 // close filepointer
02667                 if(
02668                         (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
02669                         (! $this->persistentConnection) || feof($this->fp)){
02670                         fclose($this->fp);
02671                         $this->fp = false;
02672                         $this->debug('closed socket');
02673                 }
02674 
02675                 // connection was closed unexpectedly
02676                 if($this->incoming_payload == ''){
02677                         $this->setError('no response from server');
02678                         return false;
02679                 }
02680 
02681                 // decode transfer-encoding
02682 //              if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
02683 //                      if(!$data = $this->decodeChunked($data, $lb)){
02684 //                              $this->setError('Decoding of chunked data failed');
02685 //                              return false;
02686 //                      }
02687                         //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
02688                         // set decoded payload
02689 //                      $this->incoming_payload = $header_data.$lb.$lb.$data;
02690 //              }
02691 
02692           } else if ($this->scheme == 'https') {
02693                 // send and receive
02694                 $this->debug('send and receive with cURL');
02695                 $this->incoming_payload = curl_exec($this->ch);
02696                 $data = $this->incoming_payload;
02697 
02698         $cErr = curl_error($this->ch);
02699                 if ($cErr != '') {
02700                 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
02701                 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
02702                         foreach(curl_getinfo($this->ch) as $k => $v){
02703                                 $err .= "$k: $v<br>";
02704                         }
02705                         $this->debug($err);
02706                         $this->setError($err);
02707                         curl_close($this->ch);
02708                 return false;
02709                 } else {
02710                         //echo '<pre>';
02711                         //var_dump(curl_getinfo($this->ch));
02712                         //echo '</pre>';
02713                 }
02714                 // close curl
02715                 $this->debug('No cURL error, closing cURL');
02716                 curl_close($this->ch);
02717 
02718                 // remove 100 header(s)
02719                 while (ereg('^HTTP/1.1 100',$data)) {
02720                         if ($pos = strpos($data,"\r\n\r\n")) {
02721                                 $data = ltrim(substr($data,$pos));
02722                         } elseif($pos = strpos($data,"\n\n") ) {
02723                                 $data = ltrim(substr($data,$pos));
02724                         }
02725                 }
02726 
02727                 // separate content from HTTP headers
02728                 if ($pos = strpos($data,"\r\n\r\n")) {
02729                         $lb = "\r\n";
02730                 } elseif( $pos = strpos($data,"\n\n")) {
02731                         $lb = "\n";
02732                 } else {
02733                         $this->debug('no proper separation of headers and document');
02734                         $this->setError('no proper separation of headers and document');
02735                         return false;
02736                 }
02737                 $header_data = trim(substr($data,0,$pos));
02738                 $header_array = explode($lb,$header_data);
02739                 $data = ltrim(substr($data,$pos));
02740                 $this->debug('found proper separation of headers and document');
02741                 $this->debug('cleaned data, stringlen: '.strlen($data));
02742                 // clean headers
02743                 foreach ($header_array as $header_line) {
02744                         $arr = explode(':',$header_line,2);
02745                         if(count($arr) > 1){
02746                                 $header_name = strtolower(trim($arr[0]));
02747                                 $this->incoming_headers[$header_name] = trim($arr[1]);
02748                                 if ($header_name == 'set-cookie') {
02749                                         // TODO: allow multiple cookies from parseCookie
02750                                         $cookie = $this->parseCookie(trim($arr[1]));
02751                                         if ($cookie) {
02752                                                 $this->incoming_cookies[] = $cookie;
02753                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
02754                                         } else {
02755                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
02756                                         }
02757                         }
02758                         } else if (isset($header_name)) {
02759                                 // append continuation line to previous header
02760                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
02761                         }
02762                 }
02763           }
02764 
02765                 $arr = explode(' ', $header_array[0], 3);
02766                 $http_version = $arr[0];
02767                 $http_status = intval($arr[1]);
02768                 $http_reason = count($arr) > 2 ? $arr[2] : '';
02769 
02770                 // see if we need to resend the request with http digest authentication
02771                 if (isset($this->incoming_headers['location']) && $http_status == 301) {
02772                         $this->debug("Got 301 $http_reason with Location: " . $this->incoming_headers['location']);
02773                         $this->setURL($this->incoming_headers['location']);
02774                         $this->tryagain = true;
02775                         return false;
02776                 }
02777 
02778                 // see if we need to resend the request with http digest authentication
02779                 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
02780                         $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
02781                         if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
02782                                 $this->debug('Server wants digest authentication');
02783                                 // remove "Digest " from our elements
02784                                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
02785 
02786                                 // parse elements into array
02787                                 $digestElements = explode(',', $digestString);
02788                                 foreach ($digestElements as $val) {
02789                                         $tempElement = explode('=', trim($val), 2);
02790                                         $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
02791                                 }
02792 
02793                                 // should have (at least) qop, realm, nonce
02794                                 if (isset($digestRequest['nonce'])) {
02795                                         $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
02796                                         $this->tryagain = true;
02797                                         return false;
02798                                 }
02799                         }
02800                         $this->debug('HTTP authentication failed');
02801                         $this->setError('HTTP authentication failed');
02802                         return false;
02803                 }
02804 
02805                 if (
02806                         ($http_status >= 300 && $http_status <= 307) ||
02807                         ($http_status >= 400 && $http_status <= 417) ||
02808                         ($http_status >= 501 && $http_status <= 505)
02809                    ) {
02810                         $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
02811                         return false;
02812                 }
02813 
02814                 // decode content-encoding
02815                 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
02816                         if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
02817                         // if decoding works, use it. else assume data wasn't gzencoded
02818                         if(function_exists('gzinflate')){
02819                                         //$timer->setMarker('starting decoding of gzip/deflated content');
02820                                         // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
02821                                         // this means there are no Zlib headers, although there should be
02822                                         $this->debug('The gzinflate function exists');
02823                                         $datalen = strlen($data);
02824                                         if ($this->incoming_headers['content-encoding'] == 'deflate') {
02825                                                 if ($degzdata = @gzinflate($data)) {
02826                                                 $data = $degzdata;
02827                                                 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
02828                                                 if (strlen($data) < $datalen) {
02829                                                         // test for the case that the payload has been compressed twice
02830                                                         $this->debug('The inflated payload is smaller than the gzipped one; try again');
02831                                                                 if ($degzdata = @gzinflate($data)) {
02832                                                                 $data = $degzdata;
02833                                                                 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
02834                                                                 }
02835                                                 }
02836                                         } else {
02837                                                 $this->debug('Error using gzinflate to inflate the payload');
02838                                                 $this->setError('Error using gzinflate to inflate the payload');
02839                                         }
02840                                         } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
02841                                                 if ($degzdata = @gzinflate(substr($data, 10))) {        // do our best
02842                                                         $data = $degzdata;
02843                                                 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
02844                                                 if (strlen($data) < $datalen) {
02845                                                         // test for the case that the payload has been compressed twice
02846                                                         $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
02847                                                                 if ($degzdata = @gzinflate(substr($data, 10))) {
02848                                                                 $data = $degzdata;
02849                                                                 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
02850                                                                 }
02851                                                 }
02852                                         } else {
02853                                                 $this->debug('Error using gzinflate to un-gzip the payload');
02854                                                         $this->setError('Error using gzinflate to un-gzip the payload');
02855                                         }
02856                                         }
02857                                         //$timer->setMarker('finished decoding of gzip/deflated content');
02858                                         //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
02859                                         // set decoded payload
02860                                         $this->incoming_payload = $header_data.$lb.$lb.$data;
02861                         } else {
02862                                         $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
02863                                         $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
02864                                 }
02865                         } else {
02866                                 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
02867                                 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
02868                         }
02869                 } else {
02870                         $this->debug('No Content-Encoding header');
02871                 }
02872 
02873                 if(strlen($data) == 0){
02874                         $this->debug('no data after headers!');
02875                         $this->setError('no data present after HTTP headers');
02876                         return false;
02877                 }
02878 
02879                 return $data;
02880         }
02881 
02882         function setContentType($type, $charset = false) {
02883                 $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
02884                 $this->debug('set Content-Type: ' . $this->outgoing_headers['Content-Type']);
02885         }
02886 
02887         function usePersistentConnection(){
02888                 if (isset($this->outgoing_headers['Accept-Encoding'])) {
02889                         return false;
02890                 }
02891                 $this->protocol_version = '1.1';
02892                 $this->persistentConnection = true;
02893                 $this->outgoing_headers['Connection'] = 'Keep-Alive';
02894                 $this->debug('set Connection: ' . $this->outgoing_headers['Connection']);
02895                 return true;
02896         }
02897 
02905         /*
02906          * TODO: allow a Set-Cookie string to be parsed into multiple cookies
02907          */
02908         function parseCookie($cookie_str) {
02909                 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
02910                 $data = split(';', $cookie_str);
02911                 $value_str = $data[0];
02912 
02913                 $cookie_param = 'domain=';
02914                 $start = strpos($cookie_str, $cookie_param);
02915                 if ($start > 0) {
02916                         $domain = substr($cookie_str, $start + strlen($cookie_param));
02917                         $domain = substr($domain, 0, strpos($domain, ';'));
02918                 } else {
02919                         $domain = '';
02920                 }
02921 
02922                 $cookie_param = 'expires=';
02923                 $start = strpos($cookie_str, $cookie_param);
02924                 if ($start > 0) {
02925                         $expires = substr($cookie_str, $start + strlen($cookie_param));
02926                         $expires = substr($expires, 0, strpos($expires, ';'));
02927                 } else {
02928                         $expires = '';
02929                 }
02930 
02931                 $cookie_param = 'path=';
02932                 $start = strpos($cookie_str, $cookie_param);
02933                 if ( $start > 0 ) {
02934                         $path = substr($cookie_str, $start + strlen($cookie_param));
02935                         $path = substr($path, 0, strpos($path, ';'));
02936                 } else {
02937                         $path = '/';
02938                 }
02939 
02940                 $cookie_param = ';secure;';
02941                 if (strpos($cookie_str, $cookie_param) !== FALSE) {
02942                         $secure = true;
02943                 } else {
02944                         $secure = false;
02945                 }
02946 
02947                 $sep_pos = strpos($value_str, '=');
02948 
02949                 if ($sep_pos) {
02950                         $name = substr($value_str, 0, $sep_pos);
02951                         $value = substr($value_str, $sep_pos + 1);
02952                         $cookie= array( 'name' => $name,
02953                                         'value' => $value,
02954                                                         'domain' => $domain,
02955                                                         'path' => $path,
02956                                                         'expires' => $expires,
02957                                                         'secure' => $secure
02958                                                         );
02959                         return $cookie;
02960                 }
02961                 return false;
02962         }
02963 
02972         function getCookiesForRequest($cookies, $secure=false) {
02973                 $cookie_str = '';
02974                 if ((! is_null($cookies)) && (is_array($cookies))) {
02975                         foreach ($cookies as $cookie) {
02976                                 if (! is_array($cookie)) {
02977                                         continue;
02978                                 }
02979                         $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
02980                                 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
02981                                         if (strtotime($cookie['expires']) <= time()) {
02982                                                 $this->debug('cookie has expired');
02983                                                 continue;
02984                                         }
02985                                 }
02986                                 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
02987                                         $domain = preg_quote($cookie['domain']);
02988                                         if (! preg_match("'.*$domain$'i", $this->host)) {
02989                                                 $this->debug('cookie has different domain');
02990                                                 continue;
02991                                         }
02992                                 }
02993                                 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
02994                                         $path = preg_quote($cookie['path']);
02995                                         if (! preg_match("'^$path.*'i", $this->path)) {
02996                                                 $this->debug('cookie is for a different path');
02997                                                 continue;
02998                                         }
02999                                 }
03000                                 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
03001                                         $this->debug('cookie is secure, transport is not');
03002                                         continue;
03003                                 }
03004                                 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
03005                         $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
03006                         }
03007                 }
03008                 return $cookie_str;
03009   }
03010 }
03011 
03012 
03013 
03021 class wsdl extends nusoap_base {
03022         // URL or filename of the root of this WSDL
03023     var $wsdl;
03024     // define internal arrays of bindings, ports, operations, messages, etc.
03025     var $schemas = array();
03026     var $currentSchema;
03027     var $message = array();
03028     var $complexTypes = array();
03029     var $messages = array();
03030     var $currentMessage;
03031     var $currentOperation;
03032     var $portTypes = array();
03033     var $currentPortType;
03034     var $bindings = array();
03035     var $currentBinding;
03036     var $ports = array();
03037     var $currentPort;
03038     var $opData = array();
03039     var $status = '';
03040     var $documentation = false;
03041     var $endpoint = '';
03042     // array of wsdl docs to import
03043     var $import = array();
03044     // parser vars
03045     var $parser;
03046     var $position = 0;
03047     var $depth = 0;
03048     var $depth_array = array();
03049         // for getting wsdl
03050         var $proxyhost = '';
03051     var $proxyport = '';
03052         var $proxyusername = '';
03053         var $proxypassword = '';
03054         var $timeout = 0;
03055         var $response_timeout = 30;
03056 
03069     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){
03070                 parent::nusoap_base();
03071         $this->wsdl = $wsdl;
03072         $this->proxyhost = $proxyhost;
03073         $this->proxyport = $proxyport;
03074                 $this->proxyusername = $proxyusername;
03075                 $this->proxypassword = $proxypassword;
03076                 $this->timeout = $timeout;
03077                 $this->response_timeout = $response_timeout;
03078 
03079         // parse wsdl file
03080         if ($wsdl != "") {
03081             $this->debug('initial wsdl URL: ' . $wsdl);
03082             $this->parseWSDL($wsdl);
03083         }
03084         // imports
03085         // TODO: handle imports more properly, grabbing them in-line and nesting them
03086                 $imported_urls = array();
03087                 $imported = 1;
03088                 while ($imported > 0) {
03089                         $imported = 0;
03090                         // Schema imports
03091                         foreach ($this->schemas as $ns => $list) {
03092                                 foreach ($list as $xs) {
03093                                                 $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
03094                                     foreach ($xs->imports as $ns2 => $list2) {
03095                                         for ($ii = 0; $ii < count($list2); $ii++) {
03096                                                 if (! $list2[$ii]['loaded']) {
03097                                                         $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
03098                                                         $url = $list2[$ii]['location'];
03099                                                                         if ($url != '') {
03100                                                                                 $urlparts = parse_url($url);
03101                                                                                 if (!isset($urlparts['host'])) {
03102                                                                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
03103                                                                                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
03104                                                                                 }
03105                                                                                 if (! in_array($url, $imported_urls)) {
03106                                                                         $this->parseWSDL($url);
03107                                                                         $imported++;
03108                                                                         $imported_urls[] = $url;
03109                                                                 }
03110                                                                         } else {
03111                                                                                 $this->debug("Unexpected scenario: empty URL for unloaded import");
03112                                                                         }
03113                                                                 }
03114                                                         }
03115                                     }
03116                                 }
03117                         }
03118                         // WSDL imports
03119                                 $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
03120                     foreach ($this->import as $ns => $list) {
03121                         for ($ii = 0; $ii < count($list); $ii++) {
03122                                 if (! $list[$ii]['loaded']) {
03123                                         $this->import[$ns][$ii]['loaded'] = true;
03124                                         $url = $list[$ii]['location'];
03125                                                         if ($url != '') {
03126                                                                 $urlparts = parse_url($url);
03127                                                                 if (!isset($urlparts['host'])) {
03128                                                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
03129                                                                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
03130                                                                 }
03131                                                                 if (! in_array($url, $imported_urls)) {
03132                                                         $this->parseWSDL($url);
03133                                                         $imported++;
03134                                                         $imported_urls[] = $url;
03135                                                 }
03136                                                         } else {
03137                                                                 $this->debug("Unexpected scenario: empty URL for unloaded import");
03138                                                         }
03139                                                 }
03140                                         }
03141                     }
03142                         }
03143         // add new data to operation data
03144         foreach($this->bindings as $binding => $bindingData) {
03145             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
03146                 foreach($bindingData['operations'] as $operation => $data) {
03147                     $this->debug('post-parse data gathering for ' . $operation);
03148                     $this->bindings[$binding]['operations'][$operation]['input'] =
03149                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ?
03150                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
03151                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
03152                     $this->bindings[$binding]['operations'][$operation]['output'] =
03153                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
03154                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
03155                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
03156                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
03157                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
03158                                         }
03159                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
03160                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
03161                     }
03162                                         if (isset($bindingData['style'])) {
03163                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
03164                     }
03165                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
03166                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
03167                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
03168                 }
03169             }
03170         }
03171     }
03172 
03179     function parseWSDL($wsdl = '')
03180     {
03181         if ($wsdl == '') {
03182             $this->debug('no wsdl passed to parseWSDL()!!');
03183             $this->setError('no wsdl passed to parseWSDL()!!');
03184             return false;
03185         }
03186 
03187         // parse $wsdl for url format
03188         $wsdl_props = parse_url($wsdl);
03189 
03190         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
03191             $this->debug('getting WSDL http(s) URL ' . $wsdl);
03192                 // get wsdl
03193                 $tr = new soap_transport_http($wsdl);
03194                         $tr->request_method = 'GET';
03195                         $tr->useSOAPAction = false;
03196                         if($this->proxyhost && $this->proxyport){
03197                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
03198                         }
03199                         $tr->setEncoding('gzip, deflate');
03200                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
03201                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);
03202                         //$this->debug("WSDL response\n" . $tr->incoming_payload);
03203                         $this->appendDebug($tr->getDebug());
03204                         // catch errors
03205                         if($err = $tr->getError() ){
03206                                 $errstr = 'HTTP ERROR: '.$err;
03207                                 $this->debug($errstr);
03208                     $this->setError($errstr);
03209                                 unset($tr);
03210                     return false;
03211                         }
03212                         unset($tr);
03213                         $this->debug("got WSDL URL");
03214         } else {
03215             // $wsdl is not http(s), so treat it as a file URL or plain file path
03216                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
03217                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
03218                 } else {
03219                         $path = $wsdl;
03220                 }
03221             $this->debug('getting WSDL file ' . $path);
03222             if ($fp = @fopen($path, 'r')) {
03223                 $wsdl_string = '';
03224                 while ($data = fread($fp, 32768)) {
03225                     $wsdl_string .= $data;
03226                 }
03227                 fclose($fp);
03228             } else {
03229                 $errstr = "Bad path to WSDL file $path";
03230                 $this->debug($errstr);
03231                 $this->setError($errstr);
03232                 return false;
03233             }
03234         }
03235         $this->debug('Parse WSDL');
03236         // end new code added
03237         // Create an XML parser.
03238         $this->parser = xml_parser_create();
03239         // Set the options for parsing the XML data.
03240         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
03241         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
03242         // Set the object for the parser.
03243         xml_set_object($this->parser, $this);
03244         // Set the element handlers for the parser.
03245         xml_set_element_handler($this->parser, 'start_element', 'end_element');
03246         xml_set_character_data_handler($this->parser, 'character_data');
03247         // Parse the XML file.
03248         if (!xml_parse($this->parser, $wsdl_string, true)) {
03249             // Display an error message.
03250             $errstr = sprintf(
03251                                 'XML error parsing WSDL from %s on line %d: %s',
03252                                 $wsdl,
03253                 xml_get_current_line_number($this->parser),
03254                 xml_error_string(xml_get_error_code($this->parser))
03255                 );
03256             $this->debug($errstr);
03257                         $this->debug("XML payload:\n" . $wsdl_string);
03258             $this->setError($errstr);
03259             return false;
03260         }
03261                 // free the parser
03262         xml_parser_free($this->parser);
03263         $this->debug('Parsing WSDL done');
03264                 // catch wsdl parse errors
03265                 if($this->getError()){
03266                         return false;
03267                 }
03268         return true;
03269     }
03270 
03279     function start_element($parser, $name, $attrs)
03280     {
03281         if ($this->status == 'schema') {
03282             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
03283             $this->appendDebug($this->currentSchema->getDebug());
03284             $this->currentSchema->clearDebug();
03285         } elseif (ereg('schema$', $name)) {
03286                 $this->debug('Parsing WSDL schema');
03287             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
03288             $this->status = 'schema';
03289             $this->currentSchema = new xmlschema('', '', $this->namespaces);
03290             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
03291             $this->appendDebug($this->currentSchema->getDebug());
03292             $this->currentSchema->clearDebug();
03293         } else {
03294             // position in the total number of elements, starting from 0
03295             $pos = $this->position++;
03296             $depth = $this->depth++;
03297             // set self as current value for this depth
03298             $this->depth_array[$depth] = $pos;
03299             $this->message[$pos] = array('cdata' => '');
03300             // process attributes
03301             if (count($attrs) > 0) {
03302                                 // register namespace declarations
03303                 foreach($attrs as $k => $v) {
03304                     if (ereg("^xmlns", $k)) {
03305                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
03306                             $this->namespaces[$ns_prefix] = $v;
03307                         } else {
03308                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
03309                         }
03310                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
03311                             $this->XMLSchemaVersion = $v;
03312                             $this->namespaces['xsi'] = $v . '-instance';
03313                         }
03314                     }
03315                 }
03316                 // expand each attribute prefix to its namespace
03317                 foreach($attrs as $k => $v) {
03318                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
03319                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
03320                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
03321                     }
03322                     $eAttrs[$k] = $v;
03323                 }
03324                 $attrs = $eAttrs;
03325             } else {
03326                 $attrs = array();
03327             }
03328             // get element prefix, namespace and name
03329             if (ereg(':', $name)) {
03330                 // get ns prefix
03331                 $prefix = substr($name, 0, strpos($name, ':'));
03332                 // get ns
03333                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
03334                 // get unqualified name
03335                 $name = substr(strstr($name, ':'), 1);
03336             }
03337                         // process attributes, expanding any prefixes to namespaces
03338             // find status, register data
03339             switch ($this->status) {
03340                 case 'message':
03341                     if ($name == 'part') {
03342                                     if (isset($attrs['type'])) {
03343                                     $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
03344                                     $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
03345                                 }
03346                                     if (isset($attrs['element'])) {
03347                                     $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
03348                                         $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
03349                                     }
03350                                 }
03351                                 break;
03352                             case 'portType':
03353                                 switch ($name) {
03354                                     case 'operation':
03355                                         $this->currentPortOperation = $attrs['name'];
03356                                         $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
03357                                         if (isset($attrs['parameterOrder'])) {
03358                                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
03359                                                 }
03360                                                 break;
03361                                             case 'documentation':
03362                                                 $this->documentation = true;
03363                                                 break;
03364                                             // merge input/output data
03365                                             default:
03366                                                 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
03367                                                 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
03368                                                 break;
03369                                         }
03370                                 break;
03371                                 case 'binding':
03372                                     switch ($name) {
03373                                         case 'binding':
03374                                             // get ns prefix
03375                                             if (isset($attrs['style'])) {
03376                                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;
03377                                                 }
03378                                                 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
03379                                                 break;
03380                                                 case 'header':
03381                                                     $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
03382                                                     break;
03383                                                 case 'operation':
03384                                                     if (isset($attrs['soapAction'])) {
03385                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
03386                                                     }
03387                                                     if (isset($attrs['style'])) {
03388                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
03389                                                     }
03390                                                     if (isset($attrs['name'])) {
03391                                                         $this->currentOperation = $attrs['name'];
03392                                                         $this->debug("current binding operation: $this->currentOperation");
03393                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
03394                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
03395                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
03396                                                     }
03397                                                     break;
03398                                                 case 'input':
03399                                                     $this->opStatus = 'input';
03400                                                     break;
03401                                                 case 'output':
03402                                                     $this->opStatus = 'output';
03403                                                     break;
03404                                                 case 'body':
03405                                                     if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
03406                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
03407                                                     } else {
03408                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
03409                                                     }
03410                                                     break;
03411                                         }
03412                                         break;
03413                                 case 'service':
03414                                         switch ($name) {
03415                                             case 'port':
03416                                                 $this->currentPort = $attrs['name'];
03417                                                 $this->debug('current port: ' . $this->currentPort);
03418                                                 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
03419 
03420                                                 break;
03421                                             case 'address':
03422                                                 $this->ports[$this->currentPort]['location'] = $attrs['location'];
03423                                                 $this->ports[$this->currentPort]['bindingType'] = $namespace;
03424                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
03425                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
03426                                                 break;
03427                                         }
03428                                         break;
03429                         }
03430                 // set status
03431                 switch ($name) {
03432                         case 'import':
03433                             if (isset($attrs['location'])) {
03434                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
03435                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
03436                                 } else {
03437                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
03438                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
03439                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
03440                                         }
03441                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
03442                                 }
03443                                 break;
03444                         //wait for schema
03445                         //case 'types':
03446                         //      $this->status = 'schema';
03447                         //      break;
03448                         case 'message':
03449                                 $this->status = 'message';
03450                                 $this->messages[$attrs['name']] = array();
03451                                 $this->currentMessage = $attrs['name'];
03452                                 break;
03453                         case 'portType':
03454                                 $this->status = 'portType';
03455                                 $this->portTypes[$attrs['name']] = array();
03456                                 $this->currentPortType = $attrs['name'];
03457                                 break;
03458                         case "binding":
03459                                 if (isset($attrs['name'])) {
03460                                 // get binding name
03461                                         if (strpos($attrs['name'], ':')) {
03462                                         $this->currentBinding = $this->getLocalPart($attrs['name']);
03463                                         } else {
03464                                         $this->currentBinding = $attrs['name'];
03465                                         }
03466                                         $this->status = 'binding';
03467                                         $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
03468                                         $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
03469                                 }
03470                                 break;
03471                         case 'service':
03472                                 $this->serviceName = $attrs['name'];
03473                                 $this->status = 'service';
03474                                 $this->debug('current service: ' . $this->serviceName);
03475                                 break;
03476                         case 'definitions':
03477                                 foreach ($attrs as $name => $value) {
03478                                         $this->wsdl_info[$name] = $value;
03479                                 }
03480                                 break;
03481                         }
03482                 }
03483         }
03484 
03492         function end_element($parser, $name){
03493                 // unset schema status
03494                 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
03495                         $this->status = "";
03496             $this->appendDebug($this->currentSchema->getDebug());
03497             $this->currentSchema->clearDebug();
03498                         $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
03499                 $this->debug('Parsing WSDL schema done');
03500                 }
03501                 if ($this->status == 'schema') {
03502                         $this->currentSchema->schemaEndElement($parser, $name);
03503                 } else {
03504                         // bring depth down a notch
03505                         $this->depth--;
03506                 }
03507                 // end documentation
03508                 if ($this->documentation) {
03509                         //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
03510                         //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
03511                         $this->documentation = false;
03512                 }
03513         }
03514 
03522         function character_data($parser, $data)
03523         {
03524                 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
03525                 if (isset($this->message[$pos]['cdata'])) {
03526                         $this->message[$pos]['cdata'] .= $data;
03527                 }
03528                 if ($this->documentation) {
03529                         $this->documentation .= $data;
03530                 }
03531         }
03532 
03533         function getBindingData($binding)
03534         {
03535                 if (is_array($this->bindings[$binding])) {
03536                         return $this->bindings[$binding];
03537                 }
03538         }
03539 
03547         function getOperations($bindingType = 'soap')
03548         {
03549                 $ops = array();
03550                 if ($bindingType == 'soap') {
03551                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03552                 }
03553                 // loop thru ports
03554                 foreach($this->ports as $port => $portData) {
03555                         // binding type of port matches parameter
03556                         if ($portData['bindingType'] == $bindingType) {
03557                                 //$this->debug("getOperations for port $port");
03558                                 //$this->debug("port data: " . $this->varDump($portData));
03559                                 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
03560                                 // merge bindings
03561                                 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
03562                                         $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
03563                                 }
03564                         }
03565                 }
03566                 return $ops;
03567         }
03568 
03577         function getOperationData($operation, $bindingType = 'soap')
03578         {
03579                 if ($bindingType == 'soap') {
03580                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03581                 }
03582                 // loop thru ports
03583                 foreach($this->ports as $port => $portData) {
03584                         // binding type of port matches parameter
03585                         if ($portData['bindingType'] == $bindingType) {
03586                                 // get binding
03587                                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
03588                                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
03589                                         // note that we could/should also check the namespace here
03590                                         if ($operation == $bOperation) {
03591                                                 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
03592                                             return $opData;
03593                                         }
03594                                 }
03595                         }
03596                 }
03597         }
03598 
03607         function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
03608                 if ($bindingType == 'soap') {
03609                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03610                 }
03611                 // loop thru ports
03612                 foreach($this->ports as $port => $portData) {
03613                         // binding type of port matches parameter
03614                         if ($portData['bindingType'] == $bindingType) {
03615                                 // loop through operations for the binding
03616                                 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
03617                                         if ($opData['soapAction'] == $soapAction) {
03618                                             return $opData;
03619                                         }
03620                                 }
03621                         }
03622                 }
03623         }
03624 
03643         function getTypeDef($type, $ns) {
03644                 $this->debug("in getTypeDef: type=$type, ns=$ns");
03645                 if ((! $ns) && isset($this->namespaces['tns'])) {
03646                         $ns = $this->namespaces['tns'];
03647                         $this->debug("in getTypeDef: type namespace forced to $ns");
03648                 }
03649                 if (isset($this->schemas[$ns])) {
03650                         $this->debug("in getTypeDef: have schema for namespace $ns");
03651                         for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
03652                                 $xs = &$this->schemas[$ns][$i];
03653                                 $t = $xs->getTypeDef($type);
03654                                 $this->appendDebug($xs->getDebug());
03655                                 $xs->clearDebug();
03656                                 if ($t) {
03657                                         if (!isset($t['phpType'])) {
03658                                                 // get info for type to tack onto the element
03659                                                 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
03660                                                 $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
03661                                                 $etype = $this->getTypeDef($uqType, $ns);
03662                                                 if ($etype) {
03663                                                         $this->debug("found type for [element] $type:");
03664                                                         $this->debug($this->varDump($etype));
03665                                                         if (isset($etype['phpType'])) {
03666                                                                 $t['phpType'] = $etype['phpType'];
03667                                                         }
03668                                                         if (isset($etype['elements'])) {
03669                                                                 $t['elements'] = $etype['elements'];
03670                                                         }
03671                                                         if (isset($etype['attrs'])) {
03672                                                                 $t['attrs'] = $etype['attrs'];
03673                                                         }
03674                                                 }
03675                                         }
03676                                         return $t;
03677                                 }
03678                         }
03679                 } else {
03680                         $this->debug("in getTypeDef: do not have schema for namespace $ns");
03681                 }
03682                 return false;
03683         }
03684 
03690     function webDescription(){
03691         global $HTTP_SERVER_VARS;
03692 
03693                 if (isset($_SERVER)) {
03694                         $PHP_SELF = $_SERVER['PHP_SELF'];
03695                 } elseif (isset($HTTP_SERVER_VARS)) {
03696                         $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
03697                 } else {
03698                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
03699                 }
03700 
03701                 $b = '
03702                 <html><head><title>NuSOAP: '.$this->serviceName.'</title>
03703                 <style type="text/css">
03704                     body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
03705                     p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
03706                     pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
03707                     ul      { margin-top: 10px; margin-left: 20px; }
03708                     li      { list-style-type: none; margin-top: 10px; color: #000000; }
03709                     .content{
03710                         margin-left: 0px; padding-bottom: 2em; }
03711                     .nav {
03712                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
03713                         margin-top: 10px; margin-left: 0px; color: #000000;
03714                         background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
03715                     .title {
03716                         font-family: arial; font-size: 26px; color: #ffffff;
03717                         background-color: #999999; width: 105%; margin-left: 0px;
03718                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
03719                     .hidden {
03720                         position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
03721                         font-family: arial; overflow: hidden; width: 600;
03722                         padding: 20px; font-size: 10px; background-color: #999999;
03723                         layer-background-color:#FFFFFF; }
03724                     a,a:active  { color: charcoal; font-weight: bold; }
03725                     a:visited   { color: #666666; font-weight: bold; }
03726                     a:hover     { color: cc3300; font-weight: bold; }
03727                 </style>
03728                 <script language="JavaScript" type="text/javascript">
03729                 <!--
03730                 // POP-UP CAPTIONS...
03731                 function lib_bwcheck(){ //Browsercheck (needed)
03732                     this.ver=navigator.appVersion
03733                     this.agent=navigator.userAgent
03734                     this.dom=document.getElementById?1:0
03735                     this.opera5=this.agent.indexOf("Opera 5")>-1
03736                     this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
03737                     this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
03738                     this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
03739                     this.ie=this.ie4||this.ie5||this.ie6
03740                     this.mac=this.agent.indexOf("Mac")>-1
03741                     this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
03742                     this.ns4=(document.layers && !this.dom)?1:0;
03743                     this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
03744                     return this
03745                 }
03746                 var bw = new lib_bwcheck()
03747                 //Makes crossbrowser object.
03748                 function makeObj(obj){
03749                     this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
03750                     if(!this.evnt) return false
03751                     this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
03752                     this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
03753                     this.writeIt=b_writeIt;
03754                     return this
03755                 }
03756                 // A unit of measure that will be added when setting the position of a layer.
03757                 //var px = bw.ns4||window.opera?"":"px";
03758                 function b_writeIt(text){
03759                     if (bw.ns4){this.wref.write(text);this.wref.close()}
03760                     else this.wref.innerHTML = text
03761                 }
03762                 //Shows the messages
03763                 var oDesc;
03764                 function popup(divid){
03765                     if(oDesc = new makeObj(divid)){
03766                         oDesc.css.visibility = "visible"
03767                     }
03768                 }
03769                 function popout(){ // Hides message
03770                     if(oDesc) oDesc.css.visibility = "hidden"
03771                 }
03772                 //-->
03773                 </script>
03774                 </head>
03775                 <body>
03776                 <div class=content>
03777                         <br><br>
03778                         <div class=title>'.$this->serviceName.'</div>
03779                         <div class=nav>
03780                                 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
03781                                 Click on an operation name to view it&apos;s details.</p>
03782                                 <ul>';
03783                                 foreach($this->getOperations() as $op => $data){
03784                                     $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
03785                                     // create hidden div
03786                                     $b .= "<div id='$op' class='hidden'>
03787                                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
03788                                     foreach($data as $donnie => $marie){ // loop through opdata
03789                                                 if($donnie == 'input' || $donnie == 'output'){ // show input/output data
03790                                                     $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
03791                                                     foreach($marie as $captain => $tenille){ // loop through data
03792                                                                 if($captain == 'parts'){ // loop thru parts
03793                                                                     $b .= "&nbsp;&nbsp;$captain:<br>";
03794                                                         //if(is_array($tenille)){
03795                                                                         foreach($tenille as $joanie => $chachi){
03796                                                                                         $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
03797                                                                         }
03798                                                                 //}
03799                                                                 } else {
03800                                                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
03801                                                                 }
03802                                                     }
03803                                                 } else {
03804                                                     $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
03805                                                 }
03806                                     }
03807                                         $b .= '</div>';
03808                                 }
03809                                 $b .= '
03810                                 <ul>
03811                         </div>
03812                 </div></body></html>';
03813                 return $b;
03814     }
03815 
03823         function serialize($debug = 0)
03824         {
03825                 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
03826                 $xml .= "\n<definitions";
03827                 foreach($this->namespaces as $k => $v) {
03828                         $xml .= " xmlns:$k=\"$v\"";
03829                 }
03830                 // 10.9.02 - add poulter fix for wsdl and tns declarations
03831                 if (isset($this->namespaces['wsdl'])) {
03832                         $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
03833                 }
03834                 if (isset($this->namespaces['tns'])) {
03835                         $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
03836                 }
03837                 $xml .= '>';
03838                 // imports
03839                 if (sizeof($this->import) > 0) {
03840                         foreach($this->import as $ns => $list) {
03841                                 foreach ($list as $ii) {
03842                                         if ($ii['location'] != '') {
03843                                                 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
03844                                         } else {
03845                                                 $xml .= '<import namespace="' . $ns . '" />';
03846                                         }
03847                                 }
03848                         }
03849                 }
03850                 // types
03851                 if (count($this->schemas)>=1) {
03852                         $xml .= "\n<types>";
03853                         foreach ($this->schemas as $ns => $list) {
03854                                 foreach ($list as $xs) {
03855                                         $xml .= $xs->serializeSchema();
03856                                 }
03857                         }
03858                         $xml .= '</types>';
03859                 }
03860                 // messages
03861                 if (count($this->messages) >= 1) {
03862                         foreach($this->messages as $msgName => $msgParts) {
03863                                 $xml .= "\n<message name=\"" . $msgName . '">';
03864                                 if(is_array($msgParts)){
03865                                         foreach($msgParts as $partName => $partType) {
03866                                                 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
03867                                                 if (strpos($partType, ':')) {
03868                                                     $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
03869                                                 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
03870                                                     // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
03871                                                     $typePrefix = 'xsd';
03872                                                 } else {
03873                                                     foreach($this->typemap as $ns => $types) {
03874                                                         if (isset($types[$partType])) {
03875                                                             $typePrefix = $this->getPrefixFromNamespace($ns);
03876                                                         }
03877                                                     }
03878                                                     if (!isset($typePrefix)) {
03879                                                         die("$partType has no namespace!");
03880                                                     }
03881                                                 }
03882                                                 $ns = $this->getNamespaceFromPrefix($typePrefix);
03883                                                 $typeDef = $this->getTypeDef($this->getLocalPart($partType), $ns);
03884                                                 if ($typeDef['typeClass'] == 'element') {
03885                                                         $elementortype = 'element';
03886                                                 } else {
03887                                                         $elementortype = 'type';
03888                                                 }
03889                                                 $xml .= '<part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
03890                                         }
03891                                 }
03892                                 $xml .= '</message>';
03893                         }
03894                 }
03895                 // bindings & porttypes
03896                 if (count($this->bindings) >= 1) {
03897                         $binding_xml = '';
03898                         $portType_xml = '';
03899                         foreach($this->bindings as $bindingName => $attrs) {
03900                                 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
03901                                 $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
03902                                 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
03903                                 foreach($attrs['operations'] as $opName => $opParts) {
03904                                         $binding_xml .= '<operation name="' . $opName . '">';
03905                                         $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
03906                                         if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
03907                                                 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
03908                                         } else {
03909                                                 $enc_style = '';
03910                                         }
03911                                         $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
03912                                         if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
03913                                                 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
03914                                         } else {
03915                                                 $enc_style = '';
03916                                         }
03917                                         $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
03918                                         $binding_xml .= '</operation>';
03919                                         $portType_xml .= '<operation name="' . $opParts['name'] . '"';
03920                                         if (isset($opParts['parameterOrder'])) {
03921                                             $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
03922                                         }
03923                                         $portType_xml .= '>';
03924                                         if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
03925                                                 $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
03926                                         }
03927                                         $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
03928                                         $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
03929                                         $portType_xml .= '</operation>';
03930                                 }
03931                                 $portType_xml .= '</portType>';
03932                                 $binding_xml .= '</binding>';
03933                         }
03934                         $xml .= $portType_xml . $binding_xml;
03935                 }
03936                 // services
03937                 $xml .= "\n<service name=\"" . $this->serviceName . '">';
03938                 if (count($this->ports) >= 1) {
03939                         foreach($this->ports as $pName => $attrs) {
03940                                 $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
03941                                 $xml .= '<soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
03942                                 $xml .= '</port>';
03943                         }
03944                 }
03945                 $xml .= '</service>';
03946                 return $xml . "\n</definitions>";
03947         }
03948 
03962         function serializeRPCParameters($operation, $direction, $parameters)
03963         {
03964                 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
03965                 $this->appendDebug('parameters=' . $this->varDump($parameters));
03966 
03967                 if ($direction != 'input' && $direction != 'output') {
03968                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
03969                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
03970                         return false;
03971                 }
03972                 if (!$opData = $this->getOperationData($operation)) {
03973                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
03974                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
03975                         return false;
03976                 }
03977                 $this->debug('opData:');
03978                 $this->appendDebug($this->varDump($opData));
03979 
03980                 // Get encoding style for output and set to current
03981                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
03982                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
03983                         $encodingStyle = $opData['output']['encodingStyle'];
03984                         $enc_style = $encodingStyle;
03985                 }
03986 
03987                 // set input params
03988                 $xml = '';
03989                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
03990 
03991                         $use = $opData[$direction]['use'];
03992                         $this->debug('have ' . count($opData[$direction]['parts']) . ' part(s) to serialize');
03993                         if (is_array($parameters)) {
03994                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
03995                                 $this->debug('have ' . count($parameters) . ' parameter(s) provided as ' . $parametersArrayType . ' to serialize');
03996                                 foreach($opData[$direction]['parts'] as $name => $type) {
03997                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
03998                                         // Track encoding style
03999                                         if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
04000                                                 $encodingStyle = $opData[$direction]['encodingStyle'];
04001                                                 $enc_style = $encodingStyle;
04002                                         } else {
04003                                                 $enc_style = false;
04004                                         }
04005                                         // NOTE: add error handling here
04006                                         // if serializeType returns false, then catch global error and fault
04007                                         if ($parametersArrayType == 'arraySimple') {
04008                                                 $p = array_shift($parameters);
04009                                                 $this->debug('calling serializeType w/indexed param');
04010                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
04011                                         } elseif (isset($parameters[$name])) {
04012                                                 $this->debug('calling serializeType w/named param');
04013                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
04014                                         } else {
04015                                                 // TODO: only send nillable
04016                                                 $this->debug('calling serializeType w/null param');
04017                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
04018                                         }
04019                                 }
04020                         } else {
04021                                 $this->debug('no parameters passed.');
04022                         }
04023                 }
04024                 $this->debug("serializeRPCParameters returning: $xml");
04025                 return $xml;
04026         }
04027 
04041         function serializeParameters($operation, $direction, $parameters)
04042         {
04043                 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
04044                 $this->appendDebug('parameters=' . $this->varDump($parameters));
04045 
04046                 if ($direction != 'input' && $direction != 'output') {
04047                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
04048                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
04049                         return false;
04050                 }
04051                 if (!$opData = $this->getOperationData($operation)) {
04052                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
04053                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
04054                         return false;
04055                 }
04056                 $this->debug('opData:');
04057                 $this->appendDebug($this->varDump($opData));
04058 
04059                 // Get encoding style for output and set to current
04060                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
04061                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
04062                         $encodingStyle = $opData['output']['encodingStyle'];
04063                         $enc_style = $encodingStyle;
04064                 }
04065 
04066                 // set input params
04067                 $xml = '';
04068                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
04069 
04070                         $use = $opData[$direction]['use'];
04071                         $this->debug("use=$use");
04072                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
04073                         if (is_array($parameters)) {
04074                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
04075                                 $this->debug('have ' . $parametersArrayType . ' parameters');
04076                                 foreach($opData[$direction]['parts'] as $name => $type) {
04077                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
04078                                         // Track encoding style
04079                                         if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
04080                                                 $encodingStyle = $opData[$direction]['encodingStyle'];
04081                                                 $enc_style = $encodingStyle;
04082                                         } else {
04083                                                 $enc_style = false;
04084                                         }
04085                                         // NOTE: add error handling here
04086                                         // if serializeType returns false, then catch global error and fault
04087                                         if ($parametersArrayType == 'arraySimple') {
04088                                                 $p = array_shift($parameters);
04089                                                 $this->debug('calling serializeType w/indexed param');
04090                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
04091                                         } elseif (isset($parameters[$name])) {
04092                                                 $this->debug('calling serializeType w/named param');
04093                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
04094                                         } else {
04095                                                 // TODO: only send nillable
04096                                                 $this->debug('calling serializeType w/null param');
04097                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
04098                                         }
04099                                 }
04100                         } else {
04101                                 $this->debug('no parameters passed.');
04102                         }
04103                 }
04104                 $this->debug("serializeParameters returning: $xml");
04105                 return $xml;
04106         }
04107 
04120         function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
04121         {
04122                 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
04123                 $this->appendDebug("value=" . $this->varDump($value));
04124                 if($use == 'encoded' && $encodingStyle) {
04125                         $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
04126                 }
04127 
04128                 // if a soapval has been supplied, let its type override the WSDL
04129         if (is_object($value) && get_class($value) == 'soapval') {
04130                 if ($value->type_ns) {
04131                         $type = $value->type_ns . ':' . $value->type;
04132                         $forceType = true;
04133                         $this->debug("in serializeType: soapval overrides type to $type");
04134                 } elseif ($value->type) {
04135                         $type = $value->type;
04136                         $forceType = true;
04137                         $this->debug("in serializeType: soapval overrides type to $type");
04138                 } else {
04139                         $forceType = false;
04140                         $this->debug("in serializeType: soapval does not override type");
04141                 }
04142                 $attrs = $value->attributes;
04143                 $value = $value->value;
04144                 $this->debug("in serializeType: soapval overrides value to $value");
04145                 if ($attrs) {
04146                         if (!is_array($value)) {
04147                                 $value['!'] = $value;
04148                         }
04149                         foreach ($attrs as $n => $v) {
04150                                 $value['!' . $n] = $v;
04151                         }
04152                         $this->debug("in serializeType: soapval provides attributes");
04153                     }
04154         } else {
04155                 $forceType = false;
04156         }
04157 
04158                 $xml = '';
04159                 if (strpos($type, ':')) {
04160                         $uqType = substr($type, strrpos($type, ':') + 1);
04161                         $ns = substr($type, 0, strrpos($type, ':'));
04162                         $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
04163                         if ($this->getNamespaceFromPrefix($ns)) {
04164                                 $ns = $this->getNamespaceFromPrefix($ns);
04165                                 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
04166                         }
04167 
04168                         if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
04169                                 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
04170                                 if ($unqualified  && $use == 'literal') {
04171                                         $elementNS = " xmlns=\"\"";
04172                                 } else {
04173                                         $elementNS = '';
04174                                 }
04175                                 if (is_null($value)) {
04176                                         if ($use == 'literal') {
04177                                                 // TODO: depends on minOccurs
04178                                                 $xml = "<$name$elementNS/>";
04179                                         } else {
04180                                                 // TODO: depends on nillable, which should be checked before calling this method
04181                                                 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
04182                                         }
04183                                         $this->debug("in serializeType: returning: $xml");
04184                                         return $xml;
04185                                 }
04186                         if ($uqType == 'boolean') {
04187                                 if ((is_string($value) && $value == 'false') || (! $value)) {
04188                                                 $value = 'false';
04189                                         } else {
04190                                                 $value = 'true';
04191                                         }
04192                                 }
04193                                 if ($uqType == 'string' && gettype($value) == 'string') {
04194                                         $value = $this->expandEntities($value);
04195                                 }
04196                                 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
04197                                         $value = sprintf("%.0lf", $value);
04198                                 }
04199                                 // it's a scalar
04200                                 // TODO: what about null/nil values?
04201                                 // check type isn't a custom type extending xmlschema namespace
04202                                 if (!$this->getTypeDef($uqType, $ns)) {
04203                                         if ($use == 'literal') {
04204                                                 if ($forceType) {
04205                                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
04206                                                 } else {
04207                                                         $xml = "<$name$elementNS>$value</$name>";
04208                                                 }
04209                                         } else {
04210                                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
04211                                         }
04212                                         $this->debug("in serializeType: returning: $xml");
04213                                         return $xml;
04214                                 }
04215                                 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
04216                         } else if ($ns == 'http://xml.apache.org/xml-soap') {
04217                                 $this->debug('in serializeType: appears to be Apache SOAP type');
04218                                 if ($uqType == 'Map') {
04219                                         $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
04220                                         if (! $tt_prefix) {
04221                                                 $this->debug('in serializeType: Add namespace for Apache SOAP type');
04222                                                 $tt_prefix = 'ns' . rand(1000, 9999);
04223                                                 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
04224                                                 // force this to be added to usedNamespaces
04225                                                 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
04226                                         }
04227                                         $contents = '';
04228                                         foreach($value as $k => $v) {
04229                                                 $this->debug("serializing map element: key $k, value $v");
04230                                                 $contents .= '<item>';
04231                                                 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
04232                                                 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
04233                                                 $contents .= '</item>';
04234                                         }
04235                                         if ($use == 'literal') {
04236                                                 if ($forceType) {
04237                                                         $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
04238                                                 } else {
04239                                                         $xml = "<$name>$contents</$name>";
04240                                                 }
04241                                         } else {
04242                                                 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
04243                                         }
04244                                         $this->debug("in serializeType: returning: $xml");
04245                                         return $xml;
04246                                 }
04247                                 $this->debug('in serializeType: Apache SOAP type, but only support Map');
04248                         }
04249                 } else {
04250                         // TODO: should the type be compared to types in XSD, and the namespace
04251                         // set to XSD if the type matches?
04252                         $this->debug("in serializeType: No namespace for type $type");
04253                         $ns = '';
04254                         $uqType = $type;
04255                 }
04256                 if(!$typeDef = $this->getTypeDef($uqType, $ns)){
04257                         $this->setError("$type ($uqType) is not a supported type.");
04258                         $this->debug("in serializeType: $type ($uqType) is not a supported type.");
04259                         return false;
04260                 } else {
04261                         $this->debug("in serializeType: found typeDef");
04262                         $this->appendDebug('typeDef=' . $this->varDump($typeDef));
04263                 }
04264                 $phpType = $typeDef['phpType'];
04265                 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
04266                 // if php type == struct, map value to the <all> element names
04267                 if ($phpType == 'struct') {
04268                         if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
04269                                 $elementName = $uqType;
04270                                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04271                                         $elementNS = " xmlns=\"$ns\"";
04272                                 } else {
04273                                         $elementNS = " xmlns=\"\"";
04274                                 }
04275                         } else {
04276                                 $elementName = $name;
04277                                 if ($unqualified) {
04278                                         $elementNS = " xmlns=\"\"";
04279                                 } else {
04280                                         $elementNS = '';
04281                                 }
04282                         }
04283                         if (is_null($value)) {
04284                                 if ($use == 'literal') {
04285                                         // TODO: depends on minOccurs
04286                                         $xml = "<$elementName$elementNS/>";
04287                                 } else {
04288                                         $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
04289                                 }
04290                                 $this->debug("in serializeType: returning: $xml");
04291                                 return $xml;
04292                         }
04293                         if (is_object($value)) {
04294                                 $value = get_object_vars($value);
04295                         }
04296                         if (is_array($value)) {
04297                                 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
04298                                 if ($use == 'literal') {
04299                                         if ($forceType) {
04300                                                 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
04301                                         } else {
04302                                                 $xml = "<$elementName$elementNS$elementAttrs>";
04303                                         }
04304                                 } else {
04305                                         $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
04306                                 }
04307 
04308                                 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
04309                                 $xml .= "</$elementName>";
04310                         } else {
04311                                 $this->debug("in serializeType: phpType is struct, but value is not an array");
04312                                 $this->setError("phpType is struct, but value is not an array: see debug output for details");
04313                                 $xml = '';
04314                         }
04315                 } elseif ($phpType == 'array') {
04316                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04317                                 $elementNS = " xmlns=\"$ns\"";
04318                         } else {
04319                                 if ($unqualified) {
04320                                         $elementNS = " xmlns=\"\"";
04321                                 } else {
04322                                         $elementNS = '';
04323                                 }
04324                         }
04325                         if (is_null($value)) {
04326                                 if ($use == 'literal') {
04327                                         // TODO: depends on minOccurs
04328                                         $xml = "<$name$elementNS/>";
04329                                 } else {
04330                                         $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
04331                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
04332                                                 ":Array\" " .
04333                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
04334                                                 ':arrayType="' .
04335                                                 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
04336                                                 ':' .
04337                                                 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
04338                                 }
04339                                 $this->debug("in serializeType: returning: $xml");
04340                                 return $xml;
04341                         }
04342                         if (isset($typeDef['multidimensional'])) {
04343                                 $nv = array();
04344                                 foreach($value as $v) {
04345                                         $cols = ',' . sizeof($v);
04346                                         $nv = array_merge($nv, $v);
04347                                 }
04348                                 $value = $nv;
04349                         } else {
04350                                 $cols = '';
04351                         }
04352                         if (is_array($value) && sizeof($value) >= 1) {
04353                                 $rows = sizeof($value);
04354                                 $contents = '';
04355                                 foreach($value as $k => $v) {
04356                                         $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
04357                                         //if (strpos($typeDef['arrayType'], ':') ) {
04358                                         if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
04359                                             $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
04360                                         } else {
04361                                             $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
04362                                         }
04363                                 }
04364                         } else {
04365                                 $rows = 0;
04366                                 $contents = null;
04367                         }
04368                         // TODO: for now, an empty value will be serialized as a zero element
04369                         // array.  Revisit this when coding the handling of null/nil values.
04370                         if ($use == 'literal') {
04371                                 $xml = "<$name$elementNS>"
04372                                         .$contents
04373                                         ."</$name>";
04374                         } else {
04375                                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
04376                                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
04377                                         .':arrayType="'
04378                                         .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
04379                                         .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
04380                                         .$contents
04381                                         ."</$name>";
04382                         }
04383                 } elseif ($phpType == 'scalar') {
04384                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04385                                 $elementNS = " xmlns=\"$ns\"";
04386                         } else {
04387                                 if ($unqualified) {
04388                                         $elementNS = " xmlns=\"\"";
04389                                 } else {
04390                                         $elementNS = '';
04391                                 }
04392                         }
04393                         if ($use == 'literal') {
04394                                 if ($forceType) {
04395                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
04396                                 } else {
04397                                         $xml = "<$name$elementNS>$value</$name>";
04398                                 }
04399                         } else {
04400                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
04401                         }
04402                 }
04403                 $this->debug("in serializeType: returning: $xml");
04404                 return $xml;
04405         }
04406 
04417         function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
04418                 $xml = '';
04419                 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
04420                         $this->debug("serialize attributes for XML Schema type $ns:$uqType");
04421                         if (is_array($value)) {
04422                                 $xvalue = $value;
04423                         } elseif (is_object($value)) {
04424                                 $xvalue = get_object_vars($value);
04425                         } else {
04426                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
04427                                 $xvalue = array();
04428                         }
04429                         foreach ($typeDef['attrs'] as $aName => $attrs) {
04430                                 if (isset($xvalue['!' . $aName])) {
04431                                         $xname = '!' . $aName;
04432                                         $this->debug("value provided for attribute $aName with key $xname");
04433                                 } elseif (isset($xvalue[$aName])) {
04434                                         $xname = $aName;
04435                                         $this->debug("value provided for attribute $aName with key $xname");
04436                                 } elseif (isset($attrs['default'])) {
04437                                         $xname = '!' . $aName;
04438                                         $xvalue[$xname] = $attrs['default'];
04439                                         $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
04440                                 } else {
04441                                         $xname = '';
04442                                         $this->debug("no value provided for attribute $aName");
04443                                 }
04444                                 if ($xname) {
04445                                         $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
04446                                 }
04447                         }
04448                 } else {
04449                         $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
04450                 }
04451                 if (isset($typeDef['extensionBase'])) {
04452                         $ns = $this->getPrefix($typeDef['extensionBase']);
04453                         $uqType = $this->getLocalPart($typeDef['extensionBase']);
04454                         if ($this->getNamespaceFromPrefix($ns)) {
04455                                 $ns = $this->getNamespaceFromPrefix($ns);
04456                         }
04457                         if ($typeDef = $this->getTypeDef($uqType, $ns)) {
04458                                 $this->debug("serialize attributes for extension base $ns:$uqType");
04459                                 $xml .= $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
04460                         } else {
04461                                 $this->debug("extension base $ns:$uqType is not a supported type");
04462                         }
04463                 }
04464                 return $xml;
04465         }
04466 
04479         function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
04480                 $xml = '';
04481                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
04482                         $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
04483                         if (is_array($value)) {
04484                                 $xvalue = $value;
04485                         } elseif (is_object($value)) {
04486                                 $xvalue = get_object_vars($value);
04487                         } else {
04488                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
04489                                 $xvalue = array();
04490                         }
04491                         // toggle whether all elements are present - ideally should validate against schema
04492                         if (count($typeDef['elements']) != count($xvalue)){
04493                                 $optionals = true;
04494                         }
04495                         foreach ($typeDef['elements'] as $eName => $attrs) {
04496                                 if (!isset($xvalue[$eName])) {
04497                                         if (isset($attrs['default'])) {
04498                                                 $xvalue[$eName] = $attrs['default'];
04499                                                 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
04500                                         }
04501                                 }
04502                                 // if user took advantage of a minOccurs=0, then only serialize named parameters
04503                                 if (isset($optionals)
04504                                     && (!isset($xvalue[$eName]))
04505                                         && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
04506                                         ){
04507                                         if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
04508                                                 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
04509                                         }
04510                                         // do nothing
04511                                         $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
04512                                 } else {
04513                                         // get value
04514                                         if (isset($xvalue[$eName])) {
04515                                             $v = $xvalue[$eName];
04516                                         } else {
04517                                             $v = null;
04518                                         }
04519                                         if (isset($attrs['form'])) {
04520                                                 $unqualified = ($attrs['form'] == 'unqualified');
04521                                         } else {
04522                                                 $unqualified = false;
04523                                         }
04524                                         if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
04525                                                 $vv = $v;
04526                                                 foreach ($vv as $k => $v) {
04527                                                         if (isset($attrs['type']) || isset($attrs['ref'])) {
04528                                                                 // serialize schema-defined type
04529                                                             $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
04530                                                         } else {
04531                                                                 // serialize generic type (can this ever really happen?)
04532                                                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
04533                                                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
04534                                                         }
04535                                                 }
04536                                         } else {
04537                                                 if (isset($attrs['type']) || isset($attrs['ref'])) {
04538                                                         // serialize schema-defined type
04539                                                     $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
04540                                                 } else {
04541                                                         // serialize generic type (can this ever really happen?)
04542                                                     $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
04543                                                     $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
04544                                                 }
04545                                         }
04546                                 }
04547                         }
04548                 } else {
04549                         $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
04550                 }
04551                 if (isset($typeDef['extensionBase'])) {
04552                         $ns = $this->getPrefix($typeDef['extensionBase']);
04553                         $uqType = $this->getLocalPart($typeDef['extensionBase']);
04554                         if ($this->getNamespaceFromPrefix($ns)) {
04555                                 $ns = $this->getNamespaceFromPrefix($ns);
04556                         }
04557                         if ($typeDef = $this->getTypeDef($uqType, $ns)) {
04558                                 $this->debug("serialize elements for extension base $ns:$uqType");
04559                                 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
04560                         } else {
04561                                 $this->debug("extension base $ns:$uqType is not a supported type");
04562                         }
04563                 }
04564                 return $xml;
04565         }
04566 
04581         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
04582                 if (count($elements) > 0) {
04583                 foreach($elements as $n => $e){
04584                     // expand each element
04585                     foreach ($e as $k => $v) {
04586                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
04587                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
04588                             $ee[$k] = $v;
04589                         }
04590                         $eElements[$n] = $ee;
04591                 }
04592                 $elements = $eElements;
04593                 }
04594 
04595                 if (count($attrs) > 0) {
04596                 foreach($attrs as $n => $a){
04597                     // expand each attribute
04598                     foreach ($a as $k => $v) {
04599                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
04600                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
04601                             $aa[$k] = $v;
04602                         }
04603                         $eAttrs[$n] = $aa;
04604                 }
04605                 $attrs = $eAttrs;
04606                 }
04607 
04608                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
04609                 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
04610 
04611                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04612                 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
04613         }
04614 
04626         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
04627                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
04628 
04629                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04630                 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
04631         }
04632 
04640         function addElement($attrs) {
04641                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04642                 $this->schemas[$typens][0]->addElement($attrs);
04643         }
04644 
04659         function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
04660                 if ($use == 'encoded' && $encodingStyle == '') {
04661                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
04662                 }
04663 
04664                 if ($style == 'document') {
04665                         $elements = array();
04666                         foreach ($in as $n => $t) {
04667                                 $elements[$n] = array('name' => $n, 'type' => $t);
04668                         }
04669                         $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
04670                         $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
04671                         $in = array('parameters' => 'tns:' . $name);
04672 
04673                         $elements = array();
04674                         foreach ($out as $n => $t) {
04675                                 $elements[$n] = array('name' => $n, 'type' => $t);
04676                         }
04677                         $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
04678                         $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType'));
04679                         $out = array('parameters' => 'tns:' . $name . 'Response');
04680                 }
04681 
04682                 // get binding
04683                 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
04684                 array(
04685                 'name' => $name,
04686                 'binding' => $this->serviceName . 'Binding',
04687                 'endpoint' => $this->endpoint,
04688                 'soapAction' => $soapaction,
04689                 'style' => $style,
04690                 'input' => array(
04691                         'use' => $use,
04692                         'namespace' => $namespace,
04693                         'encodingStyle' => $encodingStyle,
04694                         'message' => $name . 'Request',
04695                         'parts' => $in),
04696                 'output' => array(
04697                         'use' => $use,
04698                         'namespace' => $namespace,
04699                         'encodingStyle' => $encodingStyle,
04700                         'message' => $name . 'Response',
04701                         'parts' => $out),
04702                 'namespace' => $namespace,
04703                 'transport' => 'http://schemas.xmlsoap.org/soap/http',
04704                 'documentation' => $documentation);
04705                 // add portTypes
04706                 // add messages
04707                 if($in)
04708                 {
04709                         foreach($in as $pName => $pType)
04710                         {
04711                                 if(strpos($pType,':')) {
04712                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
04713                                 }
04714                                 $this->messages[$name.'Request'][$pName] = $pType;
04715                         }
04716                 } else {
04717             $this->messages[$name.'Request']= '0';
04718         }
04719                 if($out)
04720                 {
04721                         foreach($out as $pName => $pType)
04722                         {
04723                                 if(strpos($pType,':')) {
04724                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
04725                                 }
04726                                 $this->messages[$name.'Response'][$pName] = $pType;
04727                         }
04728                 } else {
04729             $this->messages[$name.'Response']= '0';
04730         }
04731                 return true;
04732         }
04733 }
04734 
04735 
04736 
04745 class soap_parser extends nusoap_base {
04746 
04747         var $xml = '';
04748         var $xml_encoding = '';
04749         var $method = '';
04750         var $root_struct = '';
04751         var $root_struct_name = '';
04752         var $root_struct_namespace = '';
04753         var $root_header = '';
04754     var $document = '';                 // incoming SOAP body (text)
04755         // determines where in the message we are (envelope,header,body,method)
04756         var $status = '';
04757         var $position = 0;
04758         var $depth = 0;
04759         var $default_namespace = '';
04760         var $namespaces = array();
04761         var $message = array();
04762     var $parent = '';
04763         var $fault = false;
04764         var $fault_code = '';
04765         var $fault_str = '';
04766         var $fault_detail = '';
04767         var $depth_array = array();
04768         var $debug_flag = true;
04769         var $soapresponse = NULL;
04770         var $responseHeaders = '';      // incoming SOAP headers (text)
04771         var $body_position = 0;
04772         // for multiref parsing:
04773         // array of id => pos
04774         var $ids = array();
04775         // array of id => hrefs => pos
04776         var $multirefs = array();
04777         // toggle for auto-decoding element content
04778         var $decode_utf8 = true;
04779 
04789         function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
04790                 parent::nusoap_base();
04791                 $this->xml = $xml;
04792                 $this->xml_encoding = $encoding;
04793                 $this->method = $method;
04794                 $this->decode_utf8 = $decode_utf8;
04795 
04796                 // Check whether content has been read.
04797                 if(!empty($xml)){
04798                         // Check XML encoding
04799                         $pos_xml = strpos($xml, '<?xml');
04800                         if ($pos_xml !== FALSE) {
04801                                 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
04802                                 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
04803                                         $xml_encoding = $res[1];
04804                                         if (strtoupper($xml_encoding) != $encoding) {
04805                                                 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
04806                                                 $this->debug($err);
04807                                                 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
04808                                                         $this->setError($err);
04809                                                         return;
04810                                                 }
04811                                                 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
04812                                         } else {
04813                                                 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
04814                                         }
04815                                 } else {
04816                                         $this->debug('No encoding specified in XML declaration');
04817                                 }
04818                         } else {
04819                                 $this->debug('No XML declaration');
04820                         }
04821                         $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding);
04822                         // Create an XML parser - why not xml_parser_create_ns?
04823                         $this->parser = xml_parser_create($this->xml_encoding);
04824                         // Set the options for parsing the XML data.
04825                         //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
04826                         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
04827                         xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
04828                         // Set the object for the parser.
04829                         xml_set_object($this->parser, $this);
04830                         // Set the element handlers for the parser.
04831                         xml_set_element_handler($this->parser, 'start_element','end_element');
04832                         xml_set_character_data_handler($this->parser,'character_data');
04833 
04834                         // Parse the XML file.
04835                         if(!xml_parse($this->parser,$xml,true)){
04836                             // Display an error message.
04837                             $err = sprintf('XML error parsing SOAP payload on line %d: %s',
04838                             xml_get_current_line_number($this->parser),
04839                             xml_error_string(xml_get_error_code($this->parser)));
04840                                 $this->debug($err);
04841                                 $this->debug("XML payload:\n" . $xml);
04842                                 $this->setError($err);
04843                         } else {
04844                                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
04845                                 // get final value
04846                                 $this->soapresponse = $this->message[$this->root_struct]['result'];
04847                                 // get header value: no, because this is documented as XML string
04848 //                              if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
04849 //                                      $this->responseHeaders = $this->message[$this->root_header]['result'];
04850 //                              }
04851                                 // resolve hrefs/ids
04852                                 if(sizeof($this->multirefs) > 0){
04853                                         foreach($this->multirefs as $id => $hrefs){
04854                                                 $this->debug('resolving multirefs for id: '.$id);
04855                                                 $idVal = $this->buildVal($this->ids[$id]);
04856                                                 if (is_array($idVal) && isset($idVal['!id'])) {
04857                                                         unset($idVal['!id']);
04858                                                 }
04859                                                 foreach($hrefs as $refPos => $ref){
04860                                                         $this->debug('resolving href at pos '.$refPos);
04861                                                         $this->multirefs[$id][$refPos] = $idVal;
04862                                                 }
04863                                         }
04864                                 }
04865                         }
04866                         xml_parser_free($this->parser);
04867                 } else {
04868                         $this->debug('xml was empty, didn\'t parse!');
04869                         $this->setError('xml was empty, didn\'t parse!');
04870                 }
04871         }
04872 
04881         function start_element($parser, $name, $attrs) {
04882                 // position in a total number of elements, starting from 0
04883                 // update class level pos
04884                 $pos = $this->position++;
04885                 // and set mine
04886                 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
04887                 // depth = how many levels removed from root?
04888                 // set mine as current global depth and increment global depth value
04889                 $this->message[$pos]['depth'] = $this->depth++;
04890 
04891                 // else add self as child to whoever the current parent is
04892                 if($pos != 0){
04893                         $this->message[$this->parent]['children'] .= '|'.$pos;
04894                 }
04895                 // set my parent
04896                 $this->message[$pos]['parent'] = $this->parent;
04897                 // set self as current parent
04898                 $this->parent = $pos;
04899                 // set self as current value for this depth
04900                 $this->depth_array[$this->depth] = $pos;
04901                 // get element prefix
04902                 if(strpos($name,':')){
04903                         // get ns prefix
04904                         $prefix = substr($name,0,strpos($name,':'));
04905                         // get unqualified name
04906                         $name = substr(strstr($name,':'),1);
04907                 }
04908                 // set status
04909                 if($name == 'Envelope'){
04910                         $this->status = 'envelope';
04911                 } elseif($name == 'Header'){
04912                         $this->root_header = $pos;
04913                         $this->status = 'header';
04914                 } elseif($name == 'Body'){
04915                         $this->status = 'body';
04916                         $this->body_position = $pos;
04917                 // set method
04918                 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
04919                         $this->status = 'method';
04920                         $this->root_struct_name = $name;
04921                         $this->root_struct = $pos;
04922                         $this->message[$pos]['type'] = 'struct';
04923                         $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
04924                 }
04925                 // set my status
04926                 $this->message[$pos]['status'] = $this->status;
04927                 // set name
04928                 $this->message[$pos]['name'] = htmlspecialchars($name);
04929                 // set attrs
04930                 $this->message[$pos]['attrs'] = $attrs;
04931 
04932                 // loop through atts, logging ns and type declarations
04933         $attstr = '';
04934                 foreach($attrs as $key => $value){
04935                 $key_prefix = $this->getPrefix($key);
04936                         $key_localpart = $this->getLocalPart($key);
04937                         // if ns declarations, add to class level array of valid namespaces
04938             if($key_prefix == 'xmlns'){
04939                                 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
04940                                         $this->XMLSchemaVersion = $value;
04941                                         $this->namespaces['xsd'] = $this->XMLSchemaVersion;
04942                                         $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
04943                                 }
04944                 $this->namespaces[$key_localpart] = $value;
04945                                 // set method namespace
04946                                 if($name == $this->root_struct_name){
04947                                         $this->methodNamespace = $value;
04948                                 }
04949                         // if it's a type declaration, set type
04950             } elseif($key_localpart == 'type'){
04951                 $value_prefix = $this->getPrefix($value);
04952                 $value_localpart = $this->getLocalPart($value);
04953                                 $this->message[$pos]['type'] = $value_localpart;
04954                                 $this->message[$pos]['typePrefix'] = $value_prefix;
04955                 if(isset($this->namespaces[$value_prefix])){
04956                         $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
04957                 } else if(isset($attrs['xmlns:'.$value_prefix])) {
04958                                         $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
04959                 }
04960                                 // should do something here with the namespace of specified type?
04961                         } elseif($key_localpart == 'arrayType'){
04962                                 $this->message[$pos]['type'] = 'array';
04963                                 /* do arrayType ereg here
04964                                 [1]    arrayTypeValue    ::=    atype asize
04965                                 [2]    atype    ::=    QName rank*
04966                                 [3]    rank    ::=    '[' (',')* ']'
04967                                 [4]    asize    ::=    '[' length~ ']'
04968                                 [5]    length    ::=    nextDimension* Digit+
04969                                 [6]    nextDimension    ::=    Digit+ ','
04970                                 */
04971                                 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
04972                                 if(ereg($expr,$value,$regs)){
04973                                         $this->message[$pos]['typePrefix'] = $regs[1];
04974                                         $this->message[$pos]['arrayTypePrefix'] = $regs[1];
04975                         if (isset($this->namespaces[$regs[1]])) {
04976                                 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
04977                         } else if (isset($attrs['xmlns:'.$regs[1]])) {
04978                                                 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
04979                         }
04980                                         $this->message[$pos]['arrayType'] = $regs[2];
04981                                         $this->message[$pos]['arraySize'] = $regs[3];
04982                                         $this->message[$pos]['arrayCols'] = $regs[4];
04983                                 }
04984                         // specifies nil value (or not)
04985                         } elseif ($key_localpart == 'nil'){
04986                                 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
04987                         // some other attribute
04988                         } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
04989                                 $this->message[$pos]['xattrs']['!' . $key] = $value;
04990                         }
04991 
04992                         if ($key == 'xmlns') {
04993                                 $this->default_namespace = $value;
04994                         }
04995                         // log id
04996                         if($key == 'id'){
04997                                 $this->ids[$value] = $pos;
04998                         }
04999                         // root
05000                         if($key_localpart == 'root' && $value == 1){
05001                                 $this->status = 'method';
05002                                 $this->root_struct_name = $name;
05003                                 $this->root_struct = $pos;
05004                                 $this->debug("found root struct $this->root_struct_name, pos $pos");
05005                         }
05006             // for doclit
05007             $attstr .= " $key=\"$value\"";
05008                 }
05009         // get namespace - must be done after namespace atts are processed
05010                 if(isset($prefix)){
05011                         $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
05012                         $this->default_namespace = $this->namespaces[$prefix];
05013                 } else {
05014                         $this->message[$pos]['namespace'] = $this->default_namespace;
05015                 }
05016         if($this->status == 'header'){
05017                 if ($this->root_header != $pos) {
05018                         $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
05019                 }
05020         } elseif($this->root_struct_name != ''){
05021                 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
05022         }
05023         }
05024 
05032         function end_element($parser, $name) {
05033                 // position of current element is equal to the last value left in depth_array for my depth
05034                 $pos = $this->depth_array[$this->depth--];
05035 
05036         // get element prefix
05037                 if(strpos($name,':')){
05038                         // get ns prefix
05039                         $prefix = substr($name,0,strpos($name,':'));
05040                         // get unqualified name
05041                         $name = substr(strstr($name,':'),1);
05042                 }
05043 
05044                 // build to native type
05045                 if(isset($this->body_position) && $pos > $this->body_position){
05046                         // deal w/ multirefs
05047                         if(isset($this->message[$pos]['attrs']['href'])){
05048                                 // get id
05049                                 $id = substr($this->message[$pos]['attrs']['href'],1);
05050                                 // add placeholder to href array
05051                                 $this->multirefs[$id][$pos] = 'placeholder';
05052                                 // add set a reference to it as the result value
05053                                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
05054             // build complexType values
05055                         } elseif($this->message[$pos]['children'] != ''){
05056                                 // if result has already been generated (struct/array)
05057                                 if(!isset($this->message[$pos]['result'])){
05058                                         $this->message[$pos]['result'] = $this->buildVal($pos);
05059                                 }
05060                         // build complexType values of attributes and possibly simpleContent
05061                         } elseif (isset($this->message[$pos]['xattrs'])) {
05062                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
05063                                         $this->message[$pos]['xattrs']['!'] = null;
05064                                 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
05065                         if (isset($this->message[$pos]['type'])) {
05066                                                 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
05067                                         } else {
05068                                                 $parent = $this->message[$pos]['parent'];
05069                                                 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
05070                                                         $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
05071                                                 } else {
05072                                                         $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
05073                                                 }
05074                                         }
05075                                 }
05076                                 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
05077                         // set value of simpleType (or nil complexType)
05078                         } else {
05079                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
05080                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
05081                                         $this->message[$pos]['xattrs']['!'] = null;
05082                                 } elseif (isset($this->message[$pos]['type'])) {
05083                                         $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
05084                                 } else {
05085                                         $parent = $this->message[$pos]['parent'];
05086                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
05087                                                 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
05088                                         } else {
05089                                                 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
05090                                         }
05091                                 }
05092 
05093                                 /* add value to parent's result, if parent is struct/array
05094                                 $parent = $this->message[$pos]['parent'];
05095                                 if($this->message[$parent]['type'] != 'map'){
05096                                         if(strtolower($this->message[$parent]['type']) == 'array'){
05097                                                 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
05098                                         } else {
05099                                                 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
05100                                         }
05101                                 }
05102                                 */
05103                         }
05104                 }
05105 
05106         // for doclit
05107         if($this->status == 'header'){
05108                 if ($this->root_header != $pos) {
05109                         $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
05110                 }
05111         } elseif($pos >= $this->root_struct){
05112                 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
05113         }
05114                 // switch status
05115                 if($pos == $this->root_struct){
05116                         $this->status = 'body';
05117                         $this->root_struct_namespace = $this->message[$pos]['namespace'];
05118                 } elseif($name == 'Body'){
05119                         $this->status = 'envelope';
05120                  } elseif($name == 'Header'){
05121                         $this->status = 'envelope';
05122                 } elseif($name == 'Envelope'){
05123                         //
05124                 }
05125                 // set parent back to my parent
05126                 $this->parent = $this->message[$pos]['parent'];
05127         }
05128 
05136         function character_data($parser, $data){
05137                 $pos = $this->depth_array[$this->depth];
05138                 if ($this->xml_encoding=='UTF-8'){
05139                         // TODO: add an option to disable this for folks who want
05140                         // raw UTF-8 that, e.g., might not map to iso-8859-1
05141                         // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
05142                         if($this->decode_utf8){
05143                                 $data = utf8_decode($data);
05144                         }
05145                 }
05146         $this->message[$pos]['cdata'] .= $data;
05147         // for doclit
05148         if($this->status == 'header'){
05149                 $this->responseHeaders .= $data;
05150         } else {
05151                 $this->document .= $data;
05152         }
05153         }
05154 
05161         function get_response(){
05162                 return $this->soapresponse;
05163         }
05164 
05171         function getHeaders(){
05172             return $this->responseHeaders;
05173         }
05174 
05184         function decodeSimple($value, $type, $typens) {
05185                 // TODO: use the namespace!
05186                 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
05187                         return (string) $value;
05188                 }
05189                 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
05190                         return (int) $value;
05191                 }
05192                 if ($type == 'float' || $type == 'double' || $type == 'decimal') {
05193                         return (double) $value;
05194                 }
05195                 if ($type == 'boolean') {
05196                         if (strtolower($value) == 'false' || strtolower($value) == 'f') {
05197                                 return false;
05198                         }
05199                         return (boolean) $value;
05200                 }
05201                 if ($type == 'base64' || $type == 'base64Binary') {
05202                         $this->debug('Decode base64 value');
05203                         return base64_decode($value);
05204                 }
05205                 // obscure numeric types
05206                 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
05207                         || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
05208                         || $type == 'unsignedInt'
05209                         || $type == 'unsignedShort' || $type == 'unsignedByte') {
05210                         return (int) $value;
05211                 }
05212                 // bogus: parser treats array with no elements as a simple type
05213                 if ($type == 'array') {
05214                         return array();
05215                 }
05216                 // everything else
05217                 return (string) $value;
05218         }
05219 
05228         function buildVal($pos){
05229                 if(!isset($this->message[$pos]['type'])){
05230                         $this->message[$pos]['type'] = '';
05231                 }
05232                 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
05233                 // if there are children...
05234                 if($this->message[$pos]['children'] != ''){
05235                         $this->debug('in buildVal, there are children');
05236                         $children = explode('|',$this->message[$pos]['children']);
05237                         array_shift($children); // knock off empty
05238                         // md array
05239                         if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
05240                 $r=0; // rowcount
05241                 $c=0; // colcount
05242                 foreach($children as $child_pos){
05243                                         $this->debug("in buildVal, got an MD array element: $r, $c");
05244                                         $params[$r][] = $this->message[$child_pos]['result'];
05245                                     $c++;
05246                                     if($c == $this->message[$pos]['arrayCols']){
05247                                         $c = 0;
05248                                                 $r++;
05249                                     }
05250                 }
05251             // array
05252                         } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
05253                 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
05254                 foreach($children as $child_pos){
05255                         $params[] = &$this->message[$child_pos]['result'];
05256                 }
05257             // apache Map type: java hashtable
05258             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
05259                 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
05260                 foreach($children as $child_pos){
05261                         $kv = explode("|",$this->message[$child_pos]['children']);
05262                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
05263                 }
05264             // generic compound type
05265             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
05266                     } else {
05267                         // Apache Vector type: treat as an array
05268                 $this->debug('in buildVal, adding Java Vector '.$this->message[$pos]['name']);
05269                                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
05270                                         $notstruct = 1;
05271                                 } else {
05272                                         $notstruct = 0;
05273                     }
05274                 //
05275                 foreach($children as $child_pos){
05276                         if($notstruct){
05277                                 $params[] = &$this->message[$child_pos]['result'];
05278                         } else {
05279                                 if (isset($params[$this->message[$child_pos]['name']])) {
05280                                         // de-serialize repeated element name into an array
05281                                         if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
05282                                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
05283                                         }
05284                                         $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
05285                                 } else {
05286                                                 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
05287                                             }
05288                         }
05289                 }
05290                         }
05291                         if (isset($this->message[$pos]['xattrs'])) {
05292                 $this->debug('in buildVal, handling attributes');
05293                                 foreach ($this->message[$pos]['xattrs'] as $n => $v) {
05294                                         $params[$n] = $v;
05295                                 }
05296                         }
05297                         // handle simpleContent
05298                         if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
05299                 $this->debug('in buildVal, handling simpleContent');
05300                 if (isset($this->message[$pos]['type'])) {
05301                                         $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
05302                                 } else {
05303                                         $parent = $this->message[$pos]['parent'];
05304                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
05305                                                 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
05306                                         } else {
05307                                                 $params['!'] = $this->message[$pos]['cdata'];
05308                                         }
05309                                 }
05310                         }
05311                         return is_array($params) ? $params : array();
05312                 } else {
05313                 $this->debug('in buildVal, no children, building scalar');
05314                         $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
05315                 if (isset($this->message[$pos]['type'])) {
05316                                 return $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
05317                         }
05318                         $parent = $this->message[$pos]['parent'];
05319                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
05320                                 return $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
05321                         }
05322                 return $this->message[$pos]['cdata'];
05323                 }
05324         }
05325 }
05326 
05327 
05328 
05348 class soapclient extends nusoap_base  {
05349 
05350         var $username = '';
05351         var $password = '';
05352         var $authtype = '';
05353         var $certRequest = array();
05354         var $requestHeaders = false;    // SOAP headers in request (text)
05355         var $responseHeaders = '';              // SOAP headers from response (incomplete namespace resolution) (text)
05356         var $document = '';                             // SOAP body response portion (incomplete namespace resolution) (text)
05357         var $endpoint;
05358         var $forceEndpoint = '';                // overrides WSDL endpoint
05359     var $proxyhost = '';
05360     var $proxyport = '';
05361         var $proxyusername = '';
05362         var $proxypassword = '';
05363     var $xml_encoding = '';                     // character set encoding of incoming (response) messages
05364         var $http_encoding = false;
05365         var $timeout = 0;                               // HTTP connection timeout
05366         var $response_timeout = 30;             // HTTP response timeout
05367         var $endpointType = '';                 // soap|wsdl, empty for WSDL initialization error
05368         var $persistentConnection = false;
05369         var $defaultRpcParams = false;  // This is no longer used
05370         var $request = '';                              // HTTP request
05371         var $response = '';                             // HTTP response
05372         var $responseData = '';                 // SOAP payload of response
05373         var $cookies = array();                 // Cookies from response or for request
05374     var $decode_utf8 = true;            // toggles whether the parser decodes element content w/ utf8_decode()
05375         var $operations = array();              // WSDL operations, empty for WSDL initialization error
05376 
05377         /*
05378          * fault related variables
05379          */
05384         var $fault;
05389         var $faultcode;
05394         var $faultstring;
05399         var $faultdetail;
05400 
05415         function soapclient($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
05416                 parent::nusoap_base();
05417                 $this->endpoint = $endpoint;
05418                 $this->proxyhost = $proxyhost;
05419                 $this->proxyport = $proxyport;
05420                 $this->proxyusername = $proxyusername;
05421                 $this->proxypassword = $proxypassword;
05422                 $this->timeout = $timeout;
05423                 $this->response_timeout = $response_timeout;
05424 
05425                 // make values
05426                 if($wsdl){
05427                         if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
05428                                 $this->wsdl = $endpoint;
05429                                 $this->endpoint = $this->wsdl->wsdl;
05430                                 $this->wsdlFile = $this->endpoint;
05431                                 $this->debug('existing wsdl instance created from ' . $this->endpoint);
05432                         } else {
05433                                 $this->wsdlFile = $this->endpoint;
05434 
05435                                 // instantiate wsdl object and parse wsdl file
05436                                 $this->debug('instantiating wsdl class with doc: '.$endpoint);
05437                                 $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
05438                         }
05439                         $this->appendDebug($this->wsdl->getDebug());
05440                         $this->wsdl->clearDebug();
05441                         // catch errors
05442                         if($errstr = $this->wsdl->getError()){
05443                                 $this->debug('got wsdl error: '.$errstr);
05444                                 $this->setError('wsdl error: '.$errstr);
05445                         } elseif($this->operations = $this->wsdl->getOperations()){
05446                                 $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
05447                                 $this->endpointType = 'wsdl';
05448                         } else {
05449                                 $this->debug( 'getOperations returned false');
05450                                 $this->setError('no operations defined in the WSDL document!');
05451                         }
05452                 } else {
05453                         $this->debug("instantiate SOAP with endpoint at $endpoint");
05454                         $this->endpointType = 'soap';
05455                 }
05456         }
05457 
05483         function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
05484                 $this->operation = $operation;
05485                 $this->fault = false;
05486                 $this->setError('');
05487                 $this->request = '';
05488                 $this->response = '';
05489                 $this->responseData = '';
05490                 $this->faultstring = '';
05491                 $this->faultcode = '';
05492                 $this->opData = array();
05493 
05494                 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
05495                 $this->appendDebug('params=' . $this->varDump($params));
05496                 $this->appendDebug('headers=' . $this->varDump($headers));
05497                 if ($headers) {
05498                         $this->requestHeaders = $headers;
05499                 }
05500                 // serialize parameters
05501                 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
05502                         // use WSDL for operation
05503                         $this->opData = $opData;
05504                         $this->debug("found operation");
05505                         $this->appendDebug('opData=' . $this->varDump($opData));
05506                         if (isset($opData['soapAction'])) {
05507                                 $soapAction = $opData['soapAction'];
05508                         }
05509                         if (! $this->forceEndpoint) {
05510                                 $this->endpoint = $opData['endpoint'];
05511                         } else {
05512                                 $this->endpoint = $this->forceEndpoint;
05513                         }
05514                         $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     $namespace;
05515                         $style = $opData['style'];
05516                         $use = $opData['input']['use'];
05517                         // add ns to ns array
05518                         if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
05519                                 $nsPrefix = 'ns' . rand(1000, 9999);
05520                                 $this->wsdl->namespaces[$nsPrefix] = $namespace;
05521                         }
05522             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
05523                         // serialize payload
05524                         if (is_string($params)) {
05525                                 $this->debug("serializing param string for WSDL operation $operation");
05526                                 $payload = $params;
05527                         } elseif (is_array($params)) {
05528                                 $this->debug("serializing param array for WSDL operation $operation");
05529                                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
05530                         } else {
05531                                 $this->debug('params must be array or string');
05532                                 $this->setError('params must be array or string');
05533                                 return false;
05534                         }
05535             $usedNamespaces = $this->wsdl->usedNamespaces;
05536                         if (isset($opData['input']['encodingStyle'])) {
05537                                 $encodingStyle = $opData['input']['encodingStyle'];
05538                         } else {
05539                                 $encodingStyle = '';
05540                         }
05541                         $this->appendDebug($this->wsdl->getDebug());
05542                         $this->wsdl->clearDebug();
05543                         if ($errstr = $this->wsdl->getError()) {
05544                                 $this->debug('got wsdl error: '.$errstr);
05545                                 $this->setError('wsdl error: '.$errstr);
05546                                 return false;
05547                         }
05548                 } elseif($this->endpointType == 'wsdl') {
05549                         // operation not in WSDL
05550                         $this->appendDebug($this->wsdl->getDebug());
05551                         $this->wsdl->clearDebug();
05552                         $this->setError( 'operation '.$operation.' not present.');
05553                         $this->debug("operation '$operation' not present.");
05554                         return false;
05555                 } else {
05556                         // no WSDL
05557                         //$this->namespaces['ns1'] = $namespace;
05558                         $nsPrefix = 'ns' . rand(1000, 9999);
05559                         // serialize
05560                         $payload = '';
05561                         if (is_string($params)) {
05562                                 $this->debug("serializing param string for operation $operation");
05563                                 $payload = $params;
05564                         } elseif (is_array($params)) {
05565                                 $this->debug("serializing param array for operation $operation");
05566                                 foreach($params as $k => $v){
05567                                         $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
05568                                 }
05569                         } else {
05570                                 $this->debug('params must be array or string');
05571                                 $this->setError('params must be array or string');
05572                                 return false;
05573                         }
05574                         $usedNamespaces = array();
05575                         if ($use == 'encoded') {
05576                                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
05577                         } else {
05578                                 $encodingStyle = '';
05579                         }
05580                 }
05581                 // wrap RPC calls with method element
05582                 if ($style == 'rpc') {
05583                         if ($use == 'literal') {
05584                                 $this->debug("wrapping RPC request with literal method element");
05585                                 if ($namespace) {
05586                                         $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>";
05587                                 } else {
05588                                         $payload = "<$operation>" . $payload . "</$operation>";
05589                                 }
05590                         } else {
05591                                 $this->debug("wrapping RPC request with encoded method element");
05592                                 if ($namespace) {
05593                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
05594                                                                 $payload .
05595                                                                 "</$nsPrefix:$operation>";
05596                                 } else {
05597                                         $payload = "<$operation>" .
05598                                                                 $payload .
05599                                                                 "</$operation>";
05600                                 }
05601                         }
05602                 }
05603                 // serialize envelope
05604                 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
05605                 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
05606                 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
05607                 // send
05608                 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
05609                 if($errstr = $this->getError()){
05610                         $this->debug('Error: '.$errstr);
05611                         return false;
05612                 } else {
05613                         $this->return = $return;
05614                         $this->debug('sent message successfully and got a(n) '.gettype($return));
05615                 $this->appendDebug('return=' . $this->varDump($return));
05616 
05617                         // fault?
05618                         if(is_array($return) && isset($return['faultcode'])){
05619                                 $this->debug('got fault');
05620                                 $this->setError($return['faultcode'].': '.$return['faultstring']);
05621                                 $this->fault = true;
05622                                 foreach($return as $k => $v){
05623                                         $this->$k = $v;
05624                                         $this->debug("$k = $v<br>");
05625                                 }
05626                                 return $return;
05627                         } elseif ($style == 'document') {
05628                                 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
05629                                 // we are only going to return the first part here...sorry about that
05630                                 return $return;
05631                         } else {
05632                                 // array of return values
05633                                 if(is_array($return)){
05634                                         // multiple 'out' parameters, which we return wrapped up
05635                                         // in the array
05636                                         if(sizeof($return) > 1){
05637                                                 return $return;
05638                                         }
05639                                         // single 'out' parameter (normally the return value)
05640                                         $return = array_shift($return);
05641                                         $this->debug('return shifted value: ');
05642                                         $this->appendDebug($this->varDump($return));
05643                                 return $return;
05644                                 // nothing returned (ie, echoVoid)
05645                                 } else {
05646                                         return "";
05647                                 }
05648                         }
05649                 }
05650         }
05651 
05659         function getOperationData($operation){
05660                 if(isset($this->operations[$operation])){
05661                         return $this->operations[$operation];
05662                 }
05663                 $this->debug("No data for operation: $operation");
05664         }
05665 
05680         function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
05681                 $this->checkCookies();
05682                 // detect transport
05683                 switch(true){
05684                         // http(s)
05685                         case ereg('^http',$this->endpoint):
05686                                 $this->debug('transporting via HTTP');
05687                                 if($this->persistentConnection == true && is_object($this->persistentConnection)){
05688                                         $http =& $this->persistentConnection;
05689                                 } else {
05690                                         $http = new soap_transport_http($this->endpoint);
05691                                         if ($this->persistentConnection) {
05692                                                 $http->usePersistentConnection();
05693                                         }
05694                                 }
05695                                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
05696                                 $http->setSOAPAction($soapaction);
05697                                 if($this->proxyhost && $this->proxyport){
05698                                         $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
05699                                 }
05700                 if($this->authtype != '') {
05701                                         $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
05702                                 }
05703                                 if($this->http_encoding != ''){
05704                                         $http->setEncoding($this->http_encoding);
05705                                 }
05706                                 $this->debug('sending message, length='.strlen($msg));
05707                                 if(ereg('^http:',$this->endpoint)){
05708                                 //if(strpos($this->endpoint,'http:')){
05709                                         $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
05710                                 } elseif(ereg('^https',$this->endpoint)){
05711                                 //} elseif(strpos($this->endpoint,'https:')){
05712                                         //if(phpversion() == '4.3.0-dev'){
05713                                                 //$response = $http->send($msg,$timeout,$response_timeout);
05714                                 //$this->request = $http->outgoing_payload;
05715                                                 //$this->response = $http->incoming_payload;
05716                                         //} else
05717                                         $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
05718                                 } else {
05719                                         $this->setError('no http/s in endpoint url');
05720                                 }
05721                                 $this->request = $http->outgoing_payload;
05722                                 $this->response = $http->incoming_payload;
05723                                 $this->appendDebug($http->getDebug());
05724                                 $this->UpdateCookies($http->incoming_cookies);
05725 
05726                                 // save transport object if using persistent connections
05727                                 if ($this->persistentConnection) {
05728                                         $http->clearDebug();
05729                                         if (!is_object($this->persistentConnection)) {
05730                                                 $this->persistentConnection = $http;
05731                                         }
05732                                 }
05733 
05734                                 if($err = $http->getError()){
05735                                         $this->setError('HTTP Error: '.$err);
05736                                         return false;
05737                                 } elseif($this->getError()){
05738                                         return false;
05739                                 } else {
05740                                         $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
05741                                         return $this->parseResponse($http->incoming_headers, $this->responseData);
05742                                 }
05743                         break;
05744                         default:
05745                                 $this->setError('no transport found, or selected transport is not yet supported!');
05746                         return false;
05747                         break;
05748                 }
05749         }
05750 
05759     function parseResponse($headers, $data) {
05760                 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
05761                 if (!strstr($headers['content-type'], 'text/xml')) {
05762                         $this->setError('Response not of type text/xml');
05763                         return false;
05764                 }
05765                 if (strpos($headers['content-type'], '=')) {
05766                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
05767                         $this->debug('Got response encoding: ' . $enc);
05768                         if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
05769                                 $this->xml_encoding = strtoupper($enc);
05770                         } else {
05771                                 $this->xml_encoding = 'US-ASCII';
05772                         }
05773                 } else {
05774                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
05775                         $this->xml_encoding = 'ISO-8859-1';
05776                 }
05777                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
05778                 $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
05779                 // add parser debug data to our debug
05780                 $this->appendDebug($parser->getDebug());
05781                 // if parse errors
05782                 if($errstr = $parser->getError()){
05783                         $this->setError( $errstr);
05784                         // destroy the parser object
05785                         unset($parser);
05786                         return false;
05787                 } else {
05788                         // get SOAP headers
05789                         $this->responseHeaders = $parser->getHeaders();
05790                         // get decoded message
05791                         $return = $parser->get_response();
05792             // add document for doclit support
05793             $this->document = $parser->document;
05794                         // destroy the parser object
05795                         unset($parser);
05796                         // return decode message
05797                         return $return;
05798                 }
05799          }
05800 
05807         function setEndpoint($endpoint) {
05808                 $this->forceEndpoint = $endpoint;
05809         }
05810 
05817         function setHeaders($headers){
05818                 $this->requestHeaders = $headers;
05819         }
05820 
05827         function getHeaders(){
05828                 return $this->responseHeaders;
05829         }
05830 
05840         function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
05841                 $this->proxyhost = $proxyhost;
05842                 $this->proxyport = $proxyport;
05843                 $this->proxyusername = $proxyusername;
05844                 $this->proxypassword = $proxypassword;
05845         }
05846 
05856         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
05857                 $this->username = $username;
05858                 $this->password = $password;
05859                 $this->authtype = $authtype;
05860                 $this->certRequest = $certRequest;
05861         }
05862 
05869         function setHTTPEncoding($enc='gzip, deflate'){
05870                 $this->http_encoding = $enc;
05871         }
05872 
05878         function useHTTPPersistentConnection(){
05879                 $this->persistentConnection = true;
05880         }
05881 
05893         function getDefaultRpcParams() {
05894                 return $this->defaultRpcParams;
05895         }
05896 
05908         function setDefaultRpcParams($rpcParams) {
05909                 $this->defaultRpcParams = $rpcParams;
05910         }
05911 
05919         function getProxy(){
05920                 $r = rand();
05921                 $evalStr = $this->_getProxyClassCode($r);
05922                 //$this->debug("proxy class: $evalStr";
05923                 // eval the class
05924                 eval($evalStr);
05925                 // instantiate proxy object
05926                 eval("\$proxy = new soap_proxy_$r('');");
05927                 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
05928                 $proxy->endpointType = 'wsdl';
05929                 $proxy->wsdlFile = $this->wsdlFile;
05930                 $proxy->wsdl = $this->wsdl;
05931                 $proxy->operations = $this->operations;
05932                 $proxy->defaultRpcParams = $this->defaultRpcParams;
05933                 // transfer other state
05934                 $proxy->username = $this->username;
05935                 $proxy->password = $this->password;
05936                 $proxy->authtype = $this->authtype;
05937                 $proxy->proxyhost = $this->proxyhost;
05938                 $proxy->proxyport = $this->proxyport;
05939                 $proxy->proxyusername = $this->proxyusername;
05940                 $proxy->proxypassword = $this->proxypassword;
05941                 $proxy->timeout = $this->timeout;
05942                 $proxy->response_timeout = $this->response_timeout;
05943                 $proxy->http_encoding = $this->http_encoding;
05944                 $proxy->persistentConnection = $this->persistentConnection;
05945                 $proxy->requestHeaders = $this->requestHeaders;
05946                 $proxy->soap_defencoding = $this->soap_defencoding;
05947                 $proxy->endpoint = $this->endpoint;
05948                 $proxy->forceEndpoint = $this->forceEndpoint;
05949                 return $proxy;
05950         }
05951 
05958         function _getProxyClassCode($r) {
05959                 if ($this->endpointType != 'wsdl') {
05960                         $evalStr = 'A proxy can only be created for a WSDL client';
05961                         $this->setError($evalStr);
05962                         return $evalStr;
05963                 }
05964                 $evalStr = '';
05965                 foreach ($this->operations as $operation => $opData) {
05966                         if ($operation != '') {
05967                                 // create param string and param comment string
05968                                 if (sizeof($opData['input']['parts']) > 0) {
05969                                         $paramStr = '';
05970                                         $paramArrayStr = '';
05971                                         $paramCommentStr = '';
05972                                         foreach ($opData['input']['parts'] as $name => $type) {
05973                                                 $paramStr .= "\$$name, ";
05974                                                 $paramArrayStr .= "'$name' => \$$name, ";
05975                                                 $paramCommentStr .= "$type \$$name, ";
05976                                         }
05977                                         $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
05978                                         $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
05979                                         $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
05980                                 } else {
05981                                         $paramStr = '';
05982                                         $paramCommentStr = 'void';
05983                                 }
05984                                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
05985                                 $evalStr .= "// $paramCommentStr
05986         function " . str_replace('.', '__', $operation) . "($paramStr) {
05987                 \$params = array($paramArrayStr);
05988                 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
05989         }
05990         ";
05991                                 unset($paramStr);
05992                                 unset($paramCommentStr);
05993                         }
05994                 }
05995                 $evalStr = 'class soap_proxy_'.$r.' extends soapclient {
05996         '.$evalStr.'
05997 }';
05998                 return $evalStr;
05999         }
06000 
06007         function getProxyClassCode() {
06008                 $r = rand();
06009                 return $this->_getProxyClassCode($r);
06010         }
06011 
06019         function getHTTPBody($soapmsg) {
06020                 return $soapmsg;
06021         }
06022 
06031         function getHTTPContentType() {
06032                 return 'text/xml';
06033         }
06034 
06044         function getHTTPContentTypeCharset() {
06045                 return $this->soap_defencoding;
06046         }
06047 
06048         /*
06049         * whether or not parser should decode utf8 element content
06050     *
06051     * @return   always returns true
06052     * @access   public
06053     */
06054     function decodeUTF8($bool){
06055                 $this->decode_utf8 = $bool;
06056                 return true;
06057     }
06058 
06067         function setCookie($name, $value) {
06068                 if (strlen($name) == 0) {
06069                         return false;
06070                 }
06071                 $this->cookies[] = array('name' => $name, 'value' => $value);
06072                 return true;
06073         }
06074 
06081         function getCookies() {
06082                 return $this->cookies;
06083         }
06084 
06091         function checkCookies() {
06092                 if (sizeof($this->cookies) == 0) {
06093                         return true;
06094                 }
06095                 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
06096                 $curr_cookies = $this->cookies;
06097                 $this->cookies = array();
06098                 foreach ($curr_cookies as $cookie) {
06099                         if (! is_array($cookie)) {
06100                                 $this->debug('Remove cookie that is not an array');
06101                                 continue;
06102                         }
06103                         if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
06104                                 if (strtotime($cookie['expires']) > time()) {
06105                                         $this->cookies[] = $cookie;
06106                                 } else {
06107                                         $this->debug('Remove expired cookie ' . $cookie['name']);
06108                                 }
06109                         } else {
06110                                 $this->cookies[] = $cookie;
06111                         }
06112                 }
06113                 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
06114                 return true;
06115         }
06116 
06124         function UpdateCookies($cookies) {
06125                 if (sizeof($this->cookies) == 0) {
06126                         // no existing cookies: take whatever is new
06127                         if (sizeof($cookies) > 0) {
06128                                 $this->debug('Setting new cookie(s)');
06129                                 $this->cookies = $cookies;
06130                         }
06131                         return true;
06132                 }
06133                 if (sizeof($cookies) == 0) {
06134                         // no new cookies: keep what we've got
06135                         return true;
06136                 }
06137                 // merge
06138                 foreach ($cookies as $newCookie) {
06139                         if (!is_array($newCookie)) {
06140                                 continue;
06141                         }
06142                         if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
06143                                 continue;
06144                         }
06145                         $newName = $newCookie['name'];
06146 
06147                         $found = false;
06148                         for ($i = 0; $i < count($this->cookies); $i++) {
06149                                 $cookie = $this->cookies[$i];
06150                                 if (!is_array($cookie)) {
06151                                         continue;
06152                                 }
06153                                 if (!isset($cookie['name'])) {
06154                                         continue;
06155                                 }
06156                                 if ($newName != $cookie['name']) {
06157                                         continue;
06158                                 }
06159                                 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
06160                                 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
06161                                 if ($newDomain != $domain) {
06162                                         continue;
06163                                 }
06164                                 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
06165                                 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
06166                                 if ($newPath != $path) {
06167                                         continue;
06168                                 }
06169                                 $this->cookies[$i] = $newCookie;
06170                                 $found = true;
06171                                 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
06172                                 break;
06173                         }
06174                         if (! $found) {
06175                                 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
06176                                 $this->cookies[] = $newCookie;
06177                         }
06178                 }
06179                 return true;
06180         }
06181 }
06182 ?>