• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

webservice/soap/lib/nusoap.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004 $Id: nusoap.php 6577 2005-01-27 16:22:48Z smeyer $
00005 
00006 NuSOAP - Web Services Toolkit for PHP
00007 
00008 Copyright (c) 2002 NuSphere Corporation
00009 
00010 This library is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU Lesser General Public
00012 License as published by the Free Software Foundation; either
00013 version 2.1 of the License, or (at your option) any later version.
00014 
00015 This library is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 Lesser General Public License for more details.
00019 
00020 You should have received a copy of the GNU Lesser General Public
00021 License along with this library; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 
00024 If you have any questions or comments, please email:
00025 
00026 Dietrich Ayala
00027 dietrich@ganx4.com
00028 http://dietrich.ganx4.com/nusoap
00029 
00030 NuSphere Corporation
00031 http://www.nusphere.com
00032 
00033 */
00034 
00035 /* load classes
00036 
00037 // necessary classes
00038 require_once('class.soapclient.php');
00039 require_once('class.soap_val.php');
00040 require_once('class.soap_parser.php');
00041 require_once('class.soap_fault.php');
00042 
00043 // transport classes
00044 require_once('class.soap_transport_http.php');
00045 
00046 // optional add-on classes
00047 require_once('class.xmlschema.php');
00048 require_once('class.wsdl.php');
00049 
00050 // server class
00051 require_once('class.soap_server.php');*/
00052 
00061 class nusoap_base {
00062 
00063         var $title = 'NuSOAP';
00064         var $version = '0.6.7';
00065         var $revision = '$Revision: 6577 $';
00066         var $error_str = false;
00067     var $debug_str = '';
00068         // toggles automatic encoding of special characters as entities
00069         // (should always be true, I think)
00070         var $charencoding = true;
00071 
00078         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
00079         
00086         //var $soap_defencoding = 'UTF-8';
00087     var $soap_defencoding = 'ISO-8859-1';
00088 
00095         var $namespaces = array(
00096                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
00097                 'xsd' => 'http://www.w3.org/2001/XMLSchema',
00098                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
00099                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/',
00100                 'si' => 'http://soapinterop.org/xsd');
00101         var $usedNamespaces = array();
00102 
00110         var $typemap = array(
00111         'http://www.w3.org/2001/XMLSchema' => array(
00112                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
00113                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
00114                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
00115                 // derived datatypes
00116                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
00117                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
00118                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
00119                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
00120         'http://www.w3.org/1999/XMLSchema' => array(
00121                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00122                 'float'=>'double','dateTime'=>'string',
00123                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00124         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
00125         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
00126     'http://xml.apache.org/xml-soap' => array('Map')
00127         );
00128 
00135         var $xmlEntities = array('quot' => '"','amp' => '&',
00136                 'lt' => '<','gt' => '>','apos' => "'");
00137 
00144         function debug($string){
00145                 $this->debug_str .= get_class($this).": $string\n";
00146         }
00147 
00154         function expandEntities($val) {
00155                 if ($this->charencoding) {
00156                 $val = str_replace('&', '&amp;', $val);
00157                 $val = str_replace("'", '&apos;', $val);
00158                 $val = str_replace('"', '&quot;', $val);
00159                 $val = str_replace('<', '&lt;', $val);
00160                 $val = str_replace('>', '&gt;', $val);
00161             }
00162             return $val;
00163         }
00164 
00171         function getError(){
00172                 if($this->error_str != ''){
00173                         return $this->error_str;
00174                 }
00175                 return false;
00176         }
00177 
00184         function setError($str){
00185                 $this->error_str = $str;
00186         }
00187 
00195         function isArraySimpleOrStruct($val) {
00196         $keyList = array_keys($val);
00197                 foreach ($keyList as $keyListValue) {
00198                         if (!is_int($keyListValue)) {
00199                                 return 'arrayStruct';
00200                         }
00201                 }
00202                 return 'arraySimple';
00203         }
00204 
00212         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
00213         if(is_object($val) && get_class($val) == 'soapval'){
00214                 return $val->serialize($use);
00215         }
00216                 $this->debug( "in serialize_val: $val, $name, $type, $name_ns, $type_ns, $attributes, $use");
00217                 // if no name, use item
00218                 $name = (!$name|| is_numeric($name)) ? 'soapVal' : $name;
00219                 // if name has ns, add ns prefix to name
00220                 $xmlns = '';
00221         if($name_ns){
00222                         $prefix = 'nu'.rand(1000,9999);
00223                         $name = $prefix.':'.$name;
00224                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";
00225                 }
00226                 // if type is prefixed, create type prefix
00227                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
00228                         // need to fix this. shouldn't default to xsd if no ns specified
00229                     // w/o checking against typemap
00230                         $type_prefix = 'xsd';
00231                 } elseif($type_ns){
00232                         $type_prefix = 'ns'.rand(1000,9999);
00233                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
00234                 }
00235                 // serialize attributes if present
00236                 $atts = '';
00237                 if($attributes){
00238                         foreach($attributes as $k => $v){
00239                                 $atts .= " $k=\"$v\"";
00240                         }
00241                 }
00242         // serialize if an xsd built-in primitive type
00243         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
00244                 if (is_bool($val)) {
00245                         if ($type == 'boolean') {
00246                                 $val = $val ? 'true' : 'false';
00247                         } elseif (! $val) {
00248                                 $val = 0;
00249                         }
00250                         } else if (is_string($val)) {
00251                                 $val = $this->expandEntities($val);
00252                         }
00253                         if ($use == 'literal') {
00254                         return "<$name$xmlns>$val</$name>";
00255                 } else {
00256                         return "<$name$xmlns xsi:type=\"xsd:$type\">$val</$name>";
00257                 }
00258         }
00259                 // detect type and serialize
00260                 $xml = '';
00261                 switch(true) {
00262                         case ($type == '' && is_null($val)):
00263                                 if ($use == 'literal') {
00264                                         // TODO: depends on nillable
00265                                         $xml .= "<$name$xmlns/>";
00266                                 } else {
00267                                         $xml .= "<$name$xmlns xsi:nil=\"true\"/>";
00268                                 }
00269                                 break;
00270                         case (is_bool($val) || $type == 'boolean'):
00271                         if ($type == 'boolean') {
00272                                 $val = $val ? 'true' : 'false';
00273                         } elseif (! $val) {
00274                                 $val = 0;
00275                         }
00276                                 if ($use == 'literal') {
00277                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00278                                 } else {
00279                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
00280                                 }
00281                                 break;
00282                         case (is_int($val) || is_long($val) || $type == 'int'):
00283                                 if ($use == 'literal') {
00284                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00285                                 } else {
00286                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
00287                                 }
00288                                 break;
00289                         case (is_float($val)|| is_double($val) || $type == 'float'):
00290                                 if ($use == 'literal') {
00291                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00292                                 } else {
00293                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
00294                                 }
00295                                 break;
00296                         case (is_string($val) || $type == 'string'):
00297                                 $val = $this->expandEntities($val);
00298                                 if ($use == 'literal') {
00299                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00300                                 } else {
00301                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
00302                                 }
00303                                 break;
00304                         case is_object($val):
00305                                 $name = get_class($val);
00306                                 foreach(get_object_vars($val) as $k => $v){
00307                                         $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
00308                                 }
00309                                 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
00310                                 break;
00311                         break;
00312                         case (is_array($val) || $type):
00313                                 // detect if struct or array
00314                                 $valueType = $this->isArraySimpleOrStruct($val);
00315                 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
00316                                         $i = 0;
00317                                         if(is_array($val) && count($val)> 0){
00318                                                 foreach($val as $v){
00319                                 if(is_object($v) && get_class($v) ==  'soapval'){
00320                                                                 $tt_ns = $v->type_ns;
00321                                                                 $tt = $v->type;
00322                                                         } elseif (is_array($v)) {
00323                                                                 $tt = $this->isArraySimpleOrStruct($v);
00324                                                         } else {
00325                                                                 $tt = gettype($v);
00326                                 }
00327                                                         $array_types[$tt] = 1;
00328                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
00329                                                         ++$i;
00330                                                 }
00331                                                 if(count($array_types) > 1){
00332                                                         $array_typename = 'xsd:ur-type';
00333                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
00334                                                         if ($tt == 'integer') {
00335                                                                 $tt = 'int';
00336                                                         }
00337                                                         $array_typename = 'xsd:'.$tt;
00338                                                 } elseif(isset($tt) && $tt == 'arraySimple'){
00339                                                         $array_typename = 'SOAP-ENC:Array';
00340                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){
00341                                                         $array_typename = 'unnamed_struct_use_soapval';
00342                                                 } else {
00343                                                         // if type is prefixed, create type prefix
00344                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
00345                                                                  $array_typename = 'xsd:' . $tt;
00346                                                         } elseif ($tt_ns) {
00347                                                                 $tt_prefix = 'ns' . rand(1000, 9999);
00348                                                                 $array_typename = "$tt_prefix:$tt";
00349                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
00350                                                         } else {
00351                                                                 $array_typename = $tt;
00352                                                         }
00353                                                 }
00354                                                 $array_type = $i;
00355                                                 if ($use == 'literal') {
00356                                                         $type_str = '';
00357                                                 } else if (isset($type) && isset($type_prefix)) {
00358                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00359                                                 } else {
00360                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
00361                                                 }
00362                                         // empty array
00363                                         } else {
00364                                                 if ($use == 'literal') {
00365                                                         $type_str = '';
00366                                                 } else if (isset($type) && isset($type_prefix)) {
00367                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00368                                                 } else {
00369                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\"";
00370                                                 }
00371                                         }
00372                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
00373                                 } else {
00374                                         // got a struct
00375                                         if(isset($type) && isset($type_prefix)){
00376                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";
00377                                         } else {
00378                                                 $type_str = '';
00379                                         }
00380                                         if ($use == 'literal') {
00381                                                 $xml .= "<$name$xmlns $atts>";
00382                                         } else {
00383                                                 $xml .= "<$name$xmlns$type_str$atts>";
00384                                         }
00385                                         foreach($val as $k => $v){
00386                                                 // Apache Map
00387                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
00388                                                         $xml .= '<item>';
00389                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
00390                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
00391                                                         $xml .= '</item>';
00392                                                 } else {
00393                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
00394                                                 }
00395                                         }
00396                                         $xml .= "</$name>";
00397                                 }
00398                                 break;
00399                         default:
00400                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
00401                                 break;
00402                 }
00403                 return $xml;
00404         }
00405 
00417     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded'){
00418     // TODO: add an option to automatically run utf8_encode on $body and $headers
00419     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
00420     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
00421 
00422         // serialize namespaces
00423     $ns_string = '';
00424         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
00425                 $ns_string .= " xmlns:$k=\"$v\"";
00426         }
00427         if($style == 'rpc' && $use == 'encoded') {
00428                 $ns_string = ' SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string;
00429         }
00430 
00431         // serialize headers
00432         if($headers){
00433                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
00434         }
00435         // serialize envelope
00436         return
00437         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
00438         '<SOAP-ENV:Envelope'.$ns_string.">".
00439         $headers.
00440         "<SOAP-ENV:Body>".
00441                 $body.
00442         "</SOAP-ENV:Body>".
00443         "</SOAP-ENV:Envelope>";
00444     }
00445 
00446     function formatDump($str){
00447                 $str = htmlspecialchars($str);
00448                 return nl2br($str);
00449     }
00450 
00458         function contractQname($qname){
00459                 // get element namespace
00460                 //$this->xdebug("Contract $qname");
00461                 if (strrpos($qname, ':')) {
00462                         // get unqualified name
00463                         $name = substr($qname, strrpos($qname, ':') + 1);
00464                         // get ns
00465                         $ns = substr($qname, 0, strrpos($qname, ':'));
00466                         $p = $this->getPrefixFromNamespace($ns);
00467                         if ($p) {
00468                                 return $p . ':' . $name;
00469                         }
00470                         return $qname;
00471                 } else {
00472                         return $qname;
00473                 }
00474         }
00475 
00483         function expandQname($qname){
00484                 // get element prefix
00485                 if(strpos($qname,':') && !ereg('^http://',$qname)){
00486                         // get unqualified name
00487                         $name = substr(strstr($qname,':'),1);
00488                         // get ns prefix
00489                         $prefix = substr($qname,0,strpos($qname,':'));
00490                         if(isset($this->namespaces[$prefix])){
00491                                 return $this->namespaces[$prefix].':'.$name;
00492                         } else {
00493                                 return $qname;
00494                         }
00495                 } else {
00496                         return $qname;
00497                 }
00498         }
00499 
00508         function getLocalPart($str){
00509                 if($sstr = strrchr($str,':')){
00510                         // get unqualified name
00511                         return substr( $sstr, 1 );
00512                 } else {
00513                         return $str;
00514                 }
00515         }
00516 
00525         function getPrefix($str){
00526                 if($pos = strrpos($str,':')){
00527                         // get prefix
00528                         return substr($str,0,$pos);
00529                 }
00530                 return false;
00531         }
00532 
00541         function getNamespaceFromPrefix($prefix){
00542                 if (isset($this->namespaces[$prefix])) {
00543                         return $this->namespaces[$prefix];
00544                 }
00545                 //$this->setError("No namespace registered for prefix '$prefix'");
00546                 return false;
00547         }
00548 
00557         function getPrefixFromNamespace($ns) {
00558                 foreach ($this->namespaces as $p => $n) {
00559                         if ($ns == $n || $ns == $p) {
00560                             $this->usedNamespaces[$p] = $n;
00561                                 return $p;
00562                         }
00563                 }
00564                 return false;
00565         }
00566 
00567     function varDump($data) {
00568                 ob_start();
00569                 var_dump($data);
00570                 $ret_val = ob_get_contents();
00571                 ob_end_clean();
00572                 return $ret_val;
00573         }
00574 }
00575 
00576 // XML Schema Datatype Helper Functions
00577 
00578 //xsd:dateTime helpers
00579 
00586 function timestamp_to_iso8601($timestamp,$utc=true){
00587         $datestr = date('Y-m-d\TH:i:sO',$timestamp);
00588         if($utc){
00589                 $eregStr =
00590                 '([0-9]{4})-'.  // centuries & years CCYY-
00591                 '([0-9]{2})-'.  // months MM-
00592                 '([0-9]{2})'.   // days DD
00593                 'T'.                    // separator T
00594                 '([0-9]{2}):'.  // hours hh:
00595                 '([0-9]{2}):'.  // minutes mm:
00596                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
00597                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00598 
00599                 if(ereg($eregStr,$datestr,$regs)){
00600                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
00601                 }
00602                 return false;
00603         } else {
00604                 return $datestr;
00605         }
00606 }
00607 
00614 function iso8601_to_timestamp($datestr){
00615         $eregStr =
00616         '([0-9]{4})-'.  // centuries & years CCYY-
00617         '([0-9]{2})-'.  // months MM-
00618         '([0-9]{2})'.   // days DD
00619         'T'.                    // separator T
00620         '([0-9]{2}):'.  // hours hh:
00621         '([0-9]{2}):'.  // minutes mm:
00622         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
00623         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00624         if(ereg($eregStr,$datestr,$regs)){
00625                 // not utc
00626                 if($regs[8] != 'Z'){
00627                         $op = substr($regs[8],0,1);
00628                         $h = substr($regs[8],1,2);
00629                         $m = substr($regs[8],strlen($regs[8])-2,2);
00630                         if($op == '-'){
00631                                 $regs[4] = $regs[4] + $h;
00632                                 $regs[5] = $regs[5] + $m;
00633                         } elseif($op == '+'){
00634                                 $regs[4] = $regs[4] - $h;
00635                                 $regs[5] = $regs[5] - $m;
00636                         }
00637                 }
00638                 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
00639         } else {
00640                 return false;
00641         }
00642 }
00643 
00644 function usleepWindows($usec)
00645 {
00646         $start = gettimeofday();
00647         
00648         do
00649         {
00650                 $stop = gettimeofday();
00651                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
00652                 + $stop['usec'] - $start['usec'];
00653         }
00654         while ($timePassed < $usec);
00655 }
00656 
00657 ?><?php
00658 
00659 
00660 
00669 class soap_fault extends nusoap_base {
00670 
00671         var $faultcode;
00672         var $faultactor;
00673         var $faultstring;
00674         var $faultdetail;
00675 
00684         function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
00685                 $this->faultcode = $faultcode;
00686                 $this->faultactor = $faultactor;
00687                 $this->faultstring = $faultstring;
00688                 $this->faultdetail = $faultdetail;
00689         }
00690 
00696         function serialize(){
00697                 $ns_string = '';
00698                 foreach($this->namespaces as $k => $v){
00699                         $ns_string .= "\n  xmlns:$k=\"$v\"";
00700                 }
00701                 $return_msg =
00702                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
00703                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
00704                                 '<SOAP-ENV:Body>'.
00705                                 '<SOAP-ENV:Fault>'.
00706                                         '<faultcode>'.$this->expandEntities($this->faultcode).'</faultcode>'.
00707                                         '<faultactor>'.$this->expandEntities($this->faultactor).'</faultactor>'.
00708                                         '<faultstring>'.$this->expandEntities($this->faultstring).'</faultstring>'.
00709                                         '<detail>'.$this->serialize_val($this->faultdetail).'</detail>'.
00710                                 '</SOAP-ENV:Fault>'.
00711                                 '</SOAP-ENV:Body>'.
00712                         '</SOAP-ENV:Envelope>';
00713                 return $return_msg;
00714         }
00715 }
00716 
00717 
00718 
00719 ?><?php
00720 
00721 
00722 
00734 class XMLSchema extends nusoap_base  {
00735         
00736         // files
00737         var $schema = '';
00738         var $xml = '';
00739         // namespaces
00740         var $enclosingNamespaces;
00741         // schema info
00742         var $schemaInfo = array();
00743         var $schemaTargetNamespace = '';
00744         // types, elements, attributes defined by the schema
00745         var $attributes = array();
00746         var $complexTypes = array();
00747         var $currentComplexType = false;
00748         var $elements = array();
00749         var $currentElement = false;
00750         var $simpleTypes = array();
00751         var $currentSimpleType = false;
00752         // imports
00753         var $imports = array();
00754         // parser vars
00755         var $parser;
00756         var $position = 0;
00757         var $depth = 0;
00758         var $depth_array = array();
00759         var $message = array();
00760         var $defaultNamespace = array();
00761     
00770         function XMLSchema($schema='',$xml='',$namespaces=array()){
00771 
00772                 $this->debug('xmlschema class instantiated, inside constructor');
00773                 // files
00774                 $this->schema = $schema;
00775                 $this->xml = $xml;
00776 
00777                 // namespaces
00778                 $this->enclosingNamespaces = $namespaces;
00779                 $this->namespaces = array_merge($this->namespaces, $namespaces);
00780 
00781                 // parse schema file
00782                 if($schema != ''){
00783                         $this->debug('initial schema file: '.$schema);
00784                         $this->parseFile($schema, 'schema');
00785                 }
00786 
00787                 // parse xml file
00788                 if($xml != ''){
00789                         $this->debug('initial xml file: '.$xml);
00790                         $this->parseFile($xml, 'xml');
00791                 }
00792 
00793         }
00794 
00803         function parseFile($xml,$type){
00804                 // parse xml file
00805                 if($xml != ""){
00806                         $xmlStr = @join("",@file($xml));
00807                         if($xmlStr == ""){
00808                                 $msg = 'Error reading XML from '.$xml;
00809                                 $this->setError($msg);
00810                                 $this->debug($msg);
00811                         return false;
00812                         } else {
00813                                 $this->debug("parsing $xml");
00814                                 $this->parseString($xmlStr,$type);
00815                                 $this->debug("done parsing $xml");
00816                         return true;
00817                         }
00818                 }
00819                 return false;
00820         }
00821 
00829         function parseString($xml,$type){
00830                 // parse xml string
00831                 if($xml != ""){
00832 
00833                 // Create an XML parser.
00834                 $this->parser = xml_parser_create();
00835                 // Set the options for parsing the XML data.
00836                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
00837 
00838                 // Set the object for the parser.
00839                 xml_set_object($this->parser, $this);
00840 
00841                 // Set the element handlers for the parser.
00842                         if($type == "schema"){
00843                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
00844                         xml_set_character_data_handler($this->parser,'schemaCharacterData');
00845                         } elseif($type == "xml"){
00846                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
00847                         xml_set_character_data_handler($this->parser,'xmlCharacterData');
00848                         }
00849 
00850                     // Parse the XML file.
00851                     if(!xml_parse($this->parser,$xml,true)){
00852                         // Display an error message.
00853                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
00854                                 xml_get_current_line_number($this->parser),
00855                                 xml_error_string(xml_get_error_code($this->parser))
00856                                 );
00857                                 $this->debug($errstr);
00858                                 $this->debug("XML payload:\n" . $xml);
00859                                 $this->setError($errstr);
00860                 }
00861             
00862                         xml_parser_free($this->parser);
00863                 } else{
00864                         $this->debug('no xml passed to parseString()!!');
00865                         $this->setError('no xml passed to parseString()!!');
00866                 }
00867         }
00868 
00877         function schemaStartElement($parser, $name, $attrs) {
00878                 
00879                 // position in the total number of elements, starting from 0
00880                 $pos = $this->position++;
00881                 $depth = $this->depth++;
00882                 // set self as current value for this depth
00883                 $this->depth_array[$depth] = $pos;
00884                 $this->message[$pos] = array('cdata' => ''); 
00885                 if ($depth > 0) {
00886                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
00887                 } else {
00888                         $this->defaultNamespace[$pos] = false;
00889                 }
00890 
00891                 // get element prefix
00892                 if($prefix = $this->getPrefix($name)){
00893                         // get unqualified name
00894                         $name = $this->getLocalPart($name);
00895                 } else {
00896                 $prefix = '';
00897         }
00898                 
00899         // loop thru attributes, expanding, and registering namespace declarations
00900         if(count($attrs) > 0){
00901                 foreach($attrs as $k => $v){
00902                 // if ns declarations, add to class level array of valid namespaces
00903                                 if(ereg("^xmlns",$k)){
00904                         //$this->xdebug("$k: $v");
00905                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
00906                         if($ns_prefix = substr(strrchr($k,':'),1)){
00907                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");
00908                                                 $this->namespaces[$ns_prefix] = $v;
00909                                         } else {
00910                                                 $this->defaultNamespace[$pos] = $v;
00911                                                 if (! $this->getPrefixFromNamespace($v)) {
00912                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
00913                                                 }
00914                                         }
00915                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema'){
00916                                                 $this->XMLSchemaVersion = $v;
00917                                                 $this->namespaces['xsi'] = $v.'-instance';
00918                                         }
00919                                 }
00920                 }
00921                 foreach($attrs as $k => $v){
00922                 // expand each attribute
00923                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
00924                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
00925                         $eAttrs[$k] = $v;
00926                 }
00927                 $attrs = $eAttrs;
00928         } else {
00929                 $attrs = array();
00930         }
00931                 // find status, register data
00932                 switch($name){
00933                         case 'all':
00934                         case 'choice':
00935                         case 'sequence':
00936                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
00937                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
00938                                 if($name == 'all' || $name == 'sequence'){
00939                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
00940                                 }
00941                         break;
00942                         case 'attribute':
00943                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
00944                 $this->xdebug("parsing attribute " . $this->varDump($attrs));
00945                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
00946                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
00947                                         if (!strpos($v, ':')) {
00948                                                 // no namespace in arrayType attribute value...
00949                                                 if ($this->defaultNamespace[$pos]) {
00950                                                         // ...so use the default
00951                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
00952                                                 }
00953                                         }
00954                 }
00955                 if(isset($attrs['name'])){
00956                                         $this->attributes[$attrs['name']] = $attrs;
00957                                         $aname = $attrs['name'];
00958                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
00959                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
00960                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
00961                         } else {
00962                                 $aname = '';
00963                         }
00964                                 } elseif(isset($attrs['ref'])){
00965                                         $aname = $attrs['ref'];
00966                     $this->attributes[$attrs['ref']] = $attrs;
00967                                 }
00968                 
00969                                 if(isset($this->currentComplexType)){
00970                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
00971                                 } elseif(isset($this->currentElement)){
00972                                         $this->elements[$this->currentElement]['attrs'][$aname] = $attrs;
00973                                 }
00974                                 // arrayType attribute
00975                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
00976                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
00977                         $prefix = $this->getPrefix($aname);
00978                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
00979                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
00980                                         } else {
00981                                                 $v = '';
00982                                         }
00983                     if(strpos($v,'[,]')){
00984                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
00985                     }
00986                     $v = substr($v,0,strpos($v,'[')); // clip the []
00987                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
00988                         $v = $this->XMLSchemaVersion.':'.$v;
00989                     }
00990                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
00991                                 }
00992                         break;
00993                         case 'complexType':
00994                                 if(isset($attrs['name'])){
00995                                         $this->xdebug('processing named complexType '.$attrs['name']);
00996                                         $this->currentElement = false;
00997                                         $this->currentComplexType = $attrs['name'];
00998                                         $this->complexTypes[$this->currentComplexType] = $attrs;
00999                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01000                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01001                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01002                                         } else {
01003                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01004                                         }
01005                                 }else{
01006                                         $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
01007                                         $this->currentComplexType = $this->currentElement . '_ContainedType';
01008                                         $this->currentElement = false;
01009                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01010                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01011                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01012                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01013                                         } else {
01014                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01015                                         }
01016                                 }
01017                         break;
01018                         case 'element':
01019                                 // elements defined as part of a complex type should
01020                                 // not really be added to $this->elements, but for some
01021                                 // reason, they are
01022                                 if(isset($attrs['type'])){
01023                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
01024                                         $this->currentElement = $attrs['name'];
01025                                         $this->elements[ $attrs['name'] ] = $attrs;
01026                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01027                                         if (!isset($this->elements[ $attrs['name'] ]['form'])) {
01028                                                 $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
01029                                         }
01030                                         $ename = $attrs['name'];
01031                                 } elseif(isset($attrs['ref'])){
01032                                         $ename = $attrs['ref'];
01033                                 } else {
01034                                         $this->xdebug("processing untyped element ".$attrs['name']);
01035                                         $this->currentElement = $attrs['name'];
01036                                         $this->elements[ $attrs['name'] ] = $attrs;
01037                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01038                                         $this->elements[ $attrs['name'] ]['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
01039                                         if (!isset($this->elements[ $attrs['name'] ]['form'])) {
01040                                                 $this->elements[ $attrs['name'] ]['form'] = $this->schemaInfo['elementFormDefault'];
01041                                         }
01042                                 }
01043                                 if(isset($ename) && $this->currentComplexType){
01044                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
01045                                 }
01046                         break;
01047                         // we ignore enumeration values
01048                         //case 'enumeration':
01049                         //break;
01050                         case 'import':
01051                             if (isset($attrs['schemaLocation'])) {
01052                                         //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
01053                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
01054                                 } else {
01055                                         //$this->xdebug('import namespace ' . $attrs['namespace']);
01056                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
01057                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
01058                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
01059                                         }
01060                                 }
01061                         break;
01062                         case 'restriction':
01063                                 //$this->xdebug("in restriction for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
01064                                 if($this->currentElement){
01065                                         $this->elements[$this->currentElement]['type'] = $attrs['base'];
01066                                 } elseif($this->currentSimpleType){
01067                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
01068                                 } elseif($this->currentComplexType){
01069                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
01070                                         if(strstr($attrs['base'],':') == ':Array'){
01071                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01072                                         }
01073                                 }
01074                         break;
01075                         case 'schema':
01076                                 $this->schemaInfo = $attrs;
01077                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
01078                                 if (isset($attrs['targetNamespace'])) {
01079                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];
01080                                 }
01081                                 if (!isset($attrs['elementFormDefault'])) {
01082                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';
01083                                 }
01084                         break;
01085                         case 'simpleType':
01086                                 if(isset($attrs['name'])){
01087                                         $this->xdebug("processing simpleType for name " . $attrs['name']);
01088                                         $this->currentSimpleType = $attrs['name'];
01089                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;
01090                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
01091                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
01092                                 } else {
01093                                         //echo 'not parsing: '.$name;
01094                                         //var_dump($attrs);
01095                                 }
01096                         break;
01097                         default:
01098                                 //$this->xdebug("do not have anything to do for element $name");
01099                 }
01100         }
01101 
01109         function schemaEndElement($parser, $name) {
01110                 // bring depth down a notch
01111                 $this->depth--;
01112                 // position of current element is equal to the last value left in depth_array for my depth
01113                 if(isset($this->depth_array[$this->depth])){
01114                 $pos = $this->depth_array[$this->depth];
01115         }
01116                 // move on...
01117                 if($name == 'complexType'){
01118                         $this->currentComplexType = false;
01119                         $this->currentElement = false;
01120                 }
01121                 if($name == 'element'){
01122                         $this->currentElement = false;
01123                 }
01124                 if($name == 'simpleType'){
01125                         $this->currentSimpleType = false;
01126                 }
01127         }
01128 
01136         function schemaCharacterData($parser, $data){
01137                 $pos = $this->depth_array[$this->depth - 1];
01138                 $this->message[$pos]['cdata'] .= $data;
01139         }
01140 
01146         function serializeSchema(){
01147 
01148                 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
01149                 $xml = '';
01150                 // imports
01151                 if (sizeof($this->imports) > 0) {
01152                         foreach($this->imports as $ns => $list) {
01153                                 foreach ($list as $ii) {
01154                                         if ($ii['location'] != '') {
01155                                                 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
01156                                         } else {
01157                                                 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
01158                                         }
01159                                 }
01160                         } 
01161                 } 
01162                 // complex types
01163                 foreach($this->complexTypes as $typeName => $attrs){
01164                         $contentStr = '';
01165                         // serialize child elements
01166                         if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
01167                                 foreach($attrs['elements'] as $element => $eParts){
01168                                         if(isset($eParts['ref'])){
01169                                                 $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
01170                                         } else {
01171                                                 $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
01172                                         }
01173                                 }
01174                         }
01175                         // attributes
01176                         if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
01177                                 foreach($attrs['attrs'] as $attr => $aParts){
01178                                         $contentStr .= "    <$schemaPrefix:attribute ref=\"".$this->contractQName($aParts['ref']).'"';
01179                                         if(isset($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
01180                                                 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
01181                                                 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($aParts['http://schemas.xmlsoap.org/wsdl/:arrayType']).'"';
01182                                         }
01183                                         $contentStr .= "/>\n";
01184                                 }
01185                         }
01186                         // if restriction
01187                         if( isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
01188                                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
01189                         }
01190                         // compositor obviates complex/simple content
01191                         if(isset($attrs['compositor']) && ($attrs['compositor'] != '')){
01192                                 $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
01193                         }
01194                         // complex or simple content
01195                         elseif((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
01196                                 $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
01197                         }
01198                         // finalize complex type
01199                         if($contentStr != ''){
01200                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
01201                         } else {
01202                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
01203                         }
01204                         $xml .= $contentStr;
01205                 }
01206                 // simple types
01207                 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
01208                         foreach($this->simpleTypes as $typeName => $attr){
01209                                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <restriction base=\"".$this->contractQName($eParts['type'])."\"/>\n </$schemaPrefix:simpleType>";
01210                         }
01211                 }
01212                 // elements
01213                 if(isset($this->elements) && count($this->elements) > 0){
01214                         foreach($this->elements as $element => $eParts){
01215                                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
01216                         }
01217                 }
01218                 // attributes
01219                 if(isset($this->attributes) && count($this->attributes) > 0){
01220                         foreach($this->attributes as $attr => $aParts){
01221                                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
01222                         }
01223                 }
01224                 // finish 'er up
01225                 $el = "<$schemaPrefix:schema targetNamespace=\"$this->schemaTargetNamespace\"\n";
01226                 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
01227                         $el .= " xmlns:$nsp=\"$ns\"\n";
01228                 }
01229                 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
01230                 return $xml;
01231         }
01232 
01239         function xdebug($string){
01240                 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
01241         }
01242 
01254         function getPHPType($type,$ns){
01255                 if(isset($this->typemap[$ns][$type])){
01256                         //print "found type '$type' and ns $ns in typemap<br>";
01257                         return $this->typemap[$ns][$type];
01258                 } elseif(isset($this->complexTypes[$type])){
01259                         //print "getting type '$type' and ns $ns from complexTypes array<br>";
01260                         return $this->complexTypes[$type]['phpType'];
01261                 }
01262                 return false;
01263         }
01264 
01281         function getTypeDef($type){
01282                 //$this->debug("in getTypeDef for type $type");
01283                 if(isset($this->complexTypes[$type])){
01284                         $this->xdebug("in getTypeDef, found complexType $type");
01285                         return $this->complexTypes[$type];
01286                 } elseif(isset($this->simpleTypes[$type])){
01287                         $this->xdebug("in getTypeDef, found simpleType $type");
01288                         if (!isset($this->simpleTypes[$type]['phpType'])) {
01289                                 // get info for type to tack onto the simple type
01290                                 // TODO: can this ever really apply (i.e. what is a simpleType really?)
01291                                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
01292                                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
01293                                 $etype = $this->getTypeDef($uqType);
01294                                 if ($etype) {
01295                                         if (isset($etype['phpType'])) {
01296                                                 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
01297                                         }
01298                                         if (isset($etype['elements'])) {
01299                                                 $this->simpleTypes[$type]['elements'] = $etype['elements'];
01300                                         }
01301                                 }
01302                         }
01303                         return $this->simpleTypes[$type];
01304                 } elseif(isset($this->elements[$type])){
01305                         $this->xdebug("in getTypeDef, found element $type");
01306                         if (!isset($this->elements[$type]['phpType'])) {
01307                                 // get info for type to tack onto the element
01308                                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
01309                                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
01310                                 $etype = $this->getTypeDef($uqType);
01311                                 if ($etype) {
01312                                         if (isset($etype['phpType'])) {
01313                                                 $this->elements[$type]['phpType'] = $etype['phpType'];
01314                                         }
01315                                         if (isset($etype['elements'])) {
01316                                                 $this->elements[$type]['elements'] = $etype['elements'];
01317                                         }
01318                                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
01319                                         $this->elements[$type]['phpType'] = 'scalar';
01320                                 }
01321                         }
01322                         return $this->elements[$type];
01323                 } elseif(isset($this->attributes[$type])){
01324                         $this->xdebug("in getTypeDef, found attribute $type");
01325                         return $this->attributes[$type];
01326                 }
01327                 $this->xdebug("in getTypeDef, did not find $type");
01328                 return false;
01329         }
01330 
01338     function serializeTypeDef($type){
01339         //print "in sTD() for type $type<br>";
01340         if($typeDef = $this->getTypeDef($type)){
01341                 $str .= '<'.$type;
01342             if(is_array($typeDef['attrs'])){
01343                 foreach($attrs as $attName => $data){
01344                     $str .= " $attName=\"{type = ".$data['type']."}\"";
01345                 }
01346             }
01347             $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
01348             if(count($typeDef['elements']) > 0){
01349                 $str .= ">";
01350                 foreach($typeDef['elements'] as $element => $eData){
01351                     $str .= $this->serializeTypeDef($element);
01352                 }
01353                 $str .= "</$type>";
01354             } elseif($typeDef['typeClass'] == 'element') {
01355                 $str .= "></$type>";
01356             } else {
01357                 $str .= "/>";
01358             }
01359                         return $str;
01360         }
01361         return false;
01362     }
01363 
01373         function typeToForm($name,$type){
01374                 // get typedef
01375                 if($typeDef = $this->getTypeDef($type)){
01376                         // if struct
01377                         if($typeDef['phpType'] == 'struct'){
01378                                 $buffer .= '<table>';
01379                                 foreach($typeDef['elements'] as $child => $childDef){
01380                                         $buffer .= "
01381                                         <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
01382                                         <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
01383                                 }
01384                                 $buffer .= '</table>';
01385                         // if array
01386                         } elseif($typeDef['phpType'] == 'array'){
01387                                 $buffer .= '<table>';
01388                                 for($i=0;$i < 3; $i++){
01389                                         $buffer .= "
01390                                         <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
01391                                         <td><input type='text' name='parameters[".$name."][]'></td></tr>";
01392                                 }
01393                                 $buffer .= '</table>';
01394                         // if scalar
01395                         } else {
01396                                 $buffer .= "<input type='text' name='parameters[$name]'>";
01397                         }
01398                 } else {
01399                         $buffer .= "<input type='text' name='parameters[$name]'>";
01400                 }
01401                 return $buffer;
01402         }
01403         
01444         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
01445                 $this->complexTypes[$name] = array(
01446             'name'              => $name,
01447             'typeClass' => $typeClass,
01448             'phpType'   => $phpType,
01449                 'compositor'=> $compositor,
01450             'restrictionBase' => $restrictionBase,
01451                 'elements'      => $elements,
01452             'attrs'             => $attrs,
01453             'arrayType' => $arrayType
01454                 );
01455                 
01456                 $this->xdebug("addComplexType $name: " . $this->varDump($this->complexTypes[$name]));
01457         }
01458         
01469         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
01470                 $this->simpleTypes[$name] = array(
01471             'name'              => $name,
01472             'typeClass' => $typeClass,
01473             'phpType'   => $phpType,
01474             'type' => $restrictionBase
01475                 );
01476                 
01477                 $this->xdebug("addSimpleType $name: " . $this->varDump($this->simpleTypes[$name]));
01478         }
01479 }
01480 
01481 
01482 
01483 ?><?php
01484 
01485 
01486 
01495 class soapval extends nusoap_base {
01507         function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
01508                 $this->name = $name;
01509                 $this->value = $value;
01510                 $this->type = $type;
01511                 $this->element_ns = $element_ns;
01512                 $this->type_ns = $type_ns;
01513                 $this->attributes = $attributes;
01514     }
01515 
01522         function serialize($use='encoded') {
01523                 return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes,$use);
01524     }
01525 
01533         function decode(){
01534                 return $this->value;
01535         }
01536 }
01537 
01538 
01539 
01540 ?><?php
01541 
01542 
01543 
01552 class soap_transport_http extends nusoap_base {
01553 
01554         var $url = '';
01555         var $uri = '';
01556         var $scheme = '';
01557         var $host = '';
01558         var $port = '';
01559         var $path = '';
01560         var $request_method = 'POST';
01561         var $protocol_version = '1.0';
01562         var $encoding = '';
01563         var $outgoing_headers = array();
01564         var $incoming_headers = array();
01565         var $outgoing_payload = '';
01566         var $incoming_payload = '';
01567         var $useSOAPAction = true;
01568         var $persistentConnection = false;
01569         var $ch = false;        // cURL handle
01570         var $username;
01571         var $password;
01572         
01576         function soap_transport_http($url){
01577                 $this->url = $url;
01578                 
01579                 $u = parse_url($url);
01580                 foreach($u as $k => $v){
01581                         $this->debug("$k = $v");
01582                         $this->$k = $v;
01583                 }
01584                 
01585                 // add any GET params to path
01586                 if(isset($u['query']) && $u['query'] != ''){
01587             $this->path .= '?' . $u['query'];
01588                 }
01589                 
01590                 // set default port
01591                 if(!isset($u['port'])){
01592                         if($u['scheme'] == 'https'){
01593                                 $this->port = 443;
01594                         } else {
01595                                 $this->port = 80;
01596                         }
01597                 }
01598                 
01599                 $this->uri = $this->path;
01600                 
01601                 // build headers
01602                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
01603                 $this->outgoing_headers['User-Agent'] = $this->title.'/'.$this->version.' ('.$rev[1].')';
01604                 if (!isset($u['port'])) {
01605                         $this->outgoing_headers['Host'] = $this->host;
01606                 } else {
01607                         $this->outgoing_headers['Host'] = $this->host.':'.$this->port;
01608                 }
01609                 
01610                 if (isset($u['user']) && $u['user'] != '') {
01611                         $this->setCredentials($u['user'], isset($u['pass']) ? $u['pass'] : '');
01612                 }
01613         }
01614         
01615         function connect($connection_timeout=0,$response_timeout=30){
01616                 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
01617                 // "regular" socket.
01618                 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
01619                 //       loaded), and until PHP5 stream_get_wrappers is not available.
01620 //              if ($this->scheme == 'https') {
01621 //                      if (version_compare(phpversion(), '4.3.0') >= 0) {
01622 //                              if (extension_loaded('openssl')) {
01623 //                                      $this->scheme = 'ssl';
01624 //                                      $this->debug('Using SSL over OpenSSL');
01625 //                              }
01626 //                      }
01627 //              }
01628                 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
01629           if ($this->scheme == 'http' || $this->scheme == 'ssl') {
01630                 // use persistent connection
01631                 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
01632                         if (!feof($this->fp)) {
01633                                 $this->debug('Re-use persistent connection');
01634                                 return true;
01635                         }
01636                         fclose($this->fp);
01637                         $this->debug('Closed persistent connection at EOF');
01638                 }
01639 
01640                 // munge host if using OpenSSL
01641                 if ($this->scheme == 'ssl') {
01642                         $host = 'ssl://' . $this->host;
01643                 } else {
01644                         $host = $this->host;
01645                 }
01646                 $this->debug('calling fsockopen with host ' . $host);
01647 
01648                 // open socket
01649                 if($connection_timeout > 0){
01650                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
01651                 } else {
01652                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
01653                 }
01654                 
01655                 // test pointer
01656                 if(!$this->fp) {
01657                         $msg = 'Couldn\'t open socket connection to server ' . $this->url;
01658                         if ($this->errno) {
01659                                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
01660                         } else {
01661                                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';
01662                         }
01663                         $this->debug($msg);
01664                         $this->setError($msg);
01665                         return false;
01666                 }
01667                 
01668                 // set response timeout
01669                 socket_set_timeout( $this->fp, $response_timeout);
01670 
01671                 $this->debug('socket connected');
01672                 return true;
01673           } else if ($this->scheme == 'https') {
01674                 if (!extension_loaded('curl')) {
01675                         $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
01676                         return false;
01677                 }
01678                 $this->debug('connect using https');
01679                 // init CURL
01680                 $this->ch = curl_init();
01681                 // set url
01682                 $hostURL = ($this->port != '') ? "https://$this->host:$this->port" : "https://$this->host";
01683                 // add path
01684                 $hostURL .= $this->path;
01685                 curl_setopt($this->ch, CURLOPT_URL, $hostURL);
01686                 // ask for headers in the response output
01687                 curl_setopt($this->ch, CURLOPT_HEADER, 1);
01688                 // ask for the response output as the return value
01689                 curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
01690                 // encode
01691                 // We manage this ourselves through headers and encoding
01692 //              if(function_exists('gzuncompress')){
01693 //                      curl_setopt($this->ch, CURLOPT_ENCODING, 'deflate');
01694 //              }
01695                 // persistent connection
01696                 if ($this->persistentConnection) {
01697                         // The way we send data, we cannot use persistent connections, since
01698                         // there will be some "junk" at the end of our request.
01699                         //curl_setopt($this->ch, CURL_HTTP_VERSION_1_1, true);
01700                         $this->persistentConnection = false;
01701                         $this->outgoing_headers['Connection'] = 'close';
01702                 }
01703                 // set timeout (NOTE: cURL does not have separate connection and response timeouts)
01704                 if ($connection_timeout != 0) {
01705                         curl_setopt($this->ch, CURLOPT_TIMEOUT, $connection_timeout);
01706                 }
01707 
01708                 // recent versions of cURL turn on peer/host checking by default,
01709                 // while PHP binaries are not compiled with a default location for the
01710                 // CA cert bundle, so disable peer/host checking.
01711 //curl_setopt($this->ch, CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');           
01712                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0);
01713                 curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0);
01714 
01715                 /*
01716                         TODO: support client certificates (thanks Tobias Boes)
01717         curl_setopt($this->ch, CURLOPT_CAINFO, '$pathToPemFiles/rootca.pem');
01718         curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 1);
01719         curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 1);
01720         curl_setopt($this->ch, CURLOPT_SSLCERT, '$pathToPemFiles/mycert.pem');
01721         curl_setopt($this->ch, CURLOPT_SSLKEY, '$pathToPemFiles/mykey.pem');
01722                 */
01723                 $this->debug('cURL connection set up');
01724                 return true;
01725           } else {
01726                 $this->setError('Unknown scheme ' . $this->scheme);
01727                 $this->debug('Unknown scheme ' . $this->scheme);
01728                 return false;
01729           }
01730         }
01731         
01741         function send($data, $timeout=0, $response_timeout=30) {
01742                 
01743                 $this->debug('entered send() with data of length: '.strlen($data));
01744 
01745                 $this->tryagain = true;
01746                 $tries = 0;
01747                 while ($this->tryagain) {
01748                         $this->tryagain = false;
01749                         if ($tries++ < 2) {
01750                                 // make connnection
01751                                 if (!$this->connect($timeout, $response_timeout)){
01752                                         return false;
01753                                 }
01754                                 
01755                                 // send request
01756                                 if (!$this->sendRequest($data)){
01757                                         return false;
01758                                 }
01759                                 
01760                                 // get response
01761                                 $respdata = $this->getResponse();
01762                         } else {
01763                                 $this->setError('Too many tries to get an OK response');
01764                         }
01765                 }               
01766                 $this->debug('end of send()');
01767                 return $respdata;
01768         }
01769 
01770 
01780         function sendHTTPS($data, $timeout=0, $response_timeout=30) {
01781                 return $this->send($data, $timeout, $response_timeout);
01782         }
01783         
01793         function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array()) {
01794                 global $_SERVER;
01795 
01796                 $this->debug("Set credentials for authtype $authtype");
01797                 // cf. RFC 2617
01798                 if ($authtype == 'basic') {
01799                         $this->outgoing_headers['Authorization'] = 'Basic '.base64_encode($username.':'.$password);
01800                 } elseif ($authtype == 'digest') {
01801                         if (isset($digestRequest['nonce'])) {
01802                                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
01803                                 
01804                                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
01805         
01806                                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
01807                                 $A1 = $username. ':' . $digestRequest['realm'] . ':' . $password;
01808         
01809                                 // H(A1) = MD5(A1)
01810                                 $HA1 = md5($A1);
01811         
01812                                 // A2 = Method ":" digest-uri-value
01813                                 $A2 = 'POST:' . $this->uri;
01814         
01815                                 // H(A2)
01816                                 $HA2 =  md5($A2);
01817         
01818                                 // KD(secret, data) = H(concat(secret, ":", data))
01819                                 // if qop == auth:
01820                                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
01821                                 //                              ":" nc-value
01822                                 //                              ":" unq(cnonce-value)
01823                                 //                              ":" unq(qop-value)
01824                                 //                              ":" H(A2)
01825                                 //                            ) <">
01826                                 // if qop is missing,
01827                                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
01828         
01829                                 $unhashedDigest = '';
01830                                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
01831                                 $cnonce = $nonce;
01832                                 if ($digestRequest['qop'] != '') {
01833                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
01834                                 } else {
01835                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
01836                                 }
01837         
01838                                 $hashedDigest = md5($unhashedDigest);
01839         
01840                                 $this->outgoing_headers['Authorization'] = 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->uri . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"';
01841                         }
01842                 }
01843                 $this->username = $username;
01844                 $this->password = $password;
01845                 $this->authtype = $authtype;
01846                 $this->digestRequest = $digestRequest;
01847                 
01848                 if (isset($this->outgoing_headers['Authorization'])) {
01849                         $this->debug('Authorization header set: ' . substr($this->outgoing_headers['Authorization'], 0, 12) . '...');
01850                 } else {
01851                         $this->debug('Authorization header not set');
01852                 }
01853         }
01854         
01861         function setSOAPAction($soapaction) {
01862                 $this->outgoing_headers['SOAPAction'] = '"' . $soapaction . '"';
01863         }
01864         
01871         function setEncoding($enc='gzip, deflate'){
01872                 $this->protocol_version = '1.1';
01873                 $this->outgoing_headers['Accept-Encoding'] = $enc;
01874                 $this->outgoing_headers['Connection'] = 'close';
01875                 $this->persistentConnection = false;
01876                 set_magic_quotes_runtime(0);
01877                 // deprecated
01878                 $this->encoding = $enc;
01879         }
01880         
01890         function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
01891                 $this->uri = $this->url;
01892                 $this->host = $proxyhost;
01893                 $this->port = $proxyport;
01894                 if ($proxyusername != '' && $proxypassword != '') {
01895                         $this->outgoing_headers['Proxy-Authorization'] = ' Basic '.base64_encode($proxyusername.':'.$proxypassword);
01896                 }
01897         }
01898         
01908         function decodeChunked($buffer, $lb){
01909                 // length := 0
01910                 $length = 0;
01911                 $new = '';
01912                 
01913                 // read chunk-size, chunk-extension (if any) and CRLF
01914                 // get the position of the linebreak
01915                 $chunkend = strpos($buffer, $lb);
01916                 if ($chunkend == FALSE) {
01917                         $this->debug('no linebreak found in decodeChunked');
01918                         return $new;
01919                 }
01920                 $temp = substr($buffer,0,$chunkend);
01921                 $chunk_size = hexdec( trim($temp) );
01922                 $chunkstart = $chunkend + strlen($lb);
01923                 // while (chunk-size > 0) {
01924                 while ($chunk_size > 0) {
01925                         $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
01926                         $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
01927                         
01928                         // Just in case we got a broken connection
01929                         if ($chunkend == FALSE) {
01930                             $chunk = substr($buffer,$chunkstart);
01931                                 // append chunk-data to entity-body
01932                         $new .= $chunk;
01933                             $length += strlen($chunk);
01934                             break;
01935                         }
01936                         
01937                         // read chunk-data and CRLF
01938                         $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
01939                         // append chunk-data to entity-body
01940                         $new .= $chunk;
01941                         // length := length + chunk-size
01942                         $length += strlen($chunk);
01943                         // read chunk-size and CRLF
01944                         $chunkstart = $chunkend + strlen($lb);
01945                         
01946                         $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
01947                         if ($chunkend == FALSE) {
01948                                 break; //Just in case we got a broken connection
01949                         }
01950                         $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
01951                         $chunk_size = hexdec( trim($temp) );
01952                         $chunkstart = $chunkend;
01953                 }
01954                 return $new;
01955         }
01956         
01957         /*
01958          *      Writes payload, including HTTP headers, to $this->outgoing_payload.
01959          */
01960         function buildPayload($data) {
01961                 // add content-length header
01962                 $this->outgoing_headers['Content-Length'] = strlen($data);
01963                 
01964                 // start building outgoing payload:
01965                 $this->outgoing_payload = "$this->request_method $this->uri HTTP/$this->protocol_version\r\n";
01966 
01967                 // loop thru headers, serializing
01968                 foreach($this->outgoing_headers as $k => $v){
01969                         $this->outgoing_payload .= $k.': '.$v."\r\n";
01970                 }
01971                 
01972                 // header/body separator
01973                 $this->outgoing_payload .= "\r\n";
01974                 
01975                 // add data
01976                 $this->outgoing_payload .= $data;
01977         }
01978 
01979         function sendRequest($data){
01980                 // build payload
01981                 $this->buildPayload($data);
01982 
01983           if ($this->scheme == 'http' || $this->scheme == 'ssl') {
01984                 // send payload
01985                 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
01986                         $this->setError('couldn\'t write message data to socket');
01987                         $this->debug('couldn\'t write message data to socket');
01988                         return false;
01989                 }
01990                 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
01991                 return true;
01992           } else if ($this->scheme == 'https') {
01993                 // set payload
01994                 // TODO: cURL does say this should only be the verb, and in fact it
01995                 // turns out that the URI and HTTP version are appended to this, which
01996                 // some servers refuse to work with
01997                 //curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
01998                 foreach($this->outgoing_headers as $k => $v){
01999                         $curl_headers[] = "$k: $v";
02000                 }
02001                 curl_setopt($this->ch, CURLOPT_HTTPHEADER, $curl_headers);
02002                 if ($this->request_method == "POST") {
02003                         curl_setopt($this->ch, CURLOPT_POST, 1);
02004                         curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data);
02005                 } else {
02006                 }
02007                 $this->debug('set cURL payload');
02008                 return true;
02009           }
02010         }
02011 
02012         function getResponse(){
02013                 $this->incoming_payload = '';
02014             
02015           if ($this->scheme == 'http' || $this->scheme == 'ssl') {
02016             // loop until headers have been retrieved
02017             $data = '';
02018             while (!isset($lb)){
02019 
02020                         // We might EOF during header read.
02021                         if(feof($this->fp)) {
02022                                 $this->incoming_payload = $data;
02023                                 $this->debug('found no headers before EOF after length ' . strlen($data));
02024                                 $this->debug("received before EOF:\n" . $data);
02025                                 $this->setError('server failed to send headers');
02026                                 return false;
02027                         }
02028 
02029                         $tmp = fgets($this->fp, 256);
02030                         $tmplen = strlen($tmp);
02031                         $this->debug("read line of $tmplen bytes: " . trim($tmp));
02032 
02033                         if ($tmplen == 0) {
02034                                 $this->incoming_payload = $data;
02035                                 $this->debug('socket read of headers timed out after length ' . strlen($data));
02036                                 $this->debug("read before timeout:\n" . $data);
02037                                 $this->setError('socket read of headers timed out');
02038                                 return false;
02039                         }
02040 
02041                         $data .= $tmp;
02042                         $pos = strpos($data,"\r\n\r\n");
02043                         if($pos > 1){
02044                                 $lb = "\r\n";
02045                         } else {
02046                                 $pos = strpos($data,"\n\n");
02047                                 if($pos > 1){
02048                                         $lb = "\n";
02049                                 }
02050                         }
02051                         // remove 100 header
02052                         if(isset($lb) && ereg('^HTTP/1.1 100',$data)){
02053                                 unset($lb);
02054                                 $data = '';
02055                         }//
02056                 }
02057                 // store header data
02058                 $this->incoming_payload .= $data;
02059                 $this->debug('found end of headers after length ' . strlen($data));
02060                 // process headers
02061                 $header_data = trim(substr($data,0,$pos));
02062                 $header_array = explode($lb,$header_data);
02063                 $this->incoming_headers = array();
02064                 foreach($header_array as $header_line){
02065                         $arr = explode(':',$header_line, 2);
02066                         if(count($arr) > 1){
02067                                 $header_name = strtolower(trim($arr[0]));
02068                                 $this->incoming_headers[$header_name] = trim($arr[1]);
02069                         } else if (isset($header_name)) {
02070                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
02071                         }
02072                 }
02073                 
02074                 // loop until msg has been received
02075                 if (isset($this->incoming_headers['content-length'])) {
02076                         $content_length = $this->incoming_headers['content-length'];
02077                         $chunked = false;
02078                         $this->debug("want to read content of length $content_length");
02079                 } else {
02080                         $content_length =  2147483647;
02081                         if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
02082                                 $chunked = true;
02083                                 $this->debug("want to read chunked content");
02084                         } else {
02085                                 $chunked = false;
02086                                 $this->debug("want to read content to EOF");
02087                         }
02088                 }
02089                 $data = '';
02090                 do {
02091                         if ($chunked) {
02092                                 $tmp = fgets($this->fp, 256);
02093                                 $tmplen = strlen($tmp);
02094                                 $this->debug("read chunk line of $tmplen bytes");
02095                                 if ($tmplen == 0) {
02096                                         $this->incoming_payload = $data;
02097                                         $this->debug('socket read of chunk length timed out after length ' . strlen($data));
02098                                         $this->debug("read before timeout:\n" . $data);
02099                                         $this->setError('socket read of chunk length timed out');
02100                                         return false;
02101                                 }
02102                                 $content_length = hexdec(trim($tmp));
02103                                 $this->debug("chunk length $content_length");
02104                         }
02105                         $strlen = 0;
02106                     while (($strlen < $content_length) && (!feof($this->fp))) {
02107                         $readlen = min(8192, $content_length - $strlen);
02108                                 $tmp = fread($this->fp, $readlen);
02109                                 $tmplen = strlen($tmp);
02110                                 $this->debug("read buffer of $tmplen bytes");
02111                                 if (($tmplen == 0) && (!feof($this->fp))) {
02112                                         $this->incoming_payload = $data;
02113                                         $this->debug('socket read of body timed out after length ' . strlen($data));
02114                                         $this->debug("read before timeout:\n" . $data);
02115                                         $this->setError('socket read of body timed out');
02116                                         return false;
02117                                 }
02118                                 $strlen += $tmplen;
02119                                 $data .= $tmp;
02120                         }
02121                         if ($chunked && ($content_length > 0)) {
02122                                 $tmp = fgets($this->fp, 256);
02123                                 $tmplen = strlen($tmp);
02124                                 $this->debug("read chunk terminator of $tmplen bytes");
02125                                 if ($tmplen == 0) {
02126                                         $this->incoming_payload = $data;
02127                                         $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
02128                                         $this->debug("read before timeout:\n" . $data);
02129                                         $this->setError('socket read of chunk terminator timed out');
02130                                         return false;
02131                                 }
02132                         }
02133                 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
02134                 if (feof($this->fp)) {
02135                         $this->debug('read to EOF');
02136                 }
02137                 $this->debug('read body of length ' . strlen($data));
02138                 $this->incoming_payload .= $data;
02139                 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
02140                 
02141                 // close filepointer
02142                 if(
02143                         (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 
02144                         (! $this->persistentConnection) || feof($this->fp)){
02145                         fclose($this->fp);
02146                         $this->fp = false;
02147                         $this->debug('closed socket');
02148                 }
02149                 
02150                 // connection was closed unexpectedly
02151                 if($this->incoming_payload == ''){
02152                         $this->setError('no response from server');
02153                         return false;
02154                 }
02155                 
02156                 // decode transfer-encoding
02157 //              if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
02158 //                      if(!$data = $this->decodeChunked($data, $lb)){
02159 //                              $this->setError('Decoding of chunked data failed');
02160 //                              return false;
02161 //                      }
02162                         //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
02163                         // set decoded payload
02164 //                      $this->incoming_payload = $header_data.$lb.$lb.$data;
02165 //              }
02166         
02167           } else if ($this->scheme == 'https') {
02168                 // send and receive
02169                 $this->debug('send and receive with cURL');
02170                 $this->incoming_payload = curl_exec($this->ch);
02171                 $data = $this->incoming_payload;
02172 
02173         $cErr = curl_error($this->ch);
02174                 if ($cErr != '') {
02175                 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
02176                         foreach(curl_getinfo($this->ch) as $k => $v){
02177                                 $err .= "$k: $v<br>";
02178                         }
02179                         $this->debug($err);
02180                         $this->setError($err);
02181                         curl_close($this->ch);
02182                 return false;
02183                 } else {
02184                         //echo '<pre>';
02185                         //var_dump(curl_getinfo($this->ch));
02186                         //echo '</pre>';
02187                 }
02188                 // close curl
02189                 $this->debug('No cURL error, closing cURL');
02190                 curl_close($this->ch);
02191                 
02192                 // remove 100 header
02193                 if (ereg('^HTTP/1.1 100',$data)) {
02194                         if ($pos = strpos($data,"\r\n\r\n")) {
02195                                 $data = ltrim(substr($data,$pos));
02196                         } elseif($pos = strpos($data,"\n\n") ) {
02197                                 $data = ltrim(substr($data,$pos));
02198                         }
02199                 }
02200                 
02201                 // separate content from HTTP headers
02202                 if ($pos = strpos($data,"\r\n\r\n")) {
02203                         $lb = "\r\n";
02204                 } elseif( $pos = strpos($data,"\n\n")) {
02205                         $lb = "\n";
02206                 } else {
02207                         $this->debug('no proper separation of headers and document');
02208                         $this->setError('no proper separation of headers and document');
02209                         return false;
02210                 }
02211                 $header_data = trim(substr($data,0,$pos));
02212                 $header_array = explode($lb,$header_data);
02213                 $data = ltrim(substr($data,$pos));
02214                 $this->debug('found proper separation of headers and document');
02215                 $this->debug('cleaned data, stringlen: '.strlen($data));
02216                 // clean headers
02217                 foreach ($header_array as $header_line) {
02218                         $arr = explode(':',$header_line,2);
02219                         if (count($arr) > 1) {
02220                                 $this->incoming_headers[strtolower(trim($arr[0]))] = trim($arr[1]);
02221                         }
02222                 }
02223           }
02224 
02225                 // see if we need to resend the request with http digest authentication
02226                 if (isset($this->incoming_headers['www-authenticate']) && strstr($header_array[0], '401 Unauthorized')) {
02227                         $this->debug('Got 401 Unauthorized with WWW-Authenticate: ' . $this->incoming_headers['www-authenticate']);
02228                         if (substr("Digest ", $this->incoming_headers['www-authenticate'])) {
02229                                 $this->debug('Server wants digest authentication');
02230                                 // remove "Digest " from our elements
02231                                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
02232                                 
02233                                 // parse elements into array
02234                                 $digestElements = explode(',', $digestString);
02235                                 foreach ($digestElements as $val) {
02236                                         $tempElement = explode('=', trim($val));
02237                                         $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
02238                                 }
02239 
02240                                 // should have (at least) qop, realm, nonce
02241                                 if (isset($digestRequest['nonce'])) {
02242                                         $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
02243                                         $this->tryagain = true;
02244                                         return false;
02245                                 }
02246                         }
02247                         $this->debug('HTTP authentication failed');
02248                         $this->setError('HTTP authentication failed');
02249                         return false;
02250                 }
02251                 
02252                 // decode content-encoding
02253                 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
02254                         if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
02255                         // if decoding works, use it. else assume data wasn't gzencoded
02256                         if(function_exists('gzuncompress')){
02257                                         //$timer->setMarker('starting decoding of gzip/deflated content');
02258                                         if($this->incoming_headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)){
02259                                         $data = $degzdata;
02260                                         } elseif($this->incoming_headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))){    // do our best
02261                                                 $data = $degzdata;
02262                                         } else {
02263                                                 $this->setError('Errors occurred when trying to decode the data');
02264                                         }
02265                                         //$timer->setMarker('finished decoding of gzip/deflated content');
02266                                         //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
02267                                         // set decoded payload
02268                                         $this->incoming_payload = $header_data.$lb.$lb.$data;
02269                         } else {
02270                                         $this->setError('The server sent deflated data. Your php install must have the Zlib extension compiled in to support this.');
02271                                 }
02272                         }
02273                 }
02274                 
02275                 if(strlen($data) == 0){
02276                         $this->debug('no data after headers!');
02277                         $this->setError('no data present after HTTP headers');
02278                         return false;
02279                 }
02280                 
02281                 return $data;
02282         }
02283 
02284         function setContentType($type, $charset = false) {
02285                 $this->outgoing_headers['Content-Type'] = $type . ($charset ? '; charset=' . $charset : '');
02286         }
02287 
02288         function usePersistentConnection(){
02289                 if (isset($this->outgoing_headers['Accept-Encoding'])) {
02290                         return false;
02291                 }
02292                 $this->protocol_version = '1.1';
02293                 $this->persistentConnection = true;
02294                 $this->outgoing_headers['Connection'] = 'Keep-Alive';
02295                 return true;
02296         }
02297 }
02298 
02299 ?><?php
02300 
02301 
02302 
02314 class soap_server extends nusoap_base {
02315         var $headers = array();                 // HTTP headers of request
02316         var $request = '';                              // HTTP request
02317         var $requestHeaders = '';               // SOAP headers from request (incomplete namespace resolution) (text)
02318         var $document = '';                             // SOAP body request portion (incomplete namespace resolution) (text)
02319         var $requestSOAP = '';                  // SOAP payload for request (text)
02320         var $methodURI = '';                    // requested method namespace URI
02321         var $methodname = '';                   // name of method requested
02322         var $methodparams = array();    // method parameters from request
02323         var $xml_encoding = '';                 // character set encoding of incoming (request) messages
02324         var $SOAPAction = '';                   // SOAP Action from request
02325 
02326         var $outgoing_headers = array();// HTTP headers of response
02327         var $response = '';                             // HTTP response
02328         var $responseHeaders = '';              // SOAP headers for response (text)
02329         var $responseSOAP = '';                 // SOAP payload for response (text)
02330         var $methodreturn = false;              // method return to place in response
02331         var $methodreturnisliteralxml = false;  // whether $methodreturn is a string of literal XML
02332         var $fault = false;                             // SOAP fault for response
02333         var $result = 'successful';             // text indication of result (for debugging)
02334 
02335         var $operations = array();              // assoc array of operations => opData
02336         var $wsdl = false;                              // wsdl instance
02337         var $externalWSDLURL = false;   // URL for WSDL
02338         var $debug_flag = false;                // whether to append debug to response as XML comment
02339         
02347         function soap_server($wsdl=false){
02348 
02349                 // turn on debugging?
02350                 global $debug;
02351                 global $_REQUEST;
02352                 global $_SERVER;
02353                 global $HTTP_SERVER_VARS;
02354 
02355                 if (isset($debug)) {
02356                         $this->debug_flag = $debug;
02357                 } else if (isset($_REQUEST['debug'])) {
02358                         $this->debug_flag = $_REQUEST['debug'];
02359                 } else if (isset($_SERVER['QUERY_STRING'])) {
02360                         $qs = explode('&', $_SERVER['QUERY_STRING']);
02361                         foreach ($qs as $v) {
02362                                 if (substr($v, 0, 6) == 'debug=') {
02363                                         $this->debug_flag = substr($v, 6);
02364                                 }
02365                         }
02366                 } else if (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
02367                         $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
02368                         foreach ($qs as $v) {
02369                                 if (substr($v, 0, 6) == 'debug=') {
02370                                         $this->debug_flag = substr($v, 6);
02371                                 }
02372                         }
02373                 }
02374 
02375                 // wsdl
02376                 if($wsdl){
02377                         if (is_object($wsdl) && is_a($wsdl, 'wsdl')) {
02378                                 $this->wsdl = $wsdl;
02379                                 $this->externalWSDLURL = $this->wsdl->wsdl;
02380                                 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
02381                         } else {
02382                                 $this->debug('Create wsdl from ' . $wsdl);
02383                                 $this->wsdl = new wsdl($wsdl);
02384                                 $this->externalWSDLURL = $wsdl;
02385                         }
02386                         $this->debug("wsdl...\n" . $this->wsdl->debug_str);
02387                         $this->wsdl->debug_str = '';
02388                         if($err = $this->wsdl->getError()){
02389                                 die('WSDL ERROR: '.$err);
02390                         }
02391                 }
02392         }
02393 
02400         function service($data){
02401                 global $QUERY_STRING;
02402                 if(isset($_SERVER['QUERY_STRING'])){
02403                         $qs = $_SERVER['QUERY_STRING'];
02404                 } elseif(isset($GLOBALS['QUERY_STRING'])){
02405                         $qs = $GLOBALS['QUERY_STRING'];
02406                 } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
02407                         $qs = $QUERY_STRING;
02408                 }
02409 
02410                 if(isset($qs) && ereg('wsdl', $qs) ){
02411                         // This is a request for WSDL
02412                         if($this->externalWSDLURL){
02413               if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
02414                                 header('Location: '.$this->externalWSDLURL);
02415               } else { // assume file
02416                 header("Content-Type: text/xml\r\n");
02417                 $fp = fopen($this->externalWSDLURL, 'r');
02418                 fpassthru($fp);
02419               }
02420                         } else {
02421                                 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
02422                                 print $this->wsdl->serialize();
02423                         }
02424                 } elseif($data == '' && $this->wsdl){
02425                         // print web interface
02426                         print $this->webDescription();
02427                 } else {
02428                         // handle the request
02429                         $this->parse_request($data);
02430                         if (! $this->fault) {
02431                                 $this->invoke_method();
02432                         }
02433                         if (! $this->fault) {
02434                                 $this->serialize_return();
02435                         }
02436                         $this->send_response();
02437                 }
02438         }
02439 
02452         function parse_http_headers() {
02453                 global $HTTP_SERVER_VARS;
02454                 global $_SERVER;
02455 
02456                 $this->request = '';
02457                 if(function_exists('getallheaders')){
02458                         $this->headers = getallheaders();
02459                         foreach($this->headers as $k=>$v){
02460                                 $this->request .= "$k: $v\r\n";
02461                                 $this->debug("$k: $v");
02462                         }
02463                         // get SOAPAction header
02464                         if(isset($this->headers['SOAPAction'])){
02465                                 $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']);
02466                         }
02467                         // get the character encoding of the incoming request
02468                         if(strpos($this->headers['Content-Type'],'=')){
02469                                 $enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1));
02470                                 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
02471                                         $this->xml_encoding = strtoupper($enc);
02472                                 } else {
02473                                         $this->xml_encoding = 'US-ASCII';
02474                                 }
02475                         } else {
02476                                 // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
02477                                 $this->xml_encoding = 'UTF-8';
02478                         }
02479                 } elseif(isset($_SERVER) && is_array($_SERVER)){
02480                         foreach ($_SERVER as $k => $v) {
02481                                 if (substr($k, 0, 5) == 'HTTP_') {
02482                                         $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
02483                                 } else {
02484                                         $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
02485                                 }
02486                                 if ($k == 'Soapaction') {
02487                                         // get SOAPAction header
02488                                         $k = 'SOAPAction';
02489                                         $v = str_replace('"', '', $v);
02490                                         $v = str_replace('\\', '', $v);
02491                                         $this->SOAPAction = $v;
02492                                 } else if ($k == 'Content-Type') {
02493                                         // get the character encoding of the incoming request
02494                                         if (strpos($v, '=')) {
02495                                                 $enc = substr(strstr($v, '='), 1);
02496                                                 $enc = str_replace('"', '', $enc);
02497                                                 $enc = str_replace('\\', '', $enc);
02498                                                 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
02499                                                         $this->xml_encoding = strtoupper($enc);
02500                                                 } else {
02501                                                         $this->xml_encoding = 'US-ASCII';
02502                                                 }
02503                                         } else {
02504                                                 // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
02505                                                 $this->xml_encoding = 'UTF-8';
02506                                         }
02507                                 }
02508                                 $this->headers[$k] = $v;
02509                                 $this->request .= "$k: $v\r\n";
02510                                 $this->debug("$k: $v");
02511                         }
02512                 } elseif (is_array($HTTP_SERVER_VARS)) {
02513                         foreach ($HTTP_SERVER_VARS as $k => $v) {
02514                                 if (substr($k, 0, 5) == 'HTTP_') {
02515                                         $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
02516                                         if ($k == 'Soapaction') {
02517                                                 // get SOAPAction header
02518                                                 $k = 'SOAPAction';
02519                                                 $v = str_replace('"', '', $v);
02520                                                 $v = str_replace('\\', '', $v);
02521                                                 $this->SOAPAction = $v;
02522                                         } else if ($k == 'Content-Type') {
02523                                                 // get the character encoding of the incoming request
02524                                                 if (strpos($v, '=')) {
02525                                                         $enc = substr(strstr($v, '='), 1);
02526                                                         $enc = str_replace('"', '', $enc);
02527                                                         $enc = str_replace('\\', '', $enc);
02528                                                         if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
02529                                                                 $this->xml_encoding = strtoupper($enc);
02530                                                         } else {
02531                                                                 $this->xml_encoding = 'US-ASCII';
02532                                                         }
02533                                                 } else {
02534                                                         // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
02535                                                         $this->xml_encoding = 'UTF-8';
02536                                                 }
02537                                         }
02538                                         $this->headers[$k] = $v;
02539                                         $this->request .= "$k: $v\r\n";
02540                                         $this->debug("$k: $v");
02541                                 }
02542                         }
02543                 }
02544         }
02545 
02568         function parse_request($data='') {
02569                 $this->debug('entering parse_request() on '.date('H:i Y-m-d'));
02570                 $this->parse_http_headers();
02571                 $this->debug('got character encoding: '.$this->xml_encoding);
02572                 // uncompress if necessary
02573                 if (isset($this->headers['Content-Encoding']) && $this->headers['Content-Encoding'] != '') {
02574                         $this->debug('got content encoding: ' . $this->headers['Content-Encoding']);
02575                         if ($this->headers['Content-Encoding'] == 'deflate' || $this->headers['Content-Encoding'] == 'gzip') {
02576                         // if decoding works, use it. else assume data wasn't gzencoded
02577                                 if (function_exists('gzuncompress')) {
02578                                         if ($this->headers['Content-Encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
02579                                                 $data = $degzdata;
02580                                         } elseif ($this->headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
02581                                                 $data = $degzdata;
02582                                         } else {
02583                                                 $this->fault('Server', 'Errors occurred when trying to decode the data');
02584                                                 return;
02585                                         }
02586                                 } else {
02587                                         $this->fault('Server', 'This Server does not support compressed data');
02588                                         return;
02589                                 }
02590                         }
02591                 }
02592                 $this->request .= "\r\n".$data;
02593                 $this->requestSOAP = $data;
02594                 // parse response, get soap parser obj
02595                 $parser = new soap_parser($data,$this->xml_encoding);
02596                 // parser debug
02597                 $this->debug("parser debug: \n".$parser->debug_str);
02598                 // if fault occurred during message parsing
02599                 if($err = $parser->getError()){
02600                         $this->result = 'fault: error in msg parsing: '.$err;
02601                         $this->fault('Server',"error in msg parsing:\n".$err);
02602                 // else successfully parsed request into soapval object
02603                 } else {
02604                         // get/set methodname
02605                         $this->methodURI = $parser->root_struct_namespace;
02606                         $this->methodname = $parser->root_struct_name;
02607                         $this->debug('method name: '.$this->methodname);
02608                         $this->debug('calling parser->get_response()');
02609                         $this->methodparams = $parser->get_response();
02610                         // get SOAP headers
02611                         $this->requestHeaders = $parser->getHeaders();
02612             // add document for doclit support
02613             $this->document = $parser->document;
02614                 }
02615                 $this->debug('leaving parse_request() on '.date('H:i Y-m-d'));
02616         }
02617 
02635         function invoke_method() {
02636                 $this->debug('entering invoke_method');
02637                 // does method exist?
02638                 if(!function_exists($this->methodname)){
02639                         // "method not found" fault here
02640                         $this->debug("method '$this->methodname' not found!");
02641                         $this->result = 'fault: method not found';
02642                         $this->fault('Server',"method '$this->methodname' not defined in service");
02643                         return;
02644                 }
02645                 if($this->wsdl){
02646                         if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){
02647                         //if(
02648                         $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service");
02649                                 return;
02650                     }
02651                     $this->debug('opData is ' . $this->varDump($this->opData));
02652                 }
02653                 $this->debug("method '$this->methodname' exists");
02654                 // evaluate message, getting back parameters
02655                 // verify that request parameters match the method's signature
02656                 if(! $this->verify_method($this->methodname,$this->methodparams)){
02657                         // debug
02658                         $this->debug('ERROR: request not verified against method signature');
02659                         $this->result = 'fault: request failed validation against method signature';
02660                         // return fault
02661                         $this->fault('Server',"Operation '$this->methodname' not defined in service.");
02662                         return;
02663                 }
02664 
02665                 // if there are parameters to pass
02666         $this->debug('params var dump '.$this->varDump($this->methodparams));
02667                 if($this->methodparams){
02668                         $this->debug("calling '$this->methodname' with params");
02669                         if (! function_exists('call_user_func_array')) {
02670                                 $this->debug('calling method using eval()');
02671                                 $funcCall = $this->methodname.'(';
02672                                 foreach($this->methodparams as $param) {
02673                                         $funcCall .= "\"$param\",";
02674                                 }
02675                                 $funcCall = substr($funcCall, 0, -1).')';
02676                                 $this->debug('function call:<br>'.$funcCall);
02677                                 @eval("\$this->methodreturn = $funcCall;");
02678                         } else {
02679                                 $this->debug('calling method using call_user_func_array()');
02680                                 $this->methodreturn = call_user_func_array("$this->methodname",$this->methodparams);
02681                         }
02682                 } else {
02683                         // call method w/ no parameters
02684                         $this->debug("calling $this->methodname w/ no params");
02685                         $m = $this->methodname;
02686                         $this->methodreturn = @$m();
02687                 }
02688         $this->debug('methodreturn var dump'.$this->varDump($this->methodreturn));
02689                 $this->debug("leaving invoke_method: called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
02690         }
02691 
02703         function serialize_return() {
02704                 $this->debug("Entering serialize_return");
02705                 // if we got nothing back. this might be ok (echoVoid)
02706                 if(isset($this->methodreturn) && ($this->methodreturn != '' || is_bool($this->methodreturn))) {
02707                         // if fault
02708                         if(get_class($this->methodreturn) == 'soap_fault'){
02709                                 $this->debug('got a fault object from method');
02710                                 $this->fault = $this->methodreturn;
02711                                 return;
02712                         } elseif ($this->methodreturnisliteralxml) {
02713                                 $return_val = $this->methodreturn;
02714                         // returned value(s)
02715                         } else {
02716                                 $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
02717                                 $this->debug('serializing return value');
02718                                 if($this->wsdl){
02719                                         // weak attempt at supporting multiple output params
02720                                         if(sizeof($this->opData['output']['parts']) > 1){
02721                                         $opParams = $this->methodreturn;
02722                                     } else {
02723                                         // TODO: is this really necessary?
02724                                         $opParams = array($this->methodreturn);
02725                                     }
02726                                     $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
02727                                         if($errstr = $this->wsdl->getError()){
02728                                                 $this->debug('got wsdl error: '.$errstr);
02729                                                 $this->fault('Server', 'got wsdl error: '.$errstr);
02730                                                 return;
02731                                         }
02732                                 } else {
02733                                     $return_val = $this->serialize_val($this->methodreturn, 'return');
02734                                 }
02735                         }
02736                         $this->debug('return val: '.$this->varDump($return_val));
02737                 } else {
02738                         $return_val = '';
02739                         $this->debug('got no response from method');
02740                 }
02741                 $this->debug('serializing response');
02742                 if ($this->wsdl) {
02743                         if ($this->opData['style'] == 'rpc') {
02744                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
02745                         } else {
02746                                 $payload = $return_val;
02747                         }
02748                 } else {
02749                         $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
02750                 }
02751                 $this->result = 'successful';
02752                 if($this->wsdl){
02753                         //if($this->debug_flag){
02754                 $this->debug("WSDL debug data:\n".$this->wsdl->debug_str);
02755             //  }
02756                         // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
02757                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style']);
02758                 } else {
02759                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
02760                 }
02761                 $this->debug("Leaving serialize_return");
02762         }
02763 
02774         function send_response() {
02775                 $this->debug('Enter send_response');
02776                 if ($this->fault) {
02777                         $payload = $this->fault->serialize();
02778                         $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
02779                         $this->outgoing_headers[] = "Status: 500 Internal Server Error";
02780                 } else {
02781                         $payload = $this->responseSOAP;
02782                         // Some combinations of PHP+Web server allow the Status
02783                         // to come through as a header.  Since OK is the default
02784                         // just do nothing.
02785                         // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
02786                         // $this->outgoing_headers[] = "Status: 200 OK";
02787                 }
02788         // add debug data if in debug mode
02789                 if(isset($this->debug_flag) && $this->debug_flag){
02790                         while (strpos($this->debug_str, '--')) {
02791                                 $this->debug_str = str_replace('--', '- -', $this->debug_str);
02792                         }
02793                 $payload .= "<!--\n" . $this->debug_str . "\n-->";
02794         }
02795                 $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
02796                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
02797                 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
02798                 // Let the Web server decide about this
02799                 //$this->outgoing_headers[] = "Connection: Close\r\n";
02800                 $this->outgoing_headers[] = "Content-Type: text/xml; charset=$this->soap_defencoding";
02801                 //begin code to compress payload - by John
02802                 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['Accept-Encoding'])) {     
02803                    if (strstr($this->headers['Accept-Encoding'], 'deflate')) {
02804                                 if (function_exists('gzcompress')) {
02805                                         if (isset($this->debug_flag) && $this->debug_flag) {
02806                                                 $payload .= "<!-- Content being deflated -->";
02807                                         }
02808                                         $this->outgoing_headers[] = "Content-Encoding: deflate";
02809                                         $payload = gzcompress($payload);
02810                                 } else {
02811                                         if (isset($this->debug_flag) && $this->debug_flag) {
02812                                                 $payload .= "<!-- Content will not be deflated: no gzcompress -->";
02813                                         }
02814                                 }
02815                    } else if (strstr($this->headers['Accept-Encoding'], 'gzip')) {
02816                                 if (function_exists('gzencode')) {
02817                                         if (isset($this->debug_flag) && $this->debug_flag) {
02818                                                 $payload .= "<!-- Content being gzipped -->";
02819                                         }
02820                                         $this->outgoing_headers[] = "Content-Encoding: gzip";
02821                                         $payload = gzencode($payload);
02822                                 } else {
02823                                         if (isset($this->debug_flag) && $this->debug_flag) {
02824                                                 $payload .= "<!-- Content will not be gzipped: no gzencode -->";
02825                                         }
02826                                 }
02827                         }
02828                 }
02829                 //end code
02830                 $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
02831                 reset($this->outgoing_headers);
02832                 foreach($this->outgoing_headers as $hdr){
02833                         header($hdr, false);
02834                 }
02835                 $this->response = join("\r\n",$this->outgoing_headers)."\r\n".$payload;
02836                 print $payload;
02837         }
02838 
02847         function verify_method($operation,$request){
02848                 if(isset($this->wsdl) && is_object($this->wsdl)){
02849                         if($this->wsdl->getOperationData($operation)){
02850                                 return true;
02851                         }
02852             } elseif(isset($this->operations[$operation])){
02853                         return true;
02854                 }
02855                 return false;
02856         }
02857 
02866         function add_to_map($methodname,$in,$out){
02867                         $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
02868         }
02869 
02883         function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false,$documentation=''){
02884                 if($this->externalWSDLURL){
02885                         die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
02886                 }
02887             if(false == $in) {
02888                 }
02889                 if(false == $out) {
02890                 }
02891                 if(false == $namespace) {
02892                 }
02893                 if(false == $soapaction) {
02894                         $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
02895                         $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
02896                         $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name";
02897                 }
02898                 if(false == $style) {
02899                         $style = "rpc";
02900                 }
02901                 if(false == $use) {
02902                         $use = "encoded";
02903                 }
02904                 
02905                 $this->operations[$name] = array(
02906             'name' => $name,
02907             'in' => $in,
02908             'out' => $out,
02909             'namespace' => $namespace,
02910             'soapaction' => $soapaction,
02911             'style' => $style);
02912         if($this->wsdl){
02913                 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation);
02914             }
02915                 return true;
02916         }
02917 
02927         function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
02928                 $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
02929         }
02930 
02936     function webDescription(){
02937                 $b = '
02938                 <html><head><title>NuSOAP: '.$this->wsdl->serviceName.'</title>
02939                 <style type="text/css">
02940                     body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
02941                     p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
02942                     pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
02943                     ul      { margin-top: 10px; margin-left: 20px; }
02944                     li      { list-style-type: none; margin-top: 10px; color: #000000; }
02945                     .content{
02946                         margin-left: 0px; padding-bottom: 2em; }
02947                     .nav {
02948                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
02949                         margin-top: 10px; margin-left: 0px; color: #000000;
02950                         background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
02951                     .title {
02952                         font-family: arial; font-size: 26px; color: #ffffff;
02953                         background-color: #999999; width: 105%; margin-left: 0px;
02954                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
02955                     .hidden {
02956                         position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
02957                         font-family: arial; overflow: hidden; width: 600;
02958                         padding: 20px; font-size: 10px; background-color: #999999;
02959                         layer-background-color:#FFFFFF; }
02960                     a,a:active  { color: charcoal; font-weight: bold; }
02961                     a:visited   { color: #666666; font-weight: bold; }
02962                     a:hover     { color: cc3300; font-weight: bold; }
02963                 </style>
02964                 <script language="JavaScript" type="text/javascript">
02965                 <!--
02966                 // POP-UP CAPTIONS...
02967                 function lib_bwcheck(){ //Browsercheck (needed)
02968                     this.ver=navigator.appVersion
02969                     this.agent=navigator.userAgent
02970                     this.dom=document.getElementById?1:0
02971                     this.opera5=this.agent.indexOf("Opera 5")>-1
02972                     this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
02973                     this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
02974                     this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
02975                     this.ie=this.ie4||this.ie5||this.ie6
02976                     this.mac=this.agent.indexOf("Mac")>-1
02977                     this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
02978                     this.ns4=(document.layers && !this.dom)?1:0;
02979                     this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
02980                     return this
02981                 }
02982                 var bw = new lib_bwcheck()
02983                 //Makes crossbrowser object.
02984                 function makeObj(obj){
02985                     this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
02986                     if(!this.evnt) return false
02987                     this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
02988                     this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
02989                     this.writeIt=b_writeIt;
02990                     return this
02991                 }
02992                 // A unit of measure that will be added when setting the position of a layer.
02993                 //var px = bw.ns4||window.opera?"":"px";
02994                 function b_writeIt(text){
02995                     if (bw.ns4){this.wref.write(text);this.wref.close()}
02996                     else this.wref.innerHTML = text
02997                 }
02998                 //Shows the messages
02999                 var oDesc;
03000                 function popup(divid){
03001                     if(oDesc = new makeObj(divid)){
03002                         oDesc.css.visibility = "visible"
03003                     }
03004                 }
03005                 function popout(){ // Hides message
03006                     if(oDesc) oDesc.css.visibility = "hidden"
03007                 }
03008                 //-->
03009                 </script>
03010                 </head>
03011                 <body>
03012                 <div class=content>
03013                         <br><br>
03014                         <div class=title>'.$this->wsdl->serviceName.'</div>
03015                         <div class=nav>
03016                                 <p>View the <a href="'.(isset($GLOBALS['PHP_SELF']) ? $GLOBALS['PHP_SELF'] : $_SERVER['PHP_SELF']).'?wsdl">WSDL</a> for the service.
03017                                 Click on an operation name to view it&apos;s details.</p>
03018                                 <ul>';
03019                                 foreach($this->wsdl->getOperations() as $op => $data){
03020                                     $b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>";
03021                                     // create hidden div
03022                                     $b .= "<div id='$op' class='hidden'>
03023                                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
03024                                     foreach($data as $donnie => $marie){ // loop through opdata
03025                                                 if($donnie == 'input' || $donnie == 'output'){ // show input/output data
03026                                                     $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
03027                                                     foreach($marie as $captain => $tenille){ // loop through data
03028                                                                 if($captain == 'parts'){ // loop thru parts
03029                                                                     $b .= "&nbsp;&nbsp;$captain:<br>";
03030                                                         //if(is_array($tenille)){
03031                                                                         foreach($tenille as $joanie => $chachi){
03032                                                                                         $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
03033                                                                         }
03034                                                                 //}
03035                                                                 } else {
03036                                                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
03037                                                                 }
03038                                                     }
03039                                                 } else {
03040                                                     $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
03041                                                 }
03042                                     }
03043                                         $b .= '</div>';
03044                                 }
03045                                 $b .= '
03046                                 <ul>
03047                         </div>
03048                 </div></body></html>';
03049                 return $b;
03050     }
03051 
03063     function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
03064     {
03065                 $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
03066                 $SERVER_PORT = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : $GLOBALS['SERVER_PORT'];
03067                 if ($SERVER_PORT == 80) {
03068                         $SERVER_PORT = '';
03069                 } else {
03070                         $SERVER_PORT = ':' . $SERVER_PORT;
03071                 }
03072                 $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
03073         if(false == $namespace) {
03074             $namespace = "http://$SERVER_NAME/soap/$serviceName";
03075         }
03076         
03077         if(false == $endpoint) {
03078                 if (isset($_SERVER['HTTPS'])) {
03079                         $HTTPS = $_SERVER['HTTPS'];
03080                 } elseif (isset($GLOBALS['HTTPS'])) {
03081                         $HTTPS = $GLOBALS['HTTPS'];
03082                 } else {
03083                         $HTTPS = '0';
03084                 }
03085                 if ($HTTPS == '1' || $HTTPS == 'on') {
03086                         $SCHEME = 'https';
03087                 } else {
03088                         $SCHEME = 'http';
03089                 }
03090             $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
03091         }
03092         
03093         if(false == $schemaTargetNamespace) {
03094             $schemaTargetNamespace = $namespace;
03095         }
03096         
03097                 $this->wsdl = new wsdl;
03098                 $this->wsdl->serviceName = $serviceName;
03099         $this->wsdl->endpoint = $endpoint;
03100                 $this->wsdl->namespaces['tns'] = $namespace;
03101                 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
03102                 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
03103                 if ($schemaTargetNamespace != $namespace) {
03104                         $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
03105                 }
03106         $this->wsdl->schemas[$schemaTargetNamespace][0] = new xmlschema('', '', $this->wsdl->namespaces);
03107         $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
03108         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
03109         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
03110         $this->wsdl->bindings[$serviceName.'Binding'] = array(
03111                 'name'=>$serviceName.'Binding',
03112             'style'=>$style,
03113             'transport'=>$transport,
03114             'portType'=>$serviceName.'PortType');
03115         $this->wsdl->ports[$serviceName.'Port'] = array(
03116                 'binding'=>$serviceName.'Binding',
03117             'location'=>$endpoint,
03118             'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
03119     }
03120 }
03121 
03122 
03123 
03124 ?><?php
03125 
03126 
03127 
03135 class wsdl extends nusoap_base {
03136         // URL or filename of the root of this WSDL
03137     var $wsdl; 
03138     // define internal arrays of bindings, ports, operations, messages, etc.
03139     var $schemas = array();
03140     var $currentSchema;
03141     var $message = array();
03142     var $complexTypes = array();
03143     var $messages = array();
03144     var $currentMessage;
03145     var $currentOperation;
03146     var $portTypes = array();
03147     var $currentPortType;
03148     var $bindings = array();
03149     var $currentBinding;
03150     var $ports = array();
03151     var $currentPort;
03152     var $opData = array();
03153     var $status = '';
03154     var $documentation = false;
03155     var $endpoint = ''; 
03156     // array of wsdl docs to import
03157     var $import = array(); 
03158     // parser vars
03159     var $parser;
03160     var $position = 0;
03161     var $depth = 0;
03162     var $depth_array = array();
03163         // for getting wsdl
03164         var $proxyhost = '';
03165     var $proxyport = '';
03166         var $proxyusername = '';
03167         var $proxypassword = '';
03168         var $timeout = 0;
03169         var $response_timeout = 30;
03170 
03183     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){
03184         $this->wsdl = $wsdl;
03185         $this->proxyhost = $proxyhost;
03186         $this->proxyport = $proxyport;
03187                 $this->proxyusername = $proxyusername;
03188                 $this->proxypassword = $proxypassword;
03189                 $this->timeout = $timeout;
03190                 $this->response_timeout = $response_timeout;
03191         
03192         // parse wsdl file
03193         if ($wsdl != "") {
03194             $this->debug('initial wsdl URL: ' . $wsdl);
03195             $this->parseWSDL($wsdl);
03196         }
03197         // imports
03198         // TODO: handle imports more properly, grabbing them in-line and nesting them
03199                 $imported_urls = array();
03200                 $imported = 1;
03201                 while ($imported > 0) {
03202                         $imported = 0;
03203                         // Schema imports
03204                         foreach ($this->schemas as $ns => $list) {
03205                                 foreach ($list as $xs) {
03206                                                 $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
03207                                     foreach ($xs->imports as $ns2 => $list2) {
03208                                         for ($ii = 0; $ii < count($list2); $ii++) {
03209                                                 if (! $list2[$ii]['loaded']) {
03210                                                         $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
03211                                                         $url = $list2[$ii]['location'];
03212                                                                         if ($url != '') {
03213                                                                                 $urlparts = parse_url($url);
03214                                                                                 if (!isset($urlparts['host'])) {
03215                                                                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . 
03216                                                                                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
03217                                                                                 }
03218                                                                                 if (! in_array($url, $imported_urls)) {
03219                                                                         $this->parseWSDL($url);
03220                                                                         $imported++;
03221                                                                         $imported_urls[] = $url;
03222                                                                 }
03223                                                                         } else {
03224                                                                                 $this->debug("Unexpected scenario: empty URL for unloaded import");
03225                                                                         }
03226                                                                 }
03227                                                         }
03228                                     } 
03229                                 }
03230                         }
03231                         // WSDL imports
03232                                 $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
03233                     foreach ($this->import as $ns => $list) {
03234                         for ($ii = 0; $ii < count($list); $ii++) {
03235                                 if (! $list[$ii]['loaded']) {
03236                                         $this->import[$ns][$ii]['loaded'] = true;
03237                                         $url = $list[$ii]['location'];
03238                                                         if ($url != '') {
03239                                                                 $urlparts = parse_url($url);
03240                                                                 if (!isset($urlparts['host'])) {
03241                                                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . 
03242                                                                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
03243                                                                 }
03244                                                                 if (! in_array($url, $imported_urls)) {
03245                                                         $this->parseWSDL($url);
03246                                                         $imported++;
03247                                                         $imported_urls[] = $url;
03248                                                 }
03249                                                         } else {
03250                                                                 $this->debug("Unexpected scenario: empty URL for unloaded import");
03251                                                         }
03252                                                 }
03253                                         }
03254                     } 
03255                         }
03256         // add new data to operation data
03257         foreach($this->bindings as $binding => $bindingData) {
03258             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
03259                 foreach($bindingData['operations'] as $operation => $data) {
03260                     $this->debug('post-parse data gathering for ' . $operation);
03261                     $this->bindings[$binding]['operations'][$operation]['input'] = 
03262                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
03263                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
03264                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
03265                     $this->bindings[$binding]['operations'][$operation]['output'] = 
03266                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
03267                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
03268                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
03269                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
03270                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
03271                                         }
03272                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
03273                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
03274                     }
03275                                         if (isset($bindingData['style'])) {
03276                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
03277                     }
03278                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
03279                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
03280                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
03281                 } 
03282             } 
03283         }
03284     }
03285 
03292     function parseWSDL($wsdl = '')
03293     {
03294         if ($wsdl == '') {
03295             $this->debug('no wsdl passed to parseWSDL()!!');
03296             $this->setError('no wsdl passed to parseWSDL()!!');
03297             return false;
03298         }
03299         
03300         // parse $wsdl for url format
03301         $wsdl_props = parse_url($wsdl);
03302 
03303         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
03304             $this->debug('getting WSDL http(s) URL ' . $wsdl);
03305                 // get wsdl
03306                 $tr = new soap_transport_http($wsdl);
03307                         $tr->request_method = 'GET';
03308                         $tr->useSOAPAction = false;
03309                         if($this->proxyhost && $this->proxyport){
03310                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
03311                         }
03312                         if (isset($wsdl_props['user'])) {
03313                 $tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']);
03314             }
03315                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
03316                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);
03317                         //$this->debug("WSDL response\n" . $tr->incoming_payload);
03318                         $this->debug("transport debug data...\n" . $tr->debug_str);
03319                         // catch errors
03320                         if($err = $tr->getError() ){
03321                                 $errstr = 'HTTP ERROR: '.$err;
03322                                 $this->debug($errstr);
03323                     $this->setError($errstr);
03324                                 unset($tr);
03325                     return false;
03326                         }
03327                         unset($tr);
03328         } else {
03329             // $wsdl is not http(s), so treat it as a file URL or plain file path
03330                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
03331                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
03332                 } else {
03333                         $path = $wsdl;
03334                 }
03335             $this->debug('getting WSDL file ' . $path);
03336             if ($fp = @fopen($path, 'r')) {
03337                 $wsdl_string = '';
03338                 while ($data = fread($fp, 32768)) {
03339                     $wsdl_string .= $data;
03340                 } 
03341                 fclose($fp);
03342             } else {
03343                 $errstr = "Bad path to WSDL file $path";
03344                 $this->debug($errstr);
03345                 $this->setError($errstr);
03346                 return false;
03347             } 
03348         }
03349         // end new code added
03350         // Create an XML parser.
03351         $this->parser = xml_parser_create(); 
03352         // Set the options for parsing the XML data.
03353         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
03354         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
03355         // Set the object for the parser.
03356         xml_set_object($this->parser, $this); 
03357         // Set the element handlers for the parser.
03358         xml_set_element_handler($this->parser, 'start_element', 'end_element');
03359         xml_set_character_data_handler($this->parser, 'character_data');
03360         // Parse the XML file.
03361         if (!xml_parse($this->parser, $wsdl_string, true)) {
03362             // Display an error message.
03363             $errstr = sprintf(
03364                                 'XML error parsing WSDL from %s on line %d: %s',
03365                                 $wsdl,
03366                 xml_get_current_line_number($this->parser),
03367                 xml_error_string(xml_get_error_code($this->parser))
03368                 );
03369             $this->debug($errstr);
03370                         $this->debug("XML payload:\n" . $wsdl_string);
03371             $this->setError($errstr);
03372             return false;
03373         } 
03374                 // free the parser
03375         xml_parser_free($this->parser);
03376                 // catch wsdl parse errors
03377                 if($this->getError()){
03378                         return false;
03379                 }
03380         return true;
03381     } 
03382 
03391     function start_element($parser, $name, $attrs)
03392     {
03393         if ($this->status == 'schema') {
03394             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
03395             $this->debug_str .= $this->currentSchema->debug_str;
03396             $this->currentSchema->debug_str = '';
03397         } elseif (ereg('schema$', $name)) {
03398             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
03399             $this->status = 'schema';
03400             $this->currentSchema = new xmlschema('', '', $this->namespaces);
03401             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
03402             $this->debug_str .= $this->currentSchema->debug_str;
03403             $this->currentSchema->debug_str = '';
03404         } else {
03405             // position in the total number of elements, starting from 0
03406             $pos = $this->position++;
03407             $depth = $this->depth++; 
03408             // set self as current value for this depth
03409             $this->depth_array[$depth] = $pos;
03410             $this->message[$pos] = array('cdata' => ''); 
03411             // get element prefix
03412             if (ereg(':', $name)) {
03413                 // get ns prefix
03414                 $prefix = substr($name, 0, strpos($name, ':')); 
03415                 // get ns
03416                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 
03417                 // get unqualified name
03418                 $name = substr(strstr($name, ':'), 1);
03419             } 
03420 
03421             if (count($attrs) > 0) {
03422                 foreach($attrs as $k => $v) {
03423                     // if ns declarations, add to class level array of valid namespaces
03424                     if (ereg("^xmlns", $k)) {
03425                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
03426                             $this->namespaces[$ns_prefix] = $v;
03427                         } else {
03428                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
03429                         } 
03430                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema') {
03431                             $this->XMLSchemaVersion = $v;
03432                             $this->namespaces['xsi'] = $v . '-instance';
03433                         } 
03434                     } //  
03435                     // expand each attribute
03436                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
03437                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
03438                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
03439                     } 
03440                     $eAttrs[$k] = $v;
03441                 } 
03442                 $attrs = $eAttrs;
03443             } else {
03444                 $attrs = array();
03445             } 
03446             // find status, register data
03447             switch ($this->status) {
03448                 case 'message':
03449                     if ($name == 'part') {
03450                         if (isset($attrs['type'])) {
03451                                     $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
03452                                     $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
03453                                 } 
03454                                     if (isset($attrs['element'])) {
03455                                         $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
03456                                     } 
03457                                 } 
03458                                 break;
03459                             case 'portType':
03460                                 switch ($name) {
03461                                     case 'operation':
03462                                         $this->currentPortOperation = $attrs['name'];
03463                                         $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
03464                                         if (isset($attrs['parameterOrder'])) {
03465                                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
03466                                                 } 
03467                                                 break;
03468                                             case 'documentation':
03469                                                 $this->documentation = true;
03470                                                 break; 
03471                                             // merge input/output data
03472                                             default:
03473                                                 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
03474                                                 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
03475                                                 break;
03476                                         } 
03477                                 break;
03478                                 case 'binding':
03479                                     switch ($name) {
03480                                         case 'binding': 
03481                                             // get ns prefix
03482                                             if (isset($attrs['style'])) {
03483                                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;
03484                                                 } 
03485                                                 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
03486                                                 break;
03487                                                 case 'header':
03488                                                     $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
03489                                                     break;
03490                                                 case 'operation':
03491                                                     if (isset($attrs['soapAction'])) {
03492                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
03493                                                     } 
03494                                                     if (isset($attrs['style'])) {
03495                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
03496                                                     } 
03497                                                     if (isset($attrs['name'])) {
03498                                                         $this->currentOperation = $attrs['name'];
03499                                                         $this->debug("current binding operation: $this->currentOperation");
03500                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
03501                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
03502                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
03503                                                     } 
03504                                                     break;
03505                                                 case 'input':
03506                                                     $this->opStatus = 'input';
03507                                                     break;
03508                                                 case 'output':
03509                                                     $this->opStatus = 'output';
03510                                                     break;
03511                                                 case 'body':
03512                                                     if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
03513                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
03514                                                     } else {
03515                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
03516                                                     } 
03517                                                     break;
03518                                         } 
03519                                         break;
03520                                 case 'service':
03521                                         switch ($name) {
03522                                             case 'port':
03523                                                 $this->currentPort = $attrs['name'];
03524                                                 $this->debug('current port: ' . $this->currentPort);
03525                                                 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
03526                                         
03527                                                 break;
03528                                             case 'address':
03529                                                 $this->ports[$this->currentPort]['location'] = $attrs['location'];
03530                                                 $this->ports[$this->currentPort]['bindingType'] = $namespace;
03531                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
03532                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
03533                                                 break;
03534                                         } 
03535                                         break;
03536                         } 
03537                 // set status
03538                 switch ($name) {
03539                         case 'import':
03540                             if (isset($attrs['location'])) {
03541                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
03542                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
03543                                 } else {
03544                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
03545                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
03546                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
03547                                         }
03548                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
03549                                 }
03550                                 break;
03551                         //wait for schema
03552                         //case 'types':
03553                         //      $this->status = 'schema';
03554                         //      break;
03555                         case 'message':
03556                                 $this->status = 'message';
03557                                 $this->messages[$attrs['name']] = array();
03558                                 $this->currentMessage = $attrs['name'];
03559                                 break;
03560                         case 'portType':
03561                                 $this->status = 'portType';
03562                                 $this->portTypes[$attrs['name']] = array();
03563                                 $this->currentPortType = $attrs['name'];
03564                                 break;
03565                         case "binding":
03566                                 if (isset($attrs['name'])) {
03567                                 // get binding name
03568                                         if (strpos($attrs['name'], ':')) {
03569                                         $this->currentBinding = $this->getLocalPart($attrs['name']);
03570                                         } else {
03571                                         $this->currentBinding = $attrs['name'];
03572                                         } 
03573                                         $this->status = 'binding';
03574                                         $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
03575                                         $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
03576                                 } 
03577                                 break;
03578                         case 'service':
03579                                 $this->serviceName = $attrs['name'];
03580                                 $this->status = 'service';
03581                                 $this->debug('current service: ' . $this->serviceName);
03582                                 break;
03583                         case 'definitions':
03584                                 foreach ($attrs as $name => $value) {
03585                                         $this->wsdl_info[$name] = $value;
03586                                 } 
03587                                 break;
03588                         } 
03589                 } 
03590         } 
03591 
03599         function end_element($parser, $name){ 
03600                 // unset schema status
03601                 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
03602                         $this->status = "";
03603                         $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
03604                 } 
03605                 if ($this->status == 'schema') {
03606                         $this->currentSchema->schemaEndElement($parser, $name);
03607                 } else {
03608                         // bring depth down a notch
03609                         $this->depth--;
03610                 } 
03611                 // end documentation
03612                 if ($this->documentation) {
03613                         //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
03614                         //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
03615                         $this->documentation = false;
03616                 } 
03617         } 
03618 
03626         function character_data($parser, $data)
03627         {
03628                 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
03629                 if (isset($this->message[$pos]['cdata'])) {
03630                         $this->message[$pos]['cdata'] .= $data;
03631                 } 
03632                 if ($this->documentation) {
03633                         $this->documentation .= $data;
03634                 } 
03635         } 
03636         
03637         function getBindingData($binding)
03638         {
03639                 if (is_array($this->bindings[$binding])) {
03640                         return $this->bindings[$binding];
03641                 } 
03642         }
03643         
03651         function getOperations($bindingType = 'soap')
03652         {
03653                 $ops = array();
03654                 if ($bindingType == 'soap') {
03655                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03656                 }
03657                 // loop thru ports
03658                 foreach($this->ports as $port => $portData) {
03659                         // binding type of port matches parameter
03660                         if ($portData['bindingType'] == $bindingType) {
03661                                 //$this->debug("getOperations for port $port");
03662                                 //$this->debug("port data: " . $this->varDump($portData));
03663                                 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
03664                                 // merge bindings
03665                                 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
03666                                         $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
03667                                 }
03668                         }
03669                 } 
03670                 return $ops;
03671         } 
03672         
03681         function getOperationData($operation, $bindingType = 'soap')
03682         {
03683                 if ($bindingType == 'soap') {
03684                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03685                 }
03686                 // loop thru ports
03687                 foreach($this->ports as $port => $portData) {
03688                         // binding type of port matches parameter
03689                         if ($portData['bindingType'] == $bindingType) {
03690                                 // get binding
03691                                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
03692                                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
03693                                         if ($operation == $bOperation) {
03694                                                 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
03695                                             return $opData;
03696                                         } 
03697                                 } 
03698                         }
03699                 } 
03700         }
03701         
03720         function getTypeDef($type, $ns) {
03721                 if ((! $ns) && isset($this->namespaces['tns'])) {
03722                         $ns = $this->namespaces['tns'];
03723                 }
03724                 if (isset($this->schemas[$ns])) {
03725                         foreach ($this->schemas[$ns] as $xs) {
03726                                 $t = $xs->getTypeDef($type);
03727                                 $this->debug_str .= $xs->debug_str;
03728                                 $xs->debug_str = '';
03729                                 if ($t) {
03730                                         return $t;
03731                                 }
03732                         }
03733                 }
03734                 return false;
03735         }
03736 
03743         function serialize()
03744         {
03745                 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?><definitions';
03746                 foreach($this->namespaces as $k => $v) {
03747                         $xml .= " xmlns:$k=\"$v\"";
03748                 } 
03749                 // 10.9.02 - add poulter fix for wsdl and tns declarations
03750                 if (isset($this->namespaces['wsdl'])) {
03751                         $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
03752                 } 
03753                 if (isset($this->namespaces['tns'])) {
03754                         $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
03755                 } 
03756                 $xml .= '>'; 
03757                 // imports
03758                 if (sizeof($this->import) > 0) {
03759                         foreach($this->import as $ns => $list) {
03760                                 foreach ($list as $ii) {
03761                                         if ($ii['location'] != '') {
03762                                                 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
03763                                         } else {
03764                                                 $xml .= '<import namespace="' . $ns . '" />';
03765                                         }
03766                                 }
03767                         } 
03768                 } 
03769                 // types
03770                 if (count($this->schemas)>=1) {
03771                         $xml .= '<types>';
03772                         foreach ($this->schemas as $ns => $list) {
03773                                 foreach ($list as $xs) {
03774                                         $xml .= $xs->serializeSchema();
03775                                 }
03776                         }
03777                         $xml .= '</types>';
03778                 } 
03779                 // messages
03780                 if (count($this->messages) >= 1) {
03781                         foreach($this->messages as $msgName => $msgParts) {
03782                                 $xml .= '<message name="' . $msgName . '">';
03783                                 if(is_array($msgParts)){
03784                                         foreach($msgParts as $partName => $partType) {
03785                                                 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
03786                                                 if (strpos($partType, ':')) {
03787                                                     $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
03788                                                 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
03789                                                     // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
03790                                                     $typePrefix = 'xsd';
03791                                                 } else {
03792                                                     foreach($this->typemap as $ns => $types) {
03793                                                         if (isset($types[$partType])) {
03794                                                             $typePrefix = $this->getPrefixFromNamespace($ns);
03795                                                         } 
03796                                                     } 
03797                                                     if (!isset($typePrefix)) {
03798                                                         die("$partType has no namespace!");
03799                                                     } 
03800                                                 } 
03801                                                 $xml .= '<part name="' . $partName . '" type="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
03802                                         }
03803                                 }
03804                                 $xml .= '</message>';
03805                         } 
03806                 } 
03807                 // bindings & porttypes
03808                 if (count($this->bindings) >= 1) {
03809                         $binding_xml = '';
03810                         $portType_xml = '';
03811                         foreach($this->bindings as $bindingName => $attrs) {
03812                                 $binding_xml .= '<binding name="' . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
03813                                 $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
03814                                 $portType_xml .= '<portType name="' . $attrs['portType'] . '">';
03815                                 foreach($attrs['operations'] as $opName => $opParts) {
03816                                         $binding_xml .= '<operation name="' . $opName . '">';
03817                                         $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $attrs['style'] . '"/>';
03818                                         if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
03819                                                 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
03820                                         } else {
03821                                                 $enc_style = '';
03822                                         }
03823                                         $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
03824                                         if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
03825                                                 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
03826                                         } else {
03827                                                 $enc_style = '';
03828                                         }
03829                                         $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
03830                                         $binding_xml .= '</operation>';
03831                                         $portType_xml .= '<operation name="' . $opParts['name'] . '"';
03832                                         if (isset($opParts['parameterOrder'])) {
03833                                             $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
03834                                         } 
03835                                         $portType_xml .= '>';
03836                                         if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
03837                                                 $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
03838                                         }
03839                                         $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
03840                                         $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
03841                                         $portType_xml .= '</operation>';
03842                                 } 
03843                                 $portType_xml .= '</portType>';
03844                                 $binding_xml .= '</binding>';
03845                         } 
03846                         $xml .= $portType_xml . $binding_xml;
03847                 } 
03848                 // services
03849                 $xml .= '<service name="' . $this->serviceName . '">';
03850                 if (count($this->ports) >= 1) {
03851                         foreach($this->ports as $pName => $attrs) {
03852                                 $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
03853                                 $xml .= '<soap:address location="' . $attrs['location'] . '"/>';
03854                                 $xml .= '</port>';
03855                         } 
03856                 } 
03857                 $xml .= '</service>';
03858                 return $xml . '</definitions>';
03859         } 
03860         
03872         function serializeRPCParameters($operation, $direction, $parameters)
03873         {
03874                 $this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion); 
03875                 
03876                 if ($direction != 'input' && $direction != 'output') {
03877                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
03878                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
03879                         return false;
03880                 } 
03881                 if (!$opData = $this->getOperationData($operation)) {
03882                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
03883                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
03884                         return false;
03885                 }
03886                 $this->debug($this->varDump($opData));
03887 
03888                 // Get encoding style for output and set to current
03889                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
03890                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
03891                         $encodingStyle = $opData['output']['encodingStyle'];
03892                         $enc_style = $encodingStyle;
03893                 }
03894 
03895                 // set input params
03896                 $xml = '';
03897                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
03898                         
03899                         $use = $opData[$direction]['use'];
03900                         $this->debug("use=$use");
03901                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
03902                         if (is_array($parameters)) {
03903                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
03904                                 $this->debug('have ' . $parametersArrayType . ' parameters');
03905                                 foreach($opData[$direction]['parts'] as $name => $type) {
03906                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
03907                                         // Track encoding style
03908                                         if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
03909                                                 $encodingStyle = $opData[$direction]['encodingStyle'];                  
03910                                                 $enc_style = $encodingStyle;
03911                                         } else {
03912                                                 $enc_style = false;
03913                                         }
03914                                         // NOTE: add error handling here
03915                                         // if serializeType returns false, then catch global error and fault
03916                                         if ($parametersArrayType == 'arraySimple') {
03917                                                 $p = array_shift($parameters);
03918                                                 $this->debug('calling serializeType w/indexed param');
03919                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
03920                                         } elseif (isset($parameters[$name])) {
03921                                                 $this->debug('calling serializeType w/named param');
03922                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
03923                                         } else {
03924                                                 // TODO: only send nillable
03925                                                 $this->debug('calling serializeType w/null param');
03926                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
03927                                         }
03928                                 }
03929                         } else {
03930                                 $this->debug('no parameters passed.');
03931                         }
03932                 }
03933                 return $xml;
03934         } 
03935         
03947         function serializeParameters($operation, $direction, $parameters)
03948         {
03949                 $this->debug('in serializeParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion); 
03950                 
03951                 if ($direction != 'input' && $direction != 'output') {
03952                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
03953                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
03954                         return false;
03955                 } 
03956                 if (!$opData = $this->getOperationData($operation)) {
03957                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
03958                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
03959                         return false;
03960                 }
03961                 $this->debug($this->varDump($opData));
03962                 
03963                 // Get encoding style for output and set to current
03964                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
03965                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
03966                         $encodingStyle = $opData['output']['encodingStyle'];
03967                         $enc_style = $encodingStyle;
03968                 }
03969                 
03970                 // set input params
03971                 $xml = '';
03972                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
03973                         
03974                         $use = $opData[$direction]['use'];
03975                         $this->debug("use=$use");
03976                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
03977                         if (is_array($parameters)) {
03978                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
03979                                 $this->debug('have ' . $parametersArrayType . ' parameters');
03980                                 foreach($opData[$direction]['parts'] as $name => $type) {
03981                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
03982                                         // Track encoding style
03983                                         if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
03984                                                 $encodingStyle = $opData[$direction]['encodingStyle'];                  
03985                                                 $enc_style = $encodingStyle;
03986                                         } else {
03987                                                 $enc_style = false;
03988                                         }
03989                                         // NOTE: add error handling here
03990                                         // if serializeType returns false, then catch global error and fault
03991                                         if ($parametersArrayType == 'arraySimple') {
03992                                                 $p = array_shift($parameters);
03993                                                 $this->debug('calling serializeType w/indexed param');
03994                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
03995                                         } elseif (isset($parameters[$name])) {
03996                                                 $this->debug('calling serializeType w/named param');
03997                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
03998                                         } else {
03999                                                 // TODO: only send nillable
04000                                                 $this->debug('calling serializeType w/null param');
04001                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
04002                                         }
04003                                 }
04004                         } else {
04005                                 $this->debug('no parameters passed.');
04006                         }
04007                 }
04008                 return $xml;
04009         } 
04010         
04022         function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false)
04023         {
04024                 $this->debug("in serializeType: $name, $type, $value, $use, $encodingStyle");
04025                 if($use == 'encoded' && $encodingStyle) {
04026                         $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
04027                 }
04028 
04029                 // if a soap_val has been supplied, let its type override the WSDL
04030         if (is_object($value) && get_class($value) == 'soapval') {
04031                 // TODO: get attributes from soapval?
04032                 if ($value->type_ns) {
04033                         $type = $value->type_ns . ':' . $value->type;
04034                 } else {
04035                         $type = $value->type;
04036                 }
04037                 $value = $value->value;
04038                 $forceType = true;
04039                 $this->debug("in serializeType: soapval overrides type to $type, value to $value");
04040         } else {
04041                 $forceType = false;
04042         }
04043 
04044                 $xml = '';
04045                 if (strpos($type, ':')) {
04046                         $uqType = substr($type, strrpos($type, ':') + 1);
04047                         $ns = substr($type, 0, strrpos($type, ':'));
04048                         $this->debug("got a prefixed type: $uqType, $ns");
04049                         if ($this->getNamespaceFromPrefix($ns)) {
04050                                 $ns = $this->getNamespaceFromPrefix($ns);
04051                                 $this->debug("expanded prefixed type: $uqType, $ns");
04052                         }
04053 
04054                         if($ns == $this->XMLSchemaVersion){
04055                                 
04056                                 if (is_null($value)) {
04057                                         if ($use == 'literal') {
04058                                                 // TODO: depends on nillable
04059                                                 return "<$name/>";
04060                                         } else {
04061                                                 return "<$name xsi:nil=\"true\"/>";
04062                                         }
04063                                 }
04064                         if ($uqType == 'boolean' && !$value) {
04065                                         $value = 'false';
04066                                 } elseif ($uqType == 'boolean') {
04067                                         $value = 'true';
04068                                 } 
04069                                 if ($uqType == 'string' && gettype($value) == 'string') {
04070                                         $value = $this->expandEntities($value);
04071                                 } 
04072                                 // it's a scalar
04073                                 // TODO: what about null/nil values?
04074                                 // check type isn't a custom type extending xmlschema namespace
04075                                 if (!$this->getTypeDef($uqType, $ns)) {
04076                                         if ($use == 'literal') {
04077                                                 if ($forceType) {
04078                                                         return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\">$value</$name>";
04079                                                 } else {
04080                                                         return "<$name>$value</$name>";
04081                                                 }
04082                                         } else {
04083                                                 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\"$encodingStyle>$value</$name>";
04084                                         }
04085                                 }
04086                         } else if ($ns == 'http://xml.apache.org/xml-soap') {
04087                                 if ($uqType == 'Map') {
04088                                         $contents = '';
04089                                         foreach($value as $k => $v) {
04090                                                 $this->debug("serializing map element: key $k, value $v");
04091                                                 $contents .= '<item>';
04092                                                 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
04093                                                 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
04094                                                 $contents .= '</item>';
04095                                         }
04096                                         if ($use == 'literal') {
04097                                                 if ($forceType) {
04098                                                 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\">$contents</$name>";
04099                                                 } else {
04100                                                         return "<$name>$contents</$name>";
04101                                                 }
04102                                         } else {
04103                                                 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\"$encodingStyle>$contents</$name>";
04104                                         }
04105                                 }
04106                         }
04107                 } else {
04108                         $this->debug("No namespace for type $type");
04109                         $ns = '';
04110                         $uqType = $type;
04111                 }
04112                 if(!$typeDef = $this->getTypeDef($uqType, $ns)){
04113                         $this->setError("$type ($uqType) is not a supported type.");
04114                         $this->debug("$type ($uqType) is not a supported type.");
04115                         return false;
04116                 } else {
04117                         foreach($typeDef as $k => $v) {
04118                                 $this->debug("typedef, $k: $v");
04119                         }
04120                 }
04121                 $phpType = $typeDef['phpType'];
04122                 $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 
04123                 // if php type == struct, map value to the <all> element names
04124                 if ($phpType == 'struct') {
04125                         if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
04126                                 $elementName = $uqType;
04127                                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04128                                         $elementNS = " xmlns=\"$ns\"";
04129                                 }
04130                         } else {
04131                                 $elementName = $name;
04132                                 $elementNS = '';
04133                         }
04134                         if (is_null($value)) {
04135                                 if ($use == 'literal') {
04136                                         // TODO: depends on nillable
04137                                         return "<$elementName$elementNS/>";
04138                                 } else {
04139                                         return "<$elementName$elementNS xsi:nil=\"true\"/>";
04140                                 }
04141                         }
04142                         if ($use == 'literal') {
04143                                 if ($forceType) {
04144                                         $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
04145                                 } else {
04146                                         $xml = "<$elementName$elementNS>";
04147                                 }
04148                         } else {
04149                                 $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
04150                         }
04151                         
04152                         if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
04153                                 if (is_array($value)) {
04154                                         $xvalue = $value;
04155                                 } elseif (is_object($value)) {
04156                                         $xvalue = get_object_vars($value);
04157                                 } else {
04158                                         $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
04159                                         $xvalue = array();
04160                                 }
04161                                 // toggle whether all elements are present - ideally should validate against schema
04162                                 if(count($typeDef['elements']) != count($xvalue)){
04163                                         $optionals = true;
04164                                 }
04165                                 foreach($typeDef['elements'] as $eName => $attrs) {
04166                                         // if user took advantage of a minOccurs=0, then only serialize named parameters
04167                                         if(isset($optionals) && !isset($xvalue[$eName])){
04168                                                 // do nothing
04169                                         } else {
04170                                                 // get value
04171                                                 if (isset($xvalue[$eName])) {
04172                                                     $v = $xvalue[$eName];
04173                                                 } else {
04174                                                     $v = null;
04175                                                 }
04176                                                 // TODO: if maxOccurs > 1 (not just unbounded), then allow serialization of an array
04177                                                 if (isset($attrs['maxOccurs']) && $attrs['maxOccurs'] == 'unbounded' && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
04178                                                         $vv = $v;
04179                                                         foreach ($vv as $k => $v) {
04180                                                                 if (isset($attrs['type'])) {
04181                                                                         // serialize schema-defined type
04182                                                                     $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
04183                                                                 } else {
04184                                                                         // serialize generic type
04185                                                                     $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
04186                                                                     $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
04187                                                                 }
04188                                                         }
04189                                                 } else {
04190                                                         if (isset($attrs['type'])) {
04191                                                                 // serialize schema-defined type
04192                                                             $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
04193                                                         } else {
04194                                                                 // serialize generic type
04195                                                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
04196                                                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
04197                                                         }
04198                                                 }
04199                                         }
04200                                 } 
04201                         } else {
04202                                 $this->debug("Expected elements for XML Schema type $ns:$uqType");
04203                         }
04204                         $xml .= "</$elementName>";
04205                 } elseif ($phpType == 'array') {
04206                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04207                                 $elementNS = " xmlns=\"$ns\"";
04208                         } else {
04209                                 $elementNS = '';
04210                         }
04211                         if (is_null($value)) {
04212                                 if ($use == 'literal') {
04213                                         // TODO: depends on nillable
04214                                         return "<$name$elementNS/>";
04215                                 } else {
04216                                         return "<$name$elementNS xsi:nil=\"true\"/>";
04217                                 }
04218                         }
04219                         if (isset($typeDef['multidimensional'])) {
04220                                 $nv = array();
04221                                 foreach($value as $v) {
04222                                         $cols = ',' . sizeof($v);
04223                                         $nv = array_merge($nv, $v);
04224                                 } 
04225                                 $value = $nv;
04226                         } else {
04227                                 $cols = '';
04228                         } 
04229                         if (is_array($value) && sizeof($value) >= 1) {
04230                                 $rows = sizeof($value);
04231                                 $contents = '';
04232                                 foreach($value as $k => $v) {
04233                                         $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
04234                                         //if (strpos($typeDef['arrayType'], ':') ) {
04235                                         if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
04236                                             $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
04237                                         } else {
04238                                             $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
04239                                         } 
04240                                 }
04241                                 $this->debug('contents: '.$this->varDump($contents));
04242                         } else {
04243                                 $rows = 0;
04244                                 $contents = null;
04245                         }
04246                         // TODO: for now, an empty value will be serialized as a zero element
04247                         // array.  Revisit this when coding the handling of null/nil values.
04248                         if ($use == 'literal') {
04249                                 $xml = "<$name$elementNS>"
04250                                         .$contents
04251                                         ."</$name>";
04252                         } else {
04253                                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
04254                                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
04255                                         .':arrayType="'
04256                                         .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
04257                                         .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
04258                                         .$contents
04259                                         ."</$name>";
04260                         }
04261                 } elseif ($phpType == 'scalar') {
04262                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04263                                 $elementNS = " xmlns=\"$ns\"";
04264                         } else {
04265                                 $elementNS = '';
04266                         }
04267                         if ($use == 'literal') {
04268                                 if ($forceType) {
04269                                         return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
04270                                 } else {
04271                                         return "<$name$elementNS>$value</$name>";
04272                                 }
04273                         } else {
04274                                 return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
04275                         }
04276                 }
04277                 $this->debug('returning: '.$this->varDump($xml));
04278                 return $xml;
04279         }
04280         
04300         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
04301                 if (count($elements) > 0) {
04302                 foreach($elements as $n => $e){
04303                     // expand each element
04304                     foreach ($e as $k => $v) {
04305                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
04306                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
04307                             $ee[$k] = $v;
04308                         }
04309                         $eElements[$n] = $ee;
04310                 }
04311                 $elements = $eElements;
04312                 }
04313                 
04314                 if (count($attrs) > 0) {
04315                 foreach($attrs as $n => $a){
04316                     // expand each attribute
04317                     foreach ($a as $k => $v) {
04318                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
04319                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
04320                             $aa[$k] = $v;
04321                         }
04322                         $eAttrs[$n] = $aa;
04323                 }
04324                 $attrs = $eAttrs;
04325                 }
04326 
04327                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
04328                 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
04329 
04330                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04331                 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
04332         }
04333 
04344         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
04345                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
04346 
04347                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04348                 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType);
04349         }
04350 
04364         function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = ''){
04365                 if ($style == 'rpc' && $use == 'encoded') {
04366                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
04367                 } else {
04368                         $encodingStyle = '';
04369                 } 
04370                 // get binding
04371                 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
04372                 array(
04373                 'name' => $name,
04374                 'binding' => $this->serviceName . 'Binding',
04375                 'endpoint' => $this->endpoint,
04376                 'soapAction' => $soapaction,
04377                 'style' => $style,
04378                 'input' => array(
04379                         'use' => $use,
04380                         'namespace' => $namespace,
04381                         'encodingStyle' => $encodingStyle,
04382                         'message' => $name . 'Request',
04383                         'parts' => $in),
04384                 'output' => array(
04385                         'use' => $use,
04386                         'namespace' => $namespace,
04387                         'encodingStyle' => $encodingStyle,
04388                         'message' => $name . 'Response',
04389                         'parts' => $out),
04390                 'namespace' => $namespace,
04391                 'transport' => 'http://schemas.xmlsoap.org/soap/http',
04392                 'documentation' => $documentation); 
04393                 // add portTypes
04394                 // add messages
04395                 if($in)
04396                 {
04397                         foreach($in as $pName => $pType)
04398                         {
04399                                 if(strpos($pType,':')) {
04400                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
04401                                 }
04402                                 $this->messages[$name.'Request'][$pName] = $pType;
04403                         }
04404                 } else {
04405             $this->messages[$name.'Request']= '0';
04406         }
04407                 if($out)
04408                 {
04409                         foreach($out as $pName => $pType)
04410                         {
04411                                 if(strpos($pType,':')) {
04412                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
04413                                 }
04414                                 $this->messages[$name.'Response'][$pName] = $pType;
04415                         }
04416                 } else {
04417             $this->messages[$name.'Response']= '0';
04418         }
04419                 return true;
04420         } 
04421 }
04422 ?><?php
04423 
04424 
04425 
04434 class soap_parser extends nusoap_base {
04435 
04436         var $xml = '';
04437         var $xml_encoding = '';
04438         var $method = '';
04439         var $root_struct = '';
04440         var $root_struct_name = '';
04441         var $root_struct_namespace = '';
04442         var $root_header = '';
04443     var $document = '';                 // incoming SOAP body (text)
04444         // determines where in the message we are (envelope,header,body,method)
04445         var $status = '';
04446         var $position = 0;
04447         var $depth = 0;
04448         var $default_namespace = '';
04449         var $namespaces = array();
04450         var $message = array();
04451     var $parent = '';
04452         var $fault = false;
04453         var $fault_code = '';
04454         var $fault_str = '';
04455         var $fault_detail = '';
04456         var $depth_array = array();
04457         var $debug_flag = true;
04458         var $soapresponse = NULL;
04459         var $responseHeaders = '';      // incoming SOAP headers (text)
04460         var $body_position = 0;
04461         // for multiref parsing:
04462         // array of id => pos
04463         var $ids = array();
04464         // array of id => hrefs => pos
04465         var $multirefs = array();
04466         // toggle for auto-decoding element content
04467         var $decode_utf8 = true;
04468 
04478         function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
04479                 $this->xml = $xml;
04480                 $this->xml_encoding = $encoding;
04481                 $this->method = $method;
04482                 $this->decode_utf8 = $decode_utf8;
04483 
04484                 // Check whether content has been read.
04485                 if(!empty($xml)){
04486                         $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding);
04487                         // Create an XML parser - why not xml_parser_create_ns?
04488                         $this->parser = xml_parser_create($this->xml_encoding);
04489                         // Set the options for parsing the XML data.
04490                         //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
04491                         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
04492                         xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
04493                         // Set the object for the parser.
04494                         xml_set_object($this->parser, $this);
04495                         // Set the element handlers for the parser.
04496                         xml_set_element_handler($this->parser, 'start_element','end_element');
04497                         xml_set_character_data_handler($this->parser,'character_data');
04498 
04499                         // Parse the XML file.
04500                         if(!xml_parse($this->parser,$xml,true)){
04501                             // Display an error message.
04502                             $err = sprintf('XML error parsing SOAP payload on line %d: %s',
04503                             xml_get_current_line_number($this->parser),
04504                             xml_error_string(xml_get_error_code($this->parser)));
04505                                 $this->debug($err);
04506                                 $this->debug("XML payload:\n" . $xml);
04507                                 $this->setError($err);
04508                         } else {
04509                                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
04510                                 // get final value
04511                                 $this->soapresponse = $this->message[$this->root_struct]['result'];
04512                                 // get header value: no, because this is documented as XML string
04513 //                              if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
04514 //                                      $this->responseHeaders = $this->message[$this->root_header]['result'];
04515 //                              }
04516                                 // resolve hrefs/ids
04517                                 if(sizeof($this->multirefs) > 0){
04518                                         foreach($this->multirefs as $id => $hrefs){
04519                                                 $this->debug('resolving multirefs for id: '.$id);
04520                                                 $idVal = $this->buildVal($this->ids[$id]);
04521                                                 foreach($hrefs as $refPos => $ref){
04522                                                         $this->debug('resolving href at pos '.$refPos);
04523                                                         $this->multirefs[$id][$refPos] = $idVal;
04524                                                 }
04525                                         }
04526                                 }
04527                         }
04528                         xml_parser_free($this->parser);
04529                 } else {
04530                         $this->debug('xml was empty, didn\'t parse!');
04531                         $this->setError('xml was empty, didn\'t parse!');
04532                 }
04533         }
04534 
04543         function start_element($parser, $name, $attrs) {
04544                 // position in a total number of elements, starting from 0
04545                 // update class level pos
04546                 $pos = $this->position++;
04547                 // and set mine
04548                 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
04549                 // depth = how many levels removed from root?
04550                 // set mine as current global depth and increment global depth value
04551                 $this->message[$pos]['depth'] = $this->depth++;
04552 
04553                 // else add self as child to whoever the current parent is
04554                 if($pos != 0){
04555                         $this->message[$this->parent]['children'] .= '|'.$pos;
04556                 }
04557                 // set my parent
04558                 $this->message[$pos]['parent'] = $this->parent;
04559                 // set self as current parent
04560                 $this->parent = $pos;
04561                 // set self as current value for this depth
04562                 $this->depth_array[$this->depth] = $pos;
04563                 // get element prefix
04564                 if(strpos($name,':')){
04565                         // get ns prefix
04566                         $prefix = substr($name,0,strpos($name,':'));
04567                         // get unqualified name
04568                         $name = substr(strstr($name,':'),1);
04569                 }
04570                 // set status
04571                 if($name == 'Envelope'){
04572                         $this->status = 'envelope';
04573                 } elseif($name == 'Header'){
04574                         $this->root_header = $pos;
04575                         $this->status = 'header';
04576                 } elseif($name == 'Body'){
04577                         $this->status = 'body';
04578                         $this->body_position = $pos;
04579                 // set method
04580                 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
04581                         $this->status = 'method';
04582                         $this->root_struct_name = $name;
04583                         $this->root_struct = $pos;
04584                         $this->message[$pos]['type'] = 'struct';
04585                         $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
04586                 }
04587                 // set my status
04588                 $this->message[$pos]['status'] = $this->status;
04589                 // set name
04590                 $this->message[$pos]['name'] = htmlspecialchars($name);
04591                 // set attrs
04592                 $this->message[$pos]['attrs'] = $attrs;
04593 
04594                 // loop through atts, logging ns and type declarations
04595         $attstr = '';
04596                 foreach($attrs as $key => $value){
04597                 $key_prefix = $this->getPrefix($key);
04598                         $key_localpart = $this->getLocalPart($key);
04599                         // if ns declarations, add to class level array of valid namespaces
04600             if($key_prefix == 'xmlns'){
04601                                 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
04602                                         $this->XMLSchemaVersion = $value;
04603                                         $this->namespaces['xsd'] = $this->XMLSchemaVersion;
04604                                         $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
04605                                 }
04606                 $this->namespaces[$key_localpart] = $value;
04607                                 // set method namespace
04608                                 if($name == $this->root_struct_name){
04609                                         $this->methodNamespace = $value;
04610                                 }
04611                         // if it's a type declaration, set type
04612             } elseif($key_localpart == 'type'){
04613                 $value_prefix = $this->getPrefix($value);
04614                 $value_localpart = $this->getLocalPart($value);
04615                                 $this->message[$pos]['type'] = $value_localpart;
04616                                 $this->message[$pos]['typePrefix'] = $value_prefix;
04617                 if(isset($this->namespaces[$value_prefix])){
04618                         $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
04619                 } else if(isset($attrs['xmlns:'.$value_prefix])) {
04620                                         $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
04621                 }
04622                                 // should do something here with the namespace of specified type?
04623                         } elseif($key_localpart == 'arrayType'){
04624                                 $this->message[$pos]['type'] = 'array';
04625                                 /* do arrayType ereg here
04626                                 [1]    arrayTypeValue    ::=    atype asize
04627                                 [2]    atype    ::=    QName rank*
04628                                 [3]    rank    ::=    '[' (',')* ']'
04629                                 [4]    asize    ::=    '[' length~ ']'
04630                                 [5]    length    ::=    nextDimension* Digit+
04631                                 [6]    nextDimension    ::=    Digit+ ','
04632                                 */
04633                                 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
04634                                 if(ereg($expr,$value,$regs)){
04635                                         $this->message[$pos]['typePrefix'] = $regs[1];
04636                                         $this->message[$pos]['arrayTypePrefix'] = $regs[1];
04637                         if (isset($this->namespaces[$regs[1]])) {
04638                                 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
04639                         } else if (isset($attrs['xmlns:'.$regs[1]])) {
04640                                                 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
04641                         }
04642                                         $this->message[$pos]['arrayType'] = $regs[2];
04643                                         $this->message[$pos]['arraySize'] = $regs[3];
04644                                         $this->message[$pos]['arrayCols'] = $regs[4];
04645                                 }
04646                         }
04647                         // log id
04648                         if($key == 'id'){
04649                                 $this->ids[$value] = $pos;
04650                         }
04651                         // root
04652                         if($key_localpart == 'root' && $value == 1){
04653                                 $this->status = 'method';
04654                                 $this->root_struct_name = $name;
04655                                 $this->root_struct = $pos;
04656                                 $this->debug("found root struct $this->root_struct_name, pos $pos");
04657                         }
04658             // for doclit
04659             $attstr .= " $key=\"$value\"";
04660                 }
04661         // get namespace - must be done after namespace atts are processed
04662                 if(isset($prefix)){
04663                         $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
04664                         $this->default_namespace = $this->namespaces[$prefix];
04665                 } else {
04666                         $this->message[$pos]['namespace'] = $this->default_namespace;
04667                 }
04668         if($this->status == 'header'){
04669                 if ($this->root_header != $pos) {
04670                         $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
04671                 }
04672         } elseif($this->root_struct_name != ''){
04673                 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
04674         }
04675         }
04676 
04684         function end_element($parser, $name) {
04685                 // position of current element is equal to the last value left in depth_array for my depth
04686                 $pos = $this->depth_array[$this->depth--];
04687 
04688         // get element prefix
04689                 if(strpos($name,':')){
04690                         // get ns prefix
04691                         $prefix = substr($name,0,strpos($name,':'));
04692                         // get unqualified name
04693                         $name = substr(strstr($name,':'),1);
04694                 }
04695                 
04696                 // build to native type
04697                 if(isset($this->body_position) && $pos > $this->body_position){
04698                         // deal w/ multirefs
04699                         if(isset($this->message[$pos]['attrs']['href'])){
04700                                 // get id
04701                                 $id = substr($this->message[$pos]['attrs']['href'],1);
04702                                 // add placeholder to href array
04703                                 $this->multirefs[$id][$pos] = 'placeholder';
04704                                 // add set a reference to it as the result value
04705                                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
04706             // build complex values
04707                         } elseif($this->message[$pos]['children'] != ''){
04708                         
04709                                 // if result has already been generated (struct/array
04710                                 if(!isset($this->message[$pos]['result'])){
04711                                         $this->message[$pos]['result'] = $this->buildVal($pos);
04712                                 }
04713                                 
04714                         // set value of simple type
04715                         } else {
04716                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
04717                 if (isset($this->message[$pos]['type'])) {
04718                                         $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'] : '');
04719                                 } else {
04720                                         $parent = $this->message[$pos]['parent'];
04721                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
04722                                                 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
04723                                         } else {
04724                                                 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
04725                                         }
04726                                 }
04727 
04728                                 /* add value to parent's result, if parent is struct/array
04729                                 $parent = $this->message[$pos]['parent'];
04730                                 if($this->message[$parent]['type'] != 'map'){
04731                                         if(strtolower($this->message[$parent]['type']) == 'array'){
04732                                                 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
04733                                         } else {
04734                                                 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
04735                                         }
04736                                 }
04737                                 */
04738                         }
04739                 }
04740                 
04741         // for doclit
04742         if($this->status == 'header'){
04743                 if ($this->root_header != $pos) {
04744                         $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
04745                 }
04746         } elseif($pos >= $this->root_struct){
04747                 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
04748         }
04749                 // switch status
04750                 if($pos == $this->root_struct){
04751                         $this->status = 'body';
04752                         $this->root_struct_namespace = $this->message[$pos]['namespace'];
04753                 } elseif($name == 'Body'){
04754                         $this->status = 'envelope';
04755                  } elseif($name == 'Header'){
04756                         $this->status = 'envelope';
04757                 } elseif($name == 'Envelope'){
04758                         //
04759                 }
04760                 // set parent back to my parent
04761                 $this->parent = $this->message[$pos]['parent'];
04762         }
04763 
04771         function character_data($parser, $data){
04772                 $pos = $this->depth_array[$this->depth];
04773                 if ($this->xml_encoding=='UTF-8'){
04774                         // TODO: add an option to disable this for folks who want
04775                         // raw UTF-8 that, e.g., might not map to iso-8859-1
04776                         // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
04777                         if($this->decode_utf8){
04778                                 $data = utf8_decode($data);
04779                         }
04780                 }
04781         $this->message[$pos]['cdata'] .= $data;
04782         // for doclit
04783         if($this->status == 'header'){
04784                 $this->responseHeaders .= $data;
04785         } else {
04786                 $this->document .= $data;
04787         }
04788         }
04789 
04796         function get_response(){
04797                 return $this->soapresponse;
04798         }
04799 
04806         function getHeaders(){
04807             return $this->responseHeaders;
04808         }
04809 
04816         function decode_entities($text){
04817                 foreach($this->entities as $entity => $encoded){
04818                         $text = str_replace($encoded,$entity,$text);
04819                 }
04820                 return $text;
04821         }
04822 
04831         function decodeSimple($value, $type, $typens) {
04832                 // TODO: use the namespace!
04833                 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
04834                         return (string) $value;
04835                 }
04836                 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
04837                         return (int) $value;
04838                 }
04839                 if ($type == 'float' || $type == 'double' || $type == 'decimal') {
04840                         return (double) $value;
04841                 }
04842                 if ($type == 'boolean') {
04843                         if (strtolower($value) == 'false' || strtolower($value) == 'f') {
04844                                 return false;
04845                         }
04846                         return (boolean) $value;
04847                 }
04848                 if ($type == 'base64' || $type == 'base64Binary') {
04849                         return base64_decode($value);
04850                 }
04851                 // obscure numeric types
04852                 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
04853                         || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
04854                         || $type == 'unsignedInt'
04855                         || $type == 'unsignedShort' || $type == 'unsignedByte') {
04856                         return (int) $value;
04857                 }
04858                 // everything else
04859                 return (string) $value;
04860         }
04861 
04868         function buildVal($pos){
04869                 if(!isset($this->message[$pos]['type'])){
04870                         $this->message[$pos]['type'] = '';
04871                 }
04872                 $this->debug('inside buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
04873                 // if there are children...
04874                 if($this->message[$pos]['children'] != ''){
04875                         $children = explode('|',$this->message[$pos]['children']);
04876                         array_shift($children); // knock off empty
04877                         // md array
04878                         if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
04879                 $r=0; // rowcount
04880                 $c=0; // colcount
04881                 foreach($children as $child_pos){
04882                                         $this->debug("got an MD array element: $r, $c");
04883                                         $params[$r][] = $this->message[$child_pos]['result'];
04884                                     $c++;
04885                                     if($c == $this->message[$pos]['arrayCols']){
04886                                         $c = 0;
04887                                                 $r++;
04888                                     }
04889                 }
04890             // array
04891                         } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
04892                 $this->debug('adding array '.$this->message[$pos]['name']);
04893                 foreach($children as $child_pos){
04894                         $params[] = &$this->message[$child_pos]['result'];
04895                 }
04896             // apache Map type: java hashtable
04897             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
04898                 foreach($children as $child_pos){
04899                         $kv = explode("|",$this->message[$child_pos]['children']);
04900                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
04901                 }
04902             // generic compound type
04903             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
04904                     } else {
04905                         // Apache Vector type: treat as an array
04906                                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
04907                                         $notstruct = 1;
04908                                 } else {
04909                         // is array or struct?
04910                         foreach($children as $child_pos){
04911                                 if(isset($keys) && isset($keys[$this->message[$child_pos]['name']])){
04912                                         $notstruct = 1;
04913                                         break;
04914                                 }
04915                                 $keys[$this->message[$child_pos]['name']] = 1;
04916                         }
04917                     }
04918                 //
04919                 foreach($children as $child_pos){
04920                         if(isset($notstruct)){
04921                                 $params[] = &$this->message[$child_pos]['result'];
04922                         } else {
04923                                 if (isset($params[$this->message[$child_pos]['name']])) {
04924                                         // de-serialize repeated element name into an array
04925                                         if (!is_array($params[$this->message[$child_pos]['name']])) {
04926                                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
04927                                         }
04928                                         $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
04929                                 } else {
04930                                                 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
04931                                             }
04932                         }
04933                 }
04934                         }
04935                         return is_array($params) ? $params : array();
04936                 } else {
04937                 $this->debug('no children');
04938             if(strpos($this->message[$pos]['cdata'],'&')){
04939                         return  strtr($this->message[$pos]['cdata'],array_flip($this->entities));
04940             } else {
04941                 return $this->message[$pos]['cdata'];
04942             }
04943                 }
04944         }
04945 }
04946 
04947 
04948 
04949 ?><?php
04950 
04951 
04952 
04972 class soap_client extends nusoap_base  {
04973 
04974         var $username = '';
04975         var $password = '';
04976         var $authtype = '';
04977         var $requestHeaders = false;    // SOAP headers in request (text)
04978         var $responseHeaders = '';              // SOAP headers from response (incomplete namespace resolution) (text)
04979         var $document = '';                             // SOAP body response portion (incomplete namespace resolution) (text)
04980         var $endpoint;
04981         var $error_str = false;
04982     var $proxyhost = '';
04983     var $proxyport = '';
04984         var $proxyusername = '';
04985         var $proxypassword = '';
04986     var $xml_encoding = '';                     // character set encoding of incoming (response) messages
04987         var $http_encoding = false;
04988         var $timeout = 0;                               // HTTP connection timeout
04989         var $response_timeout = 30;             // HTTP response timeout
04990         var $endpointType = '';
04991         var $persistentConnection = false;
04992         var $defaultRpcParams = false;  // This is no longer used
04993         var $request = '';                              // HTTP request
04994         var $response = '';                             // HTTP response
04995         var $responseData = '';                 // SOAP payload of response
04996         // toggles whether the parser decodes element content w/ utf8_decode()
04997     var $decode_utf8 = true;
04998         
05008         var $fault, $faultcode, $faultstring, $faultdetail;
05009 
05024         function soap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
05025                 $this->endpoint = $endpoint;
05026                 $this->proxyhost = $proxyhost;
05027                 $this->proxyport = $proxyport;
05028                 $this->proxyusername = $proxyusername;
05029                 $this->proxypassword = $proxypassword;
05030                 $this->timeout = $timeout;
05031                 $this->response_timeout = $response_timeout;
05032 
05033                 // make values
05034                 if($wsdl){
05035                         $this->endpointType = 'wsdl';
05036                         if (is_object($endpoint) && is_a($endpoint, 'wsdl')) {
05037                                 $this->wsdl = $endpoint;
05038                                 $this->endpoint = $this->wsdl->wsdl;
05039                                 $this->wsdlFile = $this->endpoint;
05040                                 $this->debug('existing wsdl instance created from ' . $this->endpoint);
05041                         } else {
05042                                 $this->wsdlFile = $this->endpoint;
05043                                 
05044                                 // instantiate wsdl object and parse wsdl file
05045                                 $this->debug('instantiating wsdl class with doc: '.$endpoint);
05046                                 $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
05047                         }
05048                         $this->debug("wsdl debug...\n".$this->wsdl->debug_str);
05049                         $this->wsdl->debug_str = '';
05050                         // catch errors
05051                         if($errstr = $this->wsdl->getError()){
05052                                 $this->debug('got wsdl error: '.$errstr);
05053                                 $this->setError('wsdl error: '.$errstr);
05054                         } elseif($this->operations = $this->wsdl->getOperations()){
05055                                 $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
05056                         } else {
05057                                 $this->debug( 'getOperations returned false');
05058                                 $this->setError('no operations defined in the WSDL document!');
05059                         }
05060                 }
05061         }
05062 
05088         function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
05089                 $this->operation = $operation;
05090                 $this->fault = false;
05091                 $this->error_str = '';
05092                 $this->request = '';
05093                 $this->response = '';
05094                 $this->responseData = '';
05095                 $this->faultstring = '';
05096                 $this->faultcode = '';
05097                 $this->opData = array();
05098                 
05099                 $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $style, $use; endpointType: $this->endpointType");
05100                 if ($headers) {
05101                         $this->requestHeaders = $headers;
05102                 }
05103                 // serialize parameters
05104                 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
05105                         // use WSDL for operation
05106                         $this->opData = $opData;
05107                         foreach($opData as $key => $value){
05108                                 $this->debug("$key -> $value");
05109                         }
05110                         if (isset($opData['soapAction'])) {
05111                                 $soapAction = $opData['soapAction'];
05112                         }
05113                         $this->endpoint = $opData['endpoint'];
05114                         $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     ($namespace != '' ? $namespace : 'http://testuri.org');
05115                         $style = $opData['style'];
05116                         $use = $opData['input']['use'];
05117                         // add ns to ns array
05118                         if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
05119                                 $this->wsdl->namespaces['nu'] = $namespace;
05120             }
05121             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
05122                         // serialize payload
05123                         if (is_string($params)) {
05124                                 $this->debug("serializing param string for WSDL operation $operation");
05125                                 $payload = $params;
05126                         } elseif (is_array($params)) {
05127                                 $this->debug("serializing param array for WSDL operation $operation");
05128                                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
05129                         } else {
05130                                 $this->debug('params must be array or string');
05131                                 $this->setError('params must be array or string');
05132                                 return false;
05133                         }
05134             $usedNamespaces = $this->wsdl->usedNamespaces;
05135                         // Partial fix for multiple encoding styles in the same function call
05136                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
05137                         if (isset($opData['output']['encodingStyle']) && $encodingStyle != $opData['output']['encodingStyle']) {
05138                                 $methodEncodingStyle = ' SOAP-ENV:encodingStyle="' . $opData['output']['encodingStyle'] . '"';
05139                         } else {
05140                                 $methodEncodingStyle = '';
05141                         }
05142                         $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
05143                         $this->wsdl->debug_str = '';
05144                         if ($errstr = $this->wsdl->getError()) {
05145                                 $this->debug('got wsdl error: '.$errstr);
05146                                 $this->setError('wsdl error: '.$errstr);
05147                                 return false;
05148                         }
05149                 } elseif($this->endpointType == 'wsdl') {
05150                         // operation not in WSDL
05151                         $this->setError( 'operation '.$operation.' not present.');
05152                         $this->debug("operation '$operation' not present.");
05153                         $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
05154                         $this->wsdl->debug_str = '';
05155                         return false;
05156                 } else {
05157                         // no WSDL
05158             if($namespace == ''){
05159                 $namespace = 'http://testuri.org';
05160             }
05161                         //$this->namespaces['ns1'] = $namespace;
05162                         $nsPrefix = 'ns1';
05163                         // serialize 
05164                         $payload = '';
05165                         if (is_string($params)) {
05166                                 $this->debug("serializing param string for operation $operation");
05167                                 $payload = $params;
05168                         } elseif (is_array($params)) {
05169                                 $this->debug("serializing param array for operation $operation");
05170                                 foreach($params as $k => $v){
05171                                         $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
05172                                 }
05173                         } else {
05174                                 $this->debug('params must be array or string');
05175                                 $this->setError('params must be array or string');
05176                                 return false;
05177                         }
05178                         $usedNamespaces = array();
05179                         $methodEncodingStyle = '';
05180                 }
05181                 // wrap RPC calls with method element
05182                 if ($style == 'rpc') {
05183                         if ($use == 'literal') {
05184                                 $this->debug("wrapping RPC request with literal method element");
05185                                 $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>";
05186                         } else {
05187                                 $this->debug("wrapping RPC request with encoded method element");
05188                                 $payload = "<$nsPrefix:$operation$methodEncodingStyle xmlns:$nsPrefix=\"$namespace\">" .
05189                                                         $payload .
05190                                                         "</$nsPrefix:$operation>";
05191                         }
05192                 }
05193                 // serialize envelope
05194                 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use);
05195                 $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace, style: $style, use: $use");
05196                 $this->debug('SOAP message length: ' . strlen($soapmsg) . ' contents: ' . substr($soapmsg, 0, 1000));
05197                 // send
05198                 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
05199                 if($errstr = $this->getError()){
05200                         $this->debug('Error: '.$errstr);
05201                         return false;
05202                 } else {
05203                         $this->return = $return;
05204                         $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
05205                         
05206                         // fault?
05207                         if(is_array($return) && isset($return['faultcode'])){
05208                                 $this->debug('got fault');
05209                                 $this->setError($return['faultcode'].': '.$return['faultstring']);
05210                                 $this->fault = true;
05211                                 foreach($return as $k => $v){
05212                                         $this->$k = $v;
05213                                         $this->debug("$k = $v<br>");
05214                                 }
05215                                 return $return;
05216                         } else {
05217                                 // array of return values
05218                                 if(is_array($return)){
05219                                         // multiple 'out' parameters
05220                                         if(sizeof($return) > 1){
05221                                                 return $return;
05222                                         }
05223                                         // single 'out' parameter
05224                                         return array_shift($return);
05225                                 // nothing returned (ie, echoVoid)
05226                                 } else {
05227                                         return "";
05228                                 }
05229                         }
05230                 }
05231         }
05232 
05240         function getOperationData($operation){
05241                 if(isset($this->operations[$operation])){
05242                         return $this->operations[$operation];
05243                 }
05244                 $this->debug("No data for operation: $operation");
05245         }
05246 
05261         function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
05262                 // detect transport
05263                 switch(true){
05264                         // http(s)
05265                         case ereg('^http',$this->endpoint):
05266                                 $this->debug('transporting via HTTP');
05267                                 if($this->persistentConnection == true && is_object($this->persistentConnection)){
05268                                         $http =& $this->persistentConnection;
05269                                 } else {
05270                                         $http = new soap_transport_http($this->endpoint);
05271                                         if ($this->persistentConnection) {
05272                                                 $http->usePersistentConnection();
05273                                         }
05274                                 }
05275                                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
05276                                 $http->setSOAPAction($soapaction);
05277                                 if($this->proxyhost && $this->proxyport){
05278                                         $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
05279                                 }
05280                 if($this->username != '' && $this->password != '') {
05281                                         $http->setCredentials($this->username, $this->password, $this->authtype);
05282                                 }
05283                                 if($this->http_encoding != ''){
05284                                         $http->setEncoding($this->http_encoding);
05285                                 }
05286                                 $this->debug('sending message, length: '.strlen($msg));
05287                                 if(ereg('^http:',$this->endpoint)){
05288                                 //if(strpos($this->endpoint,'http:')){
05289                                         $this->responseData = $http->send($msg,$timeout,$response_timeout);
05290                                 } elseif(ereg('^https',$this->endpoint)){
05291                                 //} elseif(strpos($this->endpoint,'https:')){
05292                                         //if(phpversion() == '4.3.0-dev'){
05293                                                 //$response = $http->send($msg,$timeout,$response_timeout);
05294                                 //$this->request = $http->outgoing_payload;
05295                                                 //$this->response = $http->incoming_payload;
05296                                         //} else
05297                                         if (extension_loaded('curl')) {
05298                                                 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout);
05299                                         } else {
05300                                                 $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
05301                                         }                                                               
05302                                 } else {
05303                                         $this->setError('no http/s in endpoint url');
05304                                 }
05305                                 $this->request = $http->outgoing_payload;
05306                                 $this->response = $http->incoming_payload;
05307                                 $this->debug("transport debug data...\n".$http->debug_str);
05308                                 
05309                                 // save transport object if using persistent connections
05310                                 if ($this->persistentConnection) {
05311                                         $http->debug_str = '';
05312                                         if (!is_object($this->persistentConnection)) {
05313                                                 $this->persistentConnection = $http;
05314                                         }
05315                                 }
05316                                 
05317                                 if($err = $http->getError()){
05318                                         $this->setError('HTTP Error: '.$err);
05319                                         return false;
05320                                 } elseif($this->getError()){
05321                                         return false;
05322                                 } else {
05323                                         $this->debug('got response, length: '. strlen($this->responseData).' type: '.$http->incoming_headers['content-type']);
05324                                         return $this->parseResponse($http->incoming_headers, $this->responseData);
05325                                 }
05326                         break;
05327                         default:
05328                                 $this->setError('no transport found, or selected transport is not yet supported!');
05329                         return false;
05330                         break;
05331                 }
05332         }
05333 
05342     function parseResponse($headers, $data) {
05343                 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
05344                 if (!strstr($headers['content-type'], 'text/xml')) {
05345                         $this->setError('Response not of type text/xml');
05346                         return false;
05347                 }
05348                 if (strpos($headers['content-type'], '=')) {
05349                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
05350                         $this->debug('Got response encoding: ' . $enc);
05351                         if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
05352                                 $this->xml_encoding = strtoupper($enc);
05353                         } else {
05354                                 $this->xml_encoding = 'US-ASCII';
05355                         }
05356                 } else {
05357                         // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
05358                         $this->xml_encoding = 'UTF-8';
05359                 }
05360                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
05361                 $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
05362                 // add parser debug data to our debug
05363                 $this->debug($parser->debug_str);
05364                 // if parse errors
05365                 if($errstr = $parser->getError()){
05366                         $this->setError( $errstr);
05367                         // destroy the parser object
05368                         unset($parser);
05369                         return false;
05370                 } else {
05371                         // get SOAP headers
05372                         $this->responseHeaders = $parser->getHeaders();
05373                         // get decoded message
05374                         $return = $parser->get_response();
05375             // add document for doclit support
05376             $this->document = $parser->document;
05377                         // destroy the parser object
05378                         unset($parser);
05379                         // return decode message
05380                         return $return;
05381                 }
05382          }
05383 
05390         function setHeaders($headers){
05391                 $this->requestHeaders = $headers;
05392         }
05393 
05400         function getHeaders(){
05401             if($this->responseHeaders != '') {
05402                         return $this->responseHeaders;
05403             }
05404         }
05405 
05415         function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
05416                 $this->proxyhost = $proxyhost;
05417                 $this->proxyport = $proxyport;
05418                 $this->proxyusername = $proxyusername;
05419                 $this->proxypassword = $proxypassword;
05420         }
05421 
05430         function setCredentials($username, $password, $authtype = 'basic') {
05431                 $this->username = $username;
05432                 $this->password = $password;
05433                 $this->authtype = $authtype;
05434         }
05435         
05442         function setHTTPEncoding($enc='gzip, deflate'){
05443                 $this->http_encoding = $enc;
05444         }
05445         
05451         function useHTTPPersistentConnection(){
05452                 $this->persistentConnection = true;
05453         }
05454         
05465         function getDefaultRpcParams() {
05466                 return $this->defaultRpcParams;
05467         }
05468 
05477         function setDefaultRpcParams($rpcParams) {
05478                 $this->defaultRpcParams = $rpcParams;
05479         }
05480         
05487         function getProxy(){
05488                 $evalStr = '';
05489                 foreach($this->operations as $operation => $opData){
05490                         if($operation != ''){
05491                                 // create param string
05492                                 $paramStr = '';
05493                                 if(sizeof($opData['input']['parts']) > 0){
05494                                         foreach($opData['input']['parts'] as $name => $type){
05495                                                 $paramStr .= "\$$name,";
05496                                         }
05497                                         $paramStr = substr($paramStr,0,strlen($paramStr)-1);
05498                                 }
05499                                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
05500                                 $evalStr .= "function $operation ($paramStr){
05501                                         // load params into array
05502                                         \$params = array($paramStr);
05503                                         return \$this->call('$operation',\$params,'".$opData['namespace']."','".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
05504                                 }";
05505                                 unset($paramStr);
05506                         }
05507                 }
05508                 $r = rand();
05509                 $evalStr = 'class soap_proxy_'.$r.' extends soap_client {
05510                                 '.$evalStr.'
05511                         }';
05512                 //print "proxy class:<pre>$evalStr</pre>";
05513                 // eval the class
05514                 eval($evalStr);
05515                 // instantiate proxy object
05516                 eval("\$proxy = new soap_proxy_$r('');");
05517                 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
05518                 $proxy->endpointType = 'wsdl';
05519                 $proxy->wsdlFile = $this->wsdlFile;
05520                 $proxy->wsdl = $this->wsdl;
05521                 $proxy->operations = $this->operations;
05522                 $proxy->defaultRpcParams = $this->defaultRpcParams;
05523                 // transfer other state
05524                 $proxy->username = $this->username;
05525                 $proxy->password = $this->password;
05526                 $proxy->proxyhost = $this->proxyhost;
05527                 $proxy->proxyport = $this->proxyport;
05528                 $proxy->proxyusername = $this->proxyusername;
05529                 $proxy->proxypassword = $this->proxypassword;
05530                 $proxy->timeout = $this->timeout;
05531                 $proxy->response_timeout = $this->response_timeout;
05532                 $proxy->http_encoding = $this->http_encoding;
05533                 $proxy->persistentConnection = $this->persistentConnection;
05534                 return $proxy;
05535         }
05536 
05544         function getHTTPBody($soapmsg) {
05545                 return $soapmsg;
05546         }
05547         
05556         function getHTTPContentType() {
05557                 return 'text/xml';
05558         }
05559         
05569         function getHTTPContentTypeCharset() {
05570                 return $this->soap_defencoding;
05571         }
05572 
05573         /*
05574         * whether or not parser should decode utf8 element content
05575     *
05576     * @return   always returns true
05577     * @access   public
05578     */
05579     function decodeUTF8($bool){
05580                 $this->decode_utf8 = $bool;
05581                 return true;
05582     }
05583 }
05584 ?>

Generated on Fri Dec 13 2013 08:00:20 for ILIAS Release_3_3_x_branch .rev 46803 by  doxygen 1.7.1