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

Services/SOAPAuth/include/nusoap.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004 $Id: nusoap.php 11808 2006-08-08 09:57:04Z akill $
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: 11808 $';
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 
02313 class soap_server extends nusoap_base {
02314         var $headers = array();                 // HTTP headers of request
02315         var $request = '';                              // HTTP request
02316         var $requestHeaders = '';               // SOAP headers from request (incomplete namespace resolution) (text)
02317         var $document = '';                             // SOAP body request portion (incomplete namespace resolution) (text)
02318         var $requestSOAP = '';                  // SOAP payload for request (text)
02319         var $methodURI = '';                    // requested method namespace URI
02320         var $methodname = '';                   // name of method requested
02321         var $methodparams = array();    // method parameters from request
02322         var $xml_encoding = '';                 // character set encoding of incoming (request) messages
02323         var $SOAPAction = '';                   // SOAP Action from request
02324 
02325         var $outgoing_headers = array();// HTTP headers of response
02326         var $response = '';                             // HTTP response
02327         var $responseHeaders = '';              // SOAP headers for response (text)
02328         var $responseSOAP = '';                 // SOAP payload for response (text)
02329         var $methodreturn = false;              // method return to place in response
02330         var $methodreturnisliteralxml = false;  // whether $methodreturn is a string of literal XML
02331         var $fault = false;                             // SOAP fault for response
02332         var $result = 'successful';             // text indication of result (for debugging)
02333 
02334         var $operations = array();              // assoc array of operations => opData
02335         var $wsdl = false;                              // wsdl instance
02336         var $externalWSDLURL = false;   // URL for WSDL
02337         var $debug_flag = false;                // whether to append debug to response as XML comment
02338         
02346         function soap_server($wsdl=false){
02347 
02348                 // turn on debugging?
02349                 global $debug;
02350                 global $_REQUEST;
02351                 global $_SERVER;
02352                 global $HTTP_SERVER_VARS;
02353 
02354                 if (isset($debug)) {
02355                         $this->debug_flag = $debug;
02356                 } else if (isset($_REQUEST['debug'])) {
02357                         $this->debug_flag = $_REQUEST['debug'];
02358                 } else if (isset($_SERVER['QUERY_STRING'])) {
02359                         $qs = explode('&', $_SERVER['QUERY_STRING']);
02360                         foreach ($qs as $v) {
02361                                 if (substr($v, 0, 6) == 'debug=') {
02362                                         $this->debug_flag = substr($v, 6);
02363                                 }
02364                         }
02365                 } else if (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
02366                         $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
02367                         foreach ($qs as $v) {
02368                                 if (substr($v, 0, 6) == 'debug=') {
02369                                         $this->debug_flag = substr($v, 6);
02370                                 }
02371                         }
02372                 }
02373 
02374                 // wsdl
02375                 if($wsdl){
02376                         if (is_object($wsdl) && is_a($wsdl, 'wsdl')) {
02377                                 $this->wsdl = $wsdl;
02378                                 $this->externalWSDLURL = $this->wsdl->wsdl;
02379                                 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
02380                         } else {
02381                                 $this->debug('Create wsdl from ' . $wsdl);
02382                                 $this->wsdl = new wsdl($wsdl);
02383                                 $this->externalWSDLURL = $wsdl;
02384                         }
02385                         $this->debug("wsdl...\n" . $this->wsdl->debug_str);
02386                         $this->wsdl->debug_str = '';
02387                         if($err = $this->wsdl->getError()){
02388                                 die('WSDL ERROR: '.$err);
02389                         }
02390                 }
02391         }
02392 
02399         function service($data){
02400                 global $QUERY_STRING;
02401                 if(isset($_SERVER['QUERY_STRING'])){
02402                         $qs = $_SERVER['QUERY_STRING'];
02403                 } elseif(isset($GLOBALS['QUERY_STRING'])){
02404                         $qs = $GLOBALS['QUERY_STRING'];
02405  } elseif(isset($QUERY_STRING) && $QUERY_STRING != ''){
02406                         $qs = $QUERY_STRING;
02407                 }
02408 
02409                 if(isset($qs) && ereg('wsdl', $qs) ){
02410                         // This is a request for WSDL
02411                         if($this->externalWSDLURL){
02412               if (strpos($this->externalWSDLURL,"://")!==false) { // assume URL
02413                                 header('Location: '.$this->externalWSDLURL);
02414               } else { // assume file
02415                 header("Content-Type: text/xml\r\n");
02416                 $fp = fopen($this->externalWSDLURL, 'r');
02417                 fpassthru($fp);
02418               }
02419                         } else {
02420                                 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
02421                                 print $this->wsdl->serialize();
02422                         }
02423                 } elseif($data == '' && $this->wsdl){
02424                         // print web interface
02425                         print $this->webDescription();
02426                 } else {
02427                         // handle the request
02428                         $this->parse_request($data);
02429                         if (! $this->fault) {
02430                                 $this->invoke_method();
02431                         }
02432                         if (! $this->fault) {
02433                                 $this->serialize_return();
02434                         }
02435                         $this->send_response();
02436                 }
02437         }
02438 
02451         function parse_http_headers() {
02452                 global $HTTP_SERVER_VARS;
02453                 global $_SERVER;
02454 
02455                 $this->request = '';
02456                 if(function_exists('getallheaders')){
02457                         $this->headers = getallheaders();
02458                         foreach($this->headers as $k=>$v){
02459                                 $this->request .= "$k: $v\r\n";
02460                                 $this->debug("$k: $v");
02461                         }
02462                         // get SOAPAction header
02463                         if(isset($this->headers['SOAPAction'])){
02464                                 $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']);
02465                         }
02466                         // get the character encoding of the incoming request
02467                         if(strpos($this->headers['Content-Type'],'=')){
02468                                 $enc = str_replace('"','',substr(strstr($this->headers["Content-Type"],'='),1));
02469                                 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
02470                                         $this->xml_encoding = strtoupper($enc);
02471                                 } else {
02472                                         $this->xml_encoding = 'US-ASCII';
02473                                 }
02474                         } else {
02475                                 // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
02476                                 $this->xml_encoding = 'UTF-8';
02477                         }
02478                 } elseif(isset($_SERVER) && is_array($_SERVER)){
02479                         foreach ($_SERVER as $k => $v) {
02480                                 if (substr($k, 0, 5) == 'HTTP_') {
02481                                         $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
02482                                 } else {
02483                                         $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $k))));
02484                                 }
02485                                 if ($k == 'Soapaction') {
02486                                         // get SOAPAction header
02487                                         $k = 'SOAPAction';
02488                                         $v = str_replace('"', '', $v);
02489                                         $v = str_replace('\\', '', $v);
02490                                         $this->SOAPAction = $v;
02491                                 } else if ($k == 'Content-Type') {
02492                                         // get the character encoding of the incoming request
02493                                         if (strpos($v, '=')) {
02494                                                 $enc = substr(strstr($v, '='), 1);
02495                                                 $enc = str_replace('"', '', $enc);
02496                                                 $enc = str_replace('\\', '', $enc);
02497                                                 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
02498                                                         $this->xml_encoding = strtoupper($enc);
02499                                                 } else {
02500                                                         $this->xml_encoding = 'US-ASCII';
02501                                                 }
02502                                         } else {
02503                                                 // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
02504                                                 $this->xml_encoding = 'UTF-8';
02505                                         }
02506                                 }
02507                                 $this->headers[$k] = $v;
02508                                 $this->request .= "$k: $v\r\n";
02509                                 $this->debug("$k: $v");
02510                         }
02511                 } elseif (is_array($HTTP_SERVER_VARS)) {
02512                         foreach ($HTTP_SERVER_VARS as $k => $v) {
02513                                 if (substr($k, 0, 5) == 'HTTP_') {
02514                                         $k = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($k, 5)))));
02515                                         if ($k == 'Soapaction') {
02516                                                 // get SOAPAction header
02517                                                 $k = 'SOAPAction';
02518                                                 $v = str_replace('"', '', $v);
02519                                                 $v = str_replace('\\', '', $v);
02520                                                 $this->SOAPAction = $v;
02521                                         } else if ($k == 'Content-Type') {
02522                                                 // get the character encoding of the incoming request
02523                                                 if (strpos($v, '=')) {
02524                                                         $enc = substr(strstr($v, '='), 1);
02525                                                         $enc = str_replace('"', '', $enc);
02526                                                         $enc = str_replace('\\', '', $enc);
02527                                                         if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) {
02528                                                                 $this->xml_encoding = strtoupper($enc);
02529                                                         } else {
02530                                                                 $this->xml_encoding = 'US-ASCII';
02531                                                         }
02532                                                 } else {
02533                                                         // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
02534                                                         $this->xml_encoding = 'UTF-8';
02535                                                 }
02536                                         }
02537                                         $this->headers[$k] = $v;
02538                                         $this->request .= "$k: $v\r\n";
02539                                         $this->debug("$k: $v");
02540                                 }
02541                         }
02542                 }
02543         }
02544 
02567         function parse_request($data='') {
02568                 $this->debug('entering parse_request() on '.date('H:i Y-m-d'));
02569                 $this->parse_http_headers();
02570                 $this->debug('got character encoding: '.$this->xml_encoding);
02571                 // uncompress if necessary
02572                 if (isset($this->headers['Content-Encoding']) && $this->headers['Content-Encoding'] != '') {
02573                         $this->debug('got content encoding: ' . $this->headers['Content-Encoding']);
02574                         if ($this->headers['Content-Encoding'] == 'deflate' || $this->headers['Content-Encoding'] == 'gzip') {
02575                         // if decoding works, use it. else assume data wasn't gzencoded
02576                                 if (function_exists('gzuncompress')) {
02577                                         if ($this->headers['Content-Encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
02578                                                 $data = $degzdata;
02579                                         } elseif ($this->headers['Content-Encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
02580                                                 $data = $degzdata;
02581                                         } else {
02582                                                 $this->fault('Server', 'Errors occurred when trying to decode the data');
02583                                                 return;
02584                                         }
02585                                 } else {
02586                                         $this->fault('Server', 'This Server does not support compressed data');
02587                                         return;
02588                                 }
02589                         }
02590                 }
02591                 $this->request .= "\r\n".$data;
02592                 $this->requestSOAP = $data;
02593                 // parse response, get soap parser obj
02594                 $parser = new soap_parser($data,$this->xml_encoding);
02595                 // parser debug
02596                 $this->debug("parser debug: \n".$parser->debug_str);
02597                 // if fault occurred during message parsing
02598                 if($err = $parser->getError()){
02599                         $this->result = 'fault: error in msg parsing: '.$err;
02600                         $this->fault('Server',"error in msg parsing:\n".$err);
02601                 // else successfully parsed request into soapval object
02602                 } else {
02603                         // get/set methodname
02604                         $this->methodURI = $parser->root_struct_namespace;
02605                         $this->methodname = $parser->root_struct_name;
02606                         $this->debug('method name: '.$this->methodname);
02607                         $this->debug('calling parser->get_response()');
02608                         $this->methodparams = $parser->get_response();
02609                         // get SOAP headers
02610                         $this->requestHeaders = $parser->getHeaders();
02611             // add document for doclit support
02612             $this->document = $parser->document;
02613                 }
02614                 $this->debug('leaving parse_request() on '.date('H:i Y-m-d'));
02615         }
02616 
02634         function invoke_method() {
02635                 $this->debug('entering invoke_method');
02636                 // does method exist?
02637                 if(!function_exists($this->methodname)){
02638                         // "method not found" fault here
02639                         $this->debug("method '$this->methodname' not found!");
02640                         $this->result = 'fault: method not found';
02641                         $this->fault('Server',"method '$this->methodname' not defined in service");
02642                         return;
02643                 }
02644                 if($this->wsdl){
02645                         if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){
02646                         //if(
02647                         $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service");
02648                                 return;
02649                     }
02650                     $this->debug('opData is ' . $this->varDump($this->opData));
02651                 }
02652                 $this->debug("method '$this->methodname' exists");
02653                 // evaluate message, getting back parameters
02654                 // verify that request parameters match the method's signature
02655                 if(! $this->verify_method($this->methodname,$this->methodparams)){
02656                         // debug
02657                         $this->debug('ERROR: request not verified against method signature');
02658                         $this->result = 'fault: request failed validation against method signature';
02659                         // return fault
02660                         $this->fault('Server',"Operation '$this->methodname' not defined in service.");
02661                         return;
02662                 }
02663 
02664                 // if there are parameters to pass
02665         $this->debug('params var dump '.$this->varDump($this->methodparams));
02666                 if($this->methodparams){
02667                         $this->debug("calling '$this->methodname' with params");
02668                         if (! function_exists('call_user_func_array')) {
02669                                 $this->debug('calling method using eval()');
02670                                 $funcCall = $this->methodname.'(';
02671                                 foreach($this->methodparams as $param) {
02672                                         $funcCall .= "\"$param\",";
02673                                 }
02674                                 $funcCall = substr($funcCall, 0, -1).')';
02675                                 $this->debug('function call:<br>'.$funcCall);
02676                                 @eval("\$this->methodreturn = $funcCall;");
02677                         } else {
02678                                 $this->debug('calling method using call_user_func_array()');
02679                                 $this->methodreturn = call_user_func_array("$this->methodname",$this->methodparams);
02680                         }
02681                 } else {
02682                         // call method w/ no parameters
02683                         $this->debug("calling $this->methodname w/ no params");
02684                         $m = $this->methodname;
02685                         $this->methodreturn = @$m();
02686                 }
02687         $this->debug('methodreturn var dump'.$this->varDump($this->methodreturn));
02688                 $this->debug("leaving invoke_method: called method $this->methodname, received $this->methodreturn of type ".gettype($this->methodreturn));
02689         }
02690 
02702         function serialize_return() {
02703                 $this->debug("Entering serialize_return");
02704                 // if we got nothing back. this might be ok (echoVoid)
02705                 if(isset($this->methodreturn) && ($this->methodreturn != '' || is_bool($this->methodreturn))) {
02706                         // if fault
02707                         if(get_class($this->methodreturn) == 'soap_fault'){
02708                                 $this->debug('got a fault object from method');
02709                                 $this->fault = $this->methodreturn;
02710                                 return;
02711                         } elseif ($this->methodreturnisliteralxml) {
02712                                 $return_val = $this->methodreturn;
02713                         // returned value(s)
02714                         } else {
02715                                 $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
02716                                 $this->debug('serializing return value');
02717                                 if($this->wsdl){
02718                                         // weak attempt at supporting multiple output params
02719                                         if(sizeof($this->opData['output']['parts']) > 1){
02720                                         $opParams = $this->methodreturn;
02721                                     } else {
02722                                         // TODO: is this really necessary?
02723                                         $opParams = array($this->methodreturn);
02724                                     }
02725                                     $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
02726                                         if($errstr = $this->wsdl->getError()){
02727                                                 $this->debug('got wsdl error: '.$errstr);
02728                                                 $this->fault('Server', 'got wsdl error: '.$errstr);
02729                                                 return;
02730                                         }
02731                                 } else {
02732                                     $return_val = $this->serialize_val($this->methodreturn, 'return');
02733                                 }
02734                         }
02735                         $this->debug('return val: '.$this->varDump($return_val));
02736                 } else {
02737                         $return_val = '';
02738                         $this->debug('got no response from method');
02739                 }
02740                 $this->debug('serializing response');
02741                 if ($this->wsdl) {
02742                         if ($this->opData['style'] == 'rpc') {
02743                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
02744                         } else {
02745                                 $payload = $return_val;
02746                         }
02747                 } else {
02748                         $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
02749                 }
02750                 $this->result = 'successful';
02751                 if($this->wsdl){
02752                         //if($this->debug_flag){
02753                 $this->debug("WSDL debug data:\n".$this->wsdl->debug_str);
02754             //  }
02755                         // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
02756                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style']);
02757                 } else {
02758                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
02759                 }
02760                 $this->debug("Leaving serialize_return");
02761         }
02762 
02773         function send_response() {
02774                 $this->debug('Enter send_response');
02775                 if ($this->fault) {
02776                         $payload = $this->fault->serialize();
02777                         $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
02778                         $this->outgoing_headers[] = "Status: 500 Internal Server Error";
02779                 } else {
02780                         $payload = $this->responseSOAP;
02781                         // Some combinations of PHP+Web server allow the Status
02782                         // to come through as a header.  Since OK is the default
02783                         // just do nothing.
02784                         // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
02785                         // $this->outgoing_headers[] = "Status: 200 OK";
02786                 }
02787         // add debug data if in debug mode
02788                 if(isset($this->debug_flag) && $this->debug_flag){
02789                         while (strpos($this->debug_str, '--')) {
02790                                 $this->debug_str = str_replace('--', '- -', $this->debug_str);
02791                         }
02792                 $payload .= "<!--\n" . $this->debug_str . "\n-->";
02793         }
02794                 $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
02795                 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev);
02796                 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
02797                 // Let the Web server decide about this
02798                 //$this->outgoing_headers[] = "Connection: Close\r\n";
02799                 $this->outgoing_headers[] = "Content-Type: text/xml; charset=$this->soap_defencoding";
02800                 //begin code to compress payload - by John
02801                 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['Accept-Encoding'])) {     
02802                    if (strstr($this->headers['Accept-Encoding'], 'deflate')) {
02803                                 if (function_exists('gzcompress')) {
02804                                         if (isset($this->debug_flag) && $this->debug_flag) {
02805                                                 $payload .= "<!-- Content being deflated -->";
02806                                         }
02807                                         $this->outgoing_headers[] = "Content-Encoding: deflate";
02808                                         $payload = gzcompress($payload);
02809                                 } else {
02810                                         if (isset($this->debug_flag) && $this->debug_flag) {
02811                                                 $payload .= "<!-- Content will not be deflated: no gzcompress -->";
02812                                         }
02813                                 }
02814                    } else if (strstr($this->headers['Accept-Encoding'], 'gzip')) {
02815                                 if (function_exists('gzencode')) {
02816                                         if (isset($this->debug_flag) && $this->debug_flag) {
02817                                                 $payload .= "<!-- Content being gzipped -->";
02818                                         }
02819                                         $this->outgoing_headers[] = "Content-Encoding: gzip";
02820                                         $payload = gzencode($payload);
02821                                 } else {
02822                                         if (isset($this->debug_flag) && $this->debug_flag) {
02823                                                 $payload .= "<!-- Content will not be gzipped: no gzencode -->";
02824                                         }
02825                                 }
02826                         }
02827                 }
02828                 //end code
02829                 $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
02830                 reset($this->outgoing_headers);
02831                 foreach($this->outgoing_headers as $hdr){
02832                         header($hdr, false);
02833                 }
02834                 $this->response = join("\r\n",$this->outgoing_headers)."\r\n".$payload;
02835                 print $payload;
02836         }
02837 
02846         function verify_method($operation,$request){
02847                 if(isset($this->wsdl) && is_object($this->wsdl)){
02848                         if($this->wsdl->getOperationData($operation)){
02849                                 return true;
02850                         }
02851             } elseif(isset($this->operations[$operation])){
02852                         return true;
02853                 }
02854                 return false;
02855         }
02856 
02865         function add_to_map($methodname,$in,$out){
02866                         $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
02867         }
02868 
02882         function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false,$use=false,$documentation=''){
02883                 if($this->externalWSDLURL){
02884                         die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
02885                 }
02886             if(false == $in) {
02887                 }
02888                 if(false == $out) {
02889                 }
02890                 if(false == $namespace) {
02891                 }
02892                 if(false == $soapaction) {
02893                         $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
02894                         $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
02895                         $soapaction = "http://$SERVER_NAME$SCRIPT_NAME/$name";
02896                 }
02897                 if(false == $style) {
02898                         $style = "rpc";
02899                 }
02900                 if(false == $use) {
02901                         $use = "encoded";
02902                 }
02903                 
02904                 $this->operations[$name] = array(
02905             'name' => $name,
02906             'in' => $in,
02907             'out' => $out,
02908             'namespace' => $namespace,
02909             'soapaction' => $soapaction,
02910             'style' => $style);
02911         if($this->wsdl){
02912                 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation);
02913             }
02914                 return true;
02915         }
02916 
02926         function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
02927                 $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
02928         }
02929 
02935     function webDescription(){
02936                 $b = '
02937                 <html><head><title>NuSOAP: '.$this->wsdl->serviceName.'</title>
02938                 <style type="text/css">
02939                     body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
02940                     p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
02941                     pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
02942                     ul      { margin-top: 10px; margin-left: 20px; }
02943                     li      { list-style-type: none; margin-top: 10px; color: #000000; }
02944                     .content{
02945                         margin-left: 0px; padding-bottom: 2em; }
02946                     .nav {
02947                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
02948                         margin-top: 10px; margin-left: 0px; color: #000000;
02949                         background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
02950                     .title {
02951                         font-family: arial; font-size: 26px; color: #ffffff;
02952                         background-color: #999999; width: 105%; margin-left: 0px;
02953                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
02954                     .hidden {
02955                         position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
02956                         font-family: arial; overflow: hidden; width: 600;
02957                         padding: 20px; font-size: 10px; background-color: #999999;
02958                         layer-background-color:#FFFFFF; }
02959                     a,a:active  { color: charcoal; font-weight: bold; }
02960                     a:visited   { color: #666666; font-weight: bold; }
02961                     a:hover     { color: cc3300; font-weight: bold; }
02962                 </style>
02963                 <script language="JavaScript" type="text/javascript">
02964                 <!--
02965                 // POP-UP CAPTIONS...
02966                 function lib_bwcheck(){ //Browsercheck (needed)
02967                     this.ver=navigator.appVersion
02968                     this.agent=navigator.userAgent
02969                     this.dom=document.getElementById?1:0
02970                     this.opera5=this.agent.indexOf("Opera 5")>-1
02971                     this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
02972                     this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
02973                     this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
02974                     this.ie=this.ie4||this.ie5||this.ie6
02975                     this.mac=this.agent.indexOf("Mac")>-1
02976                     this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
02977                     this.ns4=(document.layers && !this.dom)?1:0;
02978                     this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
02979                     return this
02980                 }
02981                 var bw = new lib_bwcheck()
02982                 //Makes crossbrowser object.
02983                 function makeObj(obj){
02984                     this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
02985                     if(!this.evnt) return false
02986                     this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
02987                     this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
02988                     this.writeIt=b_writeIt;
02989                     return this
02990                 }
02991                 // A unit of measure that will be added when setting the position of a layer.
02992                 //var px = bw.ns4||window.opera?"":"px";
02993                 function b_writeIt(text){
02994                     if (bw.ns4){this.wref.write(text);this.wref.close()}
02995                     else this.wref.innerHTML = text
02996                 }
02997                 //Shows the messages
02998                 var oDesc;
02999                 function popup(divid){
03000                     if(oDesc = new makeObj(divid)){
03001                         oDesc.css.visibility = "visible"
03002                     }
03003                 }
03004                 function popout(){ // Hides message
03005                     if(oDesc) oDesc.css.visibility = "hidden"
03006                 }
03007                 //-->
03008                 </script>
03009                 </head>
03010                 <body>
03011                 <div class=content>
03012                         <br><br>
03013                         <div class=title>'.$this->wsdl->serviceName.'</div>
03014                         <div class=nav>
03015                                 <p>View the <a href="'.(isset($GLOBALS['PHP_SELF']) ? $GLOBALS['PHP_SELF'] : $_SERVER['PHP_SELF']).'?wsdl">WSDL</a> for the service.
03016                                 Click on an operation name to view it&apos;s details.</p>
03017                                 <ul>';
03018                                 foreach($this->wsdl->getOperations() as $op => $data){
03019                                     $b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>";
03020                                     // create hidden div
03021                                     $b .= "<div id='$op' class='hidden'>
03022                                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
03023                                     foreach($data as $donnie => $marie){ // loop through opdata
03024                                                 if($donnie == 'input' || $donnie == 'output'){ // show input/output data
03025                                                     $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
03026                                                     foreach($marie as $captain => $tenille){ // loop through data
03027                                                                 if($captain == 'parts'){ // loop thru parts
03028                                                                     $b .= "&nbsp;&nbsp;$captain:<br>";
03029                                                         //if(is_array($tenille)){
03030                                                                         foreach($tenille as $joanie => $chachi){
03031                                                                                         $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
03032                                                                         }
03033                                                                 //}
03034                                                                 } else {
03035                                                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
03036                                                                 }
03037                                                     }
03038                                                 } else {
03039                                                     $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
03040                                                 }
03041                                     }
03042                                         $b .= '</div>';
03043                                 }
03044                                 $b .= '
03045                                 <ul>
03046                         </div>
03047                 </div></body></html>';
03048                 return $b;
03049     }
03050 
03062     function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
03063     {
03064                 $SERVER_NAME = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : $GLOBALS['SERVER_NAME'];
03065                 $SERVER_PORT = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : $GLOBALS['SERVER_PORT'];
03066                 if ($SERVER_PORT == 80) {
03067                         $SERVER_PORT = '';
03068                 } else {
03069                         $SERVER_PORT = ':' . $SERVER_PORT;
03070                 }
03071                 $SCRIPT_NAME = isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] : $GLOBALS['SCRIPT_NAME'];
03072         if(false == $namespace) {
03073             $namespace = "http://$SERVER_NAME/soap/$serviceName";
03074         }
03075         
03076         if(false == $endpoint) {
03077                 if (isset($_SERVER['HTTPS'])) {
03078                         $HTTPS = $_SERVER['HTTPS'];
03079                 } elseif (isset($GLOBALS['HTTPS'])) {
03080                         $HTTPS = $GLOBALS['HTTPS'];
03081                 } else {
03082                         $HTTPS = '0';
03083                 }
03084                 if ($HTTPS == '1' || $HTTPS == 'on') {
03085                         $SCHEME = 'https';
03086                 } else {
03087                         $SCHEME = 'http';
03088                 }
03089             $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
03090         }
03091         
03092         if(false == $schemaTargetNamespace) {
03093             $schemaTargetNamespace = $namespace;
03094         }
03095         
03096                 $this->wsdl = new wsdl;
03097                 $this->wsdl->serviceName = $serviceName;
03098         $this->wsdl->endpoint = $endpoint;
03099                 $this->wsdl->namespaces['tns'] = $namespace;
03100                 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
03101                 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
03102                 if ($schemaTargetNamespace != $namespace) {
03103                         $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
03104                 }
03105         $this->wsdl->schemas[$schemaTargetNamespace][0] = new xmlschema('', '', $this->wsdl->namespaces);
03106         $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
03107         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
03108         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
03109         $this->wsdl->bindings[$serviceName.'Binding'] = array(
03110                 'name'=>$serviceName.'Binding',
03111             'style'=>$style,
03112             'transport'=>$transport,
03113             'portType'=>$serviceName.'PortType');
03114         $this->wsdl->ports[$serviceName.'Port'] = array(
03115                 'binding'=>$serviceName.'Binding',
03116             'location'=>$endpoint,
03117             'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
03118     }
03119 }
03120 
03121 
03122 
03123 ?><?php
03124 
03125 
03126 
03133 class wsdl extends nusoap_base {
03134         // URL or filename of the root of this WSDL
03135     var $wsdl; 
03136     // define internal arrays of bindings, ports, operations, messages, etc.
03137     var $schemas = array();
03138     var $currentSchema;
03139     var $message = array();
03140     var $complexTypes = array();
03141     var $messages = array();
03142     var $currentMessage;
03143     var $currentOperation;
03144     var $portTypes = array();
03145     var $currentPortType;
03146     var $bindings = array();
03147     var $currentBinding;
03148     var $ports = array();
03149     var $currentPort;
03150     var $opData = array();
03151     var $status = '';
03152     var $documentation = false;
03153     var $endpoint = ''; 
03154     // array of wsdl docs to import
03155     var $import = array(); 
03156     // parser vars
03157     var $parser;
03158     var $position = 0;
03159     var $depth = 0;
03160     var $depth_array = array();
03161         // for getting wsdl
03162         var $proxyhost = '';
03163     var $proxyport = '';
03164         var $proxyusername = '';
03165         var $proxypassword = '';
03166         var $timeout = 0;
03167         var $response_timeout = 30;
03168 
03181     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30){
03182         $this->wsdl = $wsdl;
03183         $this->proxyhost = $proxyhost;
03184         $this->proxyport = $proxyport;
03185                 $this->proxyusername = $proxyusername;
03186                 $this->proxypassword = $proxypassword;
03187                 $this->timeout = $timeout;
03188                 $this->response_timeout = $response_timeout;
03189         
03190         // parse wsdl file
03191         if ($wsdl != "") {
03192             $this->debug('initial wsdl URL: ' . $wsdl);
03193             $this->parseWSDL($wsdl);
03194         }
03195         // imports
03196         // TODO: handle imports more properly, grabbing them in-line and nesting them
03197                 $imported_urls = array();
03198                 $imported = 1;
03199                 while ($imported > 0) {
03200                         $imported = 0;
03201                         // Schema imports
03202                         foreach ($this->schemas as $ns => $list) {
03203                                 foreach ($list as $xs) {
03204                                                 $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
03205                                     foreach ($xs->imports as $ns2 => $list2) {
03206                                         for ($ii = 0; $ii < count($list2); $ii++) {
03207                                                 if (! $list2[$ii]['loaded']) {
03208                                                         $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
03209                                                         $url = $list2[$ii]['location'];
03210                                                                         if ($url != '') {
03211                                                                                 $urlparts = parse_url($url);
03212                                                                                 if (!isset($urlparts['host'])) {
03213                                                                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . 
03214                                                                                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
03215                                                                                 }
03216                                                                                 if (! in_array($url, $imported_urls)) {
03217                                                                         $this->parseWSDL($url);
03218                                                                         $imported++;
03219                                                                         $imported_urls[] = $url;
03220                                                                 }
03221                                                                         } else {
03222                                                                                 $this->debug("Unexpected scenario: empty URL for unloaded import");
03223                                                                         }
03224                                                                 }
03225                                                         }
03226                                     } 
03227                                 }
03228                         }
03229                         // WSDL imports
03230                                 $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
03231                     foreach ($this->import as $ns => $list) {
03232                         for ($ii = 0; $ii < count($list); $ii++) {
03233                                 if (! $list[$ii]['loaded']) {
03234                                         $this->import[$ns][$ii]['loaded'] = true;
03235                                         $url = $list[$ii]['location'];
03236                                                         if ($url != '') {
03237                                                                 $urlparts = parse_url($url);
03238                                                                 if (!isset($urlparts['host'])) {
03239                                                                         $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . 
03240                                                                                         substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
03241                                                                 }
03242                                                                 if (! in_array($url, $imported_urls)) {
03243                                                         $this->parseWSDL($url);
03244                                                         $imported++;
03245                                                         $imported_urls[] = $url;
03246                                                 }
03247                                                         } else {
03248                                                                 $this->debug("Unexpected scenario: empty URL for unloaded import");
03249                                                         }
03250                                                 }
03251                                         }
03252                     } 
03253                         }
03254         // add new data to operation data
03255         foreach($this->bindings as $binding => $bindingData) {
03256             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
03257                 foreach($bindingData['operations'] as $operation => $data) {
03258                     $this->debug('post-parse data gathering for ' . $operation);
03259                     $this->bindings[$binding]['operations'][$operation]['input'] = 
03260                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 
03261                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
03262                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
03263                     $this->bindings[$binding]['operations'][$operation]['output'] = 
03264                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
03265                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
03266                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
03267                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
03268                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
03269                                         }
03270                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
03271                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
03272                     }
03273                                         if (isset($bindingData['style'])) {
03274                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
03275                     }
03276                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
03277                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
03278                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
03279                 } 
03280             } 
03281         }
03282     }
03283 
03290     function parseWSDL($wsdl = '')
03291     {
03292         if ($wsdl == '') {
03293             $this->debug('no wsdl passed to parseWSDL()!!');
03294             $this->setError('no wsdl passed to parseWSDL()!!');
03295             return false;
03296         }
03297         
03298         // parse $wsdl for url format
03299         $wsdl_props = parse_url($wsdl);
03300 
03301         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
03302             $this->debug('getting WSDL http(s) URL ' . $wsdl);
03303                 // get wsdl
03304                 $tr = new soap_transport_http($wsdl);
03305                         $tr->request_method = 'GET';
03306                         $tr->useSOAPAction = false;
03307                         if($this->proxyhost && $this->proxyport){
03308                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
03309                         }
03310                         if (isset($wsdl_props['user'])) {
03311                 $tr->setCredentials($wsdl_props['user'],$wsdl_props['pass']);
03312             }
03313                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
03314                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);
03315                         //$this->debug("WSDL response\n" . $tr->incoming_payload);
03316                         $this->debug("transport debug data...\n" . $tr->debug_str);
03317                         // catch errors
03318                         if($err = $tr->getError() ){
03319                                 $errstr = 'HTTP ERROR: '.$err;
03320                                 $this->debug($errstr);
03321                     $this->setError($errstr);
03322                                 unset($tr);
03323                     return false;
03324                         }
03325                         unset($tr);
03326         } else {
03327             // $wsdl is not http(s), so treat it as a file URL or plain file path
03328                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
03329                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
03330                 } else {
03331                         $path = $wsdl;
03332                 }
03333             $this->debug('getting WSDL file ' . $path);
03334             if ($fp = @fopen($path, 'r')) {
03335                 $wsdl_string = '';
03336                 while ($data = fread($fp, 32768)) {
03337                     $wsdl_string .= $data;
03338                 } 
03339                 fclose($fp);
03340             } else {
03341                 $errstr = "Bad path to WSDL file $path";
03342                 $this->debug($errstr);
03343                 $this->setError($errstr);
03344                 return false;
03345             } 
03346         }
03347         // end new code added
03348         // Create an XML parser.
03349         $this->parser = xml_parser_create(); 
03350         // Set the options for parsing the XML data.
03351         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
03352         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 
03353         // Set the object for the parser.
03354         xml_set_object($this->parser, $this); 
03355         // Set the element handlers for the parser.
03356         xml_set_element_handler($this->parser, 'start_element', 'end_element');
03357         xml_set_character_data_handler($this->parser, 'character_data');
03358         // Parse the XML file.
03359         if (!xml_parse($this->parser, $wsdl_string, true)) {
03360             // Display an error message.
03361             $errstr = sprintf(
03362                                 'XML error parsing WSDL from %s on line %d: %s',
03363                                 $wsdl,
03364                 xml_get_current_line_number($this->parser),
03365                 xml_error_string(xml_get_error_code($this->parser))
03366                 );
03367             $this->debug($errstr);
03368                         $this->debug("XML payload:\n" . $wsdl_string);
03369             $this->setError($errstr);
03370             return false;
03371         } 
03372                 // free the parser
03373         xml_parser_free($this->parser);
03374                 // catch wsdl parse errors
03375                 if($this->getError()){
03376                         return false;
03377                 }
03378         return true;
03379     } 
03380 
03389     function start_element($parser, $name, $attrs)
03390     {
03391         if ($this->status == 'schema') {
03392             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
03393             $this->debug_str .= $this->currentSchema->debug_str;
03394             $this->currentSchema->debug_str = '';
03395         } elseif (ereg('schema$', $name)) {
03396             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
03397             $this->status = 'schema';
03398             $this->currentSchema = new xmlschema('', '', $this->namespaces);
03399             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
03400             $this->debug_str .= $this->currentSchema->debug_str;
03401             $this->currentSchema->debug_str = '';
03402         } else {
03403             // position in the total number of elements, starting from 0
03404             $pos = $this->position++;
03405             $depth = $this->depth++; 
03406             // set self as current value for this depth
03407             $this->depth_array[$depth] = $pos;
03408             $this->message[$pos] = array('cdata' => ''); 
03409             // get element prefix
03410             if (ereg(':', $name)) {
03411                 // get ns prefix
03412                 $prefix = substr($name, 0, strpos($name, ':')); 
03413                 // get ns
03414                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 
03415                 // get unqualified name
03416                 $name = substr(strstr($name, ':'), 1);
03417             } 
03418 
03419             if (count($attrs) > 0) {
03420                 foreach($attrs as $k => $v) {
03421                     // if ns declarations, add to class level array of valid namespaces
03422                     if (ereg("^xmlns", $k)) {
03423                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
03424                             $this->namespaces[$ns_prefix] = $v;
03425                         } else {
03426                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
03427                         } 
03428                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema') {
03429                             $this->XMLSchemaVersion = $v;
03430                             $this->namespaces['xsi'] = $v . '-instance';
03431                         } 
03432                     } //  
03433                     // expand each attribute
03434                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
03435                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
03436                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
03437                     } 
03438                     $eAttrs[$k] = $v;
03439                 } 
03440                 $attrs = $eAttrs;
03441             } else {
03442                 $attrs = array();
03443             } 
03444             // find status, register data
03445             switch ($this->status) {
03446                 case 'message':
03447                     if ($name == 'part') {
03448                         if (isset($attrs['type'])) {
03449                                     $this->debug("msg " . $this->currentMessage . ": found part $attrs[name]: " . implode(',', $attrs));
03450                                     $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
03451                                 } 
03452                                     if (isset($attrs['element'])) {
03453                                         $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'];
03454                                     } 
03455                                 } 
03456                                 break;
03457                             case 'portType':
03458                                 switch ($name) {
03459                                     case 'operation':
03460                                         $this->currentPortOperation = $attrs['name'];
03461                                         $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
03462                                         if (isset($attrs['parameterOrder'])) {
03463                                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
03464                                                 } 
03465                                                 break;
03466                                             case 'documentation':
03467                                                 $this->documentation = true;
03468                                                 break; 
03469                                             // merge input/output data
03470                                             default:
03471                                                 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
03472                                                 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
03473                                                 break;
03474                                         } 
03475                                 break;
03476                                 case 'binding':
03477                                     switch ($name) {
03478                                         case 'binding': 
03479                                             // get ns prefix
03480                                             if (isset($attrs['style'])) {
03481                                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;
03482                                                 } 
03483                                                 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
03484                                                 break;
03485                                                 case 'header':
03486                                                     $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
03487                                                     break;
03488                                                 case 'operation':
03489                                                     if (isset($attrs['soapAction'])) {
03490                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
03491                                                     } 
03492                                                     if (isset($attrs['style'])) {
03493                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
03494                                                     } 
03495                                                     if (isset($attrs['name'])) {
03496                                                         $this->currentOperation = $attrs['name'];
03497                                                         $this->debug("current binding operation: $this->currentOperation");
03498                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
03499                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
03500                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
03501                                                     } 
03502                                                     break;
03503                                                 case 'input':
03504                                                     $this->opStatus = 'input';
03505                                                     break;
03506                                                 case 'output':
03507                                                     $this->opStatus = 'output';
03508                                                     break;
03509                                                 case 'body':
03510                                                     if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
03511                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
03512                                                     } else {
03513                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
03514                                                     } 
03515                                                     break;
03516                                         } 
03517                                         break;
03518                                 case 'service':
03519                                         switch ($name) {
03520                                             case 'port':
03521                                                 $this->currentPort = $attrs['name'];
03522                                                 $this->debug('current port: ' . $this->currentPort);
03523                                                 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
03524                                         
03525                                                 break;
03526                                             case 'address':
03527                                                 $this->ports[$this->currentPort]['location'] = $attrs['location'];
03528                                                 $this->ports[$this->currentPort]['bindingType'] = $namespace;
03529                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
03530                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
03531                                                 break;
03532                                         } 
03533                                         break;
03534                         } 
03535                 // set status
03536                 switch ($name) {
03537                         case 'import':
03538                             if (isset($attrs['location'])) {
03539                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
03540                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
03541                                 } else {
03542                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
03543                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
03544                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
03545                                         }
03546                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
03547                                 }
03548                                 break;
03549                         //wait for schema
03550                         //case 'types':
03551                         //      $this->status = 'schema';
03552                         //      break;
03553                         case 'message':
03554                                 $this->status = 'message';
03555                                 $this->messages[$attrs['name']] = array();
03556                                 $this->currentMessage = $attrs['name'];
03557                                 break;
03558                         case 'portType':
03559                                 $this->status = 'portType';
03560                                 $this->portTypes[$attrs['name']] = array();
03561                                 $this->currentPortType = $attrs['name'];
03562                                 break;
03563                         case "binding":
03564                                 if (isset($attrs['name'])) {
03565                                 // get binding name
03566                                         if (strpos($attrs['name'], ':')) {
03567                                         $this->currentBinding = $this->getLocalPart($attrs['name']);
03568                                         } else {
03569                                         $this->currentBinding = $attrs['name'];
03570                                         } 
03571                                         $this->status = 'binding';
03572                                         $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
03573                                         $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
03574                                 } 
03575                                 break;
03576                         case 'service':
03577                                 $this->serviceName = $attrs['name'];
03578                                 $this->status = 'service';
03579                                 $this->debug('current service: ' . $this->serviceName);
03580                                 break;
03581                         case 'definitions':
03582                                 foreach ($attrs as $name => $value) {
03583                                         $this->wsdl_info[$name] = $value;
03584                                 } 
03585                                 break;
03586                         } 
03587                 } 
03588         } 
03589 
03597         function end_element($parser, $name){ 
03598                 // unset schema status
03599                 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) {
03600                         $this->status = "";
03601                         $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
03602                 } 
03603                 if ($this->status == 'schema') {
03604                         $this->currentSchema->schemaEndElement($parser, $name);
03605                 } else {
03606                         // bring depth down a notch
03607                         $this->depth--;
03608                 } 
03609                 // end documentation
03610                 if ($this->documentation) {
03611                         //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
03612                         //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
03613                         $this->documentation = false;
03614                 } 
03615         } 
03616 
03624         function character_data($parser, $data)
03625         {
03626                 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
03627                 if (isset($this->message[$pos]['cdata'])) {
03628                         $this->message[$pos]['cdata'] .= $data;
03629                 } 
03630                 if ($this->documentation) {
03631                         $this->documentation .= $data;
03632                 } 
03633         } 
03634         
03635         function getBindingData($binding)
03636         {
03637                 if (is_array($this->bindings[$binding])) {
03638                         return $this->bindings[$binding];
03639                 } 
03640         }
03641         
03649         function getOperations($bindingType = 'soap')
03650         {
03651                 $ops = array();
03652                 if ($bindingType == 'soap') {
03653                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03654                 }
03655                 // loop thru ports
03656                 foreach($this->ports as $port => $portData) {
03657                         // binding type of port matches parameter
03658                         if ($portData['bindingType'] == $bindingType) {
03659                                 //$this->debug("getOperations for port $port");
03660                                 //$this->debug("port data: " . $this->varDump($portData));
03661                                 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
03662                                 // merge bindings
03663                                 if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
03664                                         $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
03665                                 }
03666                         }
03667                 } 
03668                 return $ops;
03669         } 
03670         
03679         function getOperationData($operation, $bindingType = 'soap')
03680         {
03681                 if ($bindingType == 'soap') {
03682                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
03683                 }
03684                 // loop thru ports
03685                 foreach($this->ports as $port => $portData) {
03686                         // binding type of port matches parameter
03687                         if ($portData['bindingType'] == $bindingType) {
03688                                 // get binding
03689                                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
03690                                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
03691                                         if ($operation == $bOperation) {
03692                                                 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
03693                                             return $opData;
03694                                         } 
03695                                 } 
03696                         }
03697                 } 
03698         }
03699         
03718         function getTypeDef($type, $ns) {
03719                 if ((! $ns) && isset($this->namespaces['tns'])) {
03720                         $ns = $this->namespaces['tns'];
03721                 }
03722                 if (isset($this->schemas[$ns])) {
03723                         foreach ($this->schemas[$ns] as $xs) {
03724                                 $t = $xs->getTypeDef($type);
03725                                 $this->debug_str .= $xs->debug_str;
03726                                 $xs->debug_str = '';
03727                                 if ($t) {
03728                                         return $t;
03729                                 }
03730                         }
03731                 }
03732                 return false;
03733         }
03734 
03741         function serialize()
03742         {
03743                 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?><definitions';
03744                 foreach($this->namespaces as $k => $v) {
03745                         $xml .= " xmlns:$k=\"$v\"";
03746                 } 
03747                 // 10.9.02 - add poulter fix for wsdl and tns declarations
03748                 if (isset($this->namespaces['wsdl'])) {
03749                         $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
03750                 } 
03751                 if (isset($this->namespaces['tns'])) {
03752                         $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
03753                 } 
03754                 $xml .= '>'; 
03755                 // imports
03756                 if (sizeof($this->import) > 0) {
03757                         foreach($this->import as $ns => $list) {
03758                                 foreach ($list as $ii) {
03759                                         if ($ii['location'] != '') {
03760                                                 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
03761                                         } else {
03762                                                 $xml .= '<import namespace="' . $ns . '" />';
03763                                         }
03764                                 }
03765                         } 
03766                 } 
03767                 // types
03768                 if (count($this->schemas)>=1) {
03769                         $xml .= '<types>';
03770                         foreach ($this->schemas as $ns => $list) {
03771                                 foreach ($list as $xs) {
03772                                         $xml .= $xs->serializeSchema();
03773                                 }
03774                         }
03775                         $xml .= '</types>';
03776                 } 
03777                 // messages
03778                 if (count($this->messages) >= 1) {
03779                         foreach($this->messages as $msgName => $msgParts) {
03780                                 $xml .= '<message name="' . $msgName . '">';
03781                                 if(is_array($msgParts)){
03782                                         foreach($msgParts as $partName => $partType) {
03783                                                 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
03784                                                 if (strpos($partType, ':')) {
03785                                                     $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
03786                                                 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
03787                                                     // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
03788                                                     $typePrefix = 'xsd';
03789                                                 } else {
03790                                                     foreach($this->typemap as $ns => $types) {
03791                                                         if (isset($types[$partType])) {
03792                                                             $typePrefix = $this->getPrefixFromNamespace($ns);
03793                                                         } 
03794                                                     } 
03795                                                     if (!isset($typePrefix)) {
03796                                                         die("$partType has no namespace!");
03797                                                     } 
03798                                                 } 
03799                                                 $xml .= '<part name="' . $partName . '" type="' . $typePrefix . ':' . $this->getLocalPart($partType) . '" />';
03800                                         }
03801                                 }
03802                                 $xml .= '</message>';
03803                         } 
03804                 } 
03805                 // bindings & porttypes
03806                 if (count($this->bindings) >= 1) {
03807                         $binding_xml = '';
03808                         $portType_xml = '';
03809                         foreach($this->bindings as $bindingName => $attrs) {
03810                                 $binding_xml .= '<binding name="' . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
03811                                 $binding_xml .= '<soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
03812                                 $portType_xml .= '<portType name="' . $attrs['portType'] . '">';
03813                                 foreach($attrs['operations'] as $opName => $opParts) {
03814                                         $binding_xml .= '<operation name="' . $opName . '">';
03815                                         $binding_xml .= '<soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $attrs['style'] . '"/>';
03816                                         if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
03817                                                 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
03818                                         } else {
03819                                                 $enc_style = '';
03820                                         }
03821                                         $binding_xml .= '<input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
03822                                         if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
03823                                                 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
03824                                         } else {
03825                                                 $enc_style = '';
03826                                         }
03827                                         $binding_xml .= '<output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
03828                                         $binding_xml .= '</operation>';
03829                                         $portType_xml .= '<operation name="' . $opParts['name'] . '"';
03830                                         if (isset($opParts['parameterOrder'])) {
03831                                             $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
03832                                         } 
03833                                         $portType_xml .= '>';
03834                                         if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
03835                                                 $portType_xml .= '<documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
03836                                         }
03837                                         $portType_xml .= '<input message="tns:' . $opParts['input']['message'] . '"/>';
03838                                         $portType_xml .= '<output message="tns:' . $opParts['output']['message'] . '"/>';
03839                                         $portType_xml .= '</operation>';
03840                                 } 
03841                                 $portType_xml .= '</portType>';
03842                                 $binding_xml .= '</binding>';
03843                         } 
03844                         $xml .= $portType_xml . $binding_xml;
03845                 } 
03846                 // services
03847                 $xml .= '<service name="' . $this->serviceName . '">';
03848                 if (count($this->ports) >= 1) {
03849                         foreach($this->ports as $pName => $attrs) {
03850                                 $xml .= '<port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
03851                                 $xml .= '<soap:address location="' . $attrs['location'] . '"/>';
03852                                 $xml .= '</port>';
03853                         } 
03854                 } 
03855                 $xml .= '</service>';
03856                 return $xml . '</definitions>';
03857         } 
03858         
03870         function serializeRPCParameters($operation, $direction, $parameters)
03871         {
03872                 $this->debug('in serializeRPCParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion); 
03873                 
03874                 if ($direction != 'input' && $direction != 'output') {
03875                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
03876                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
03877                         return false;
03878                 } 
03879                 if (!$opData = $this->getOperationData($operation)) {
03880                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
03881                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
03882                         return false;
03883                 }
03884                 $this->debug($this->varDump($opData));
03885 
03886                 // Get encoding style for output and set to current
03887                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
03888                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
03889                         $encodingStyle = $opData['output']['encodingStyle'];
03890                         $enc_style = $encodingStyle;
03891                 }
03892 
03893                 // set input params
03894                 $xml = '';
03895                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
03896                         
03897                         $use = $opData[$direction]['use'];
03898                         $this->debug("use=$use");
03899                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
03900                         if (is_array($parameters)) {
03901                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
03902                                 $this->debug('have ' . $parametersArrayType . ' parameters');
03903                                 foreach($opData[$direction]['parts'] as $name => $type) {
03904                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
03905                                         // Track encoding style
03906                                         if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
03907                                                 $encodingStyle = $opData[$direction]['encodingStyle'];                  
03908                                                 $enc_style = $encodingStyle;
03909                                         } else {
03910                                                 $enc_style = false;
03911                                         }
03912                                         // NOTE: add error handling here
03913                                         // if serializeType returns false, then catch global error and fault
03914                                         if ($parametersArrayType == 'arraySimple') {
03915                                                 $p = array_shift($parameters);
03916                                                 $this->debug('calling serializeType w/indexed param');
03917                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
03918                                         } elseif (isset($parameters[$name])) {
03919                                                 $this->debug('calling serializeType w/named param');
03920                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
03921                                         } else {
03922                                                 // TODO: only send nillable
03923                                                 $this->debug('calling serializeType w/null param');
03924                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
03925                                         }
03926                                 }
03927                         } else {
03928                                 $this->debug('no parameters passed.');
03929                         }
03930                 }
03931                 return $xml;
03932         } 
03933         
03945         function serializeParameters($operation, $direction, $parameters)
03946         {
03947                 $this->debug('in serializeParameters with operation '.$operation.', direction '.$direction.' and '.count($parameters).' param(s), and xml schema version ' . $this->XMLSchemaVersion); 
03948                 
03949                 if ($direction != 'input' && $direction != 'output') {
03950                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
03951                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
03952                         return false;
03953                 } 
03954                 if (!$opData = $this->getOperationData($operation)) {
03955                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
03956                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
03957                         return false;
03958                 }
03959                 $this->debug($this->varDump($opData));
03960                 
03961                 // Get encoding style for output and set to current
03962                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
03963                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
03964                         $encodingStyle = $opData['output']['encodingStyle'];
03965                         $enc_style = $encodingStyle;
03966                 }
03967                 
03968                 // set input params
03969                 $xml = '';
03970                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
03971                         
03972                         $use = $opData[$direction]['use'];
03973                         $this->debug("use=$use");
03974                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
03975                         if (is_array($parameters)) {
03976                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
03977                                 $this->debug('have ' . $parametersArrayType . ' parameters');
03978                                 foreach($opData[$direction]['parts'] as $name => $type) {
03979                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
03980                                         // Track encoding style
03981                                         if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
03982                                                 $encodingStyle = $opData[$direction]['encodingStyle'];                  
03983                                                 $enc_style = $encodingStyle;
03984                                         } else {
03985                                                 $enc_style = false;
03986                                         }
03987                                         // NOTE: add error handling here
03988                                         // if serializeType returns false, then catch global error and fault
03989                                         if ($parametersArrayType == 'arraySimple') {
03990                                                 $p = array_shift($parameters);
03991                                                 $this->debug('calling serializeType w/indexed param');
03992                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
03993                                         } elseif (isset($parameters[$name])) {
03994                                                 $this->debug('calling serializeType w/named param');
03995                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
03996                                         } else {
03997                                                 // TODO: only send nillable
03998                                                 $this->debug('calling serializeType w/null param');
03999                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
04000                                         }
04001                                 }
04002                         } else {
04003                                 $this->debug('no parameters passed.');
04004                         }
04005                 }
04006                 return $xml;
04007         } 
04008         
04020         function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false)
04021         {
04022                 $this->debug("in serializeType: $name, $type, $value, $use, $encodingStyle");
04023                 if($use == 'encoded' && $encodingStyle) {
04024                         $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
04025                 }
04026 
04027                 // if a soap_val has been supplied, let its type override the WSDL
04028         if (is_object($value) && get_class($value) == 'soapval') {
04029                 // TODO: get attributes from soapval?
04030                 if ($value->type_ns) {
04031                         $type = $value->type_ns . ':' . $value->type;
04032                 } else {
04033                         $type = $value->type;
04034                 }
04035                 $value = $value->value;
04036                 $forceType = true;
04037                 $this->debug("in serializeType: soapval overrides type to $type, value to $value");
04038         } else {
04039                 $forceType = false;
04040         }
04041 
04042                 $xml = '';
04043                 if (strpos($type, ':')) {
04044                         $uqType = substr($type, strrpos($type, ':') + 1);
04045                         $ns = substr($type, 0, strrpos($type, ':'));
04046                         $this->debug("got a prefixed type: $uqType, $ns");
04047                         if ($this->getNamespaceFromPrefix($ns)) {
04048                                 $ns = $this->getNamespaceFromPrefix($ns);
04049                                 $this->debug("expanded prefixed type: $uqType, $ns");
04050                         }
04051 
04052                         if($ns == $this->XMLSchemaVersion){
04053                                 
04054                                 if (is_null($value)) {
04055                                         if ($use == 'literal') {
04056                                                 // TODO: depends on nillable
04057                                                 return "<$name/>";
04058                                         } else {
04059                                                 return "<$name xsi:nil=\"true\"/>";
04060                                         }
04061                                 }
04062                         if ($uqType == 'boolean' && !$value) {
04063                                         $value = 'false';
04064                                 } elseif ($uqType == 'boolean') {
04065                                         $value = 'true';
04066                                 } 
04067                                 if ($uqType == 'string' && gettype($value) == 'string') {
04068                                         $value = $this->expandEntities($value);
04069                                 } 
04070                                 // it's a scalar
04071                                 // TODO: what about null/nil values?
04072                                 // check type isn't a custom type extending xmlschema namespace
04073                                 if (!$this->getTypeDef($uqType, $ns)) {
04074                                         if ($use == 'literal') {
04075                                                 if ($forceType) {
04076                                                         return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\">$value</$name>";
04077                                                 } else {
04078                                                         return "<$name>$value</$name>";
04079                                                 }
04080                                         } else {
04081                                                 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace($this->XMLSchemaVersion) . ":$uqType\"$encodingStyle>$value</$name>";
04082                                         }
04083                                 }
04084                         } else if ($ns == 'http://xml.apache.org/xml-soap') {
04085                                 if ($uqType == 'Map') {
04086                                         $contents = '';
04087                                         foreach($value as $k => $v) {
04088                                                 $this->debug("serializing map element: key $k, value $v");
04089                                                 $contents .= '<item>';
04090                                                 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
04091                                                 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
04092                                                 $contents .= '</item>';
04093                                         }
04094                                         if ($use == 'literal') {
04095                                                 if ($forceType) {
04096                                                 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\">$contents</$name>";
04097                                                 } else {
04098                                                         return "<$name>$contents</$name>";
04099                                                 }
04100                                         } else {
04101                                                 return "<$name xsi:type=\"" . $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap') . ":$uqType\"$encodingStyle>$contents</$name>";
04102                                         }
04103                                 }
04104                         }
04105                 } else {
04106                         $this->debug("No namespace for type $type");
04107                         $ns = '';
04108                         $uqType = $type;
04109                 }
04110                 if(!$typeDef = $this->getTypeDef($uqType, $ns)){
04111                         $this->setError("$type ($uqType) is not a supported type.");
04112                         $this->debug("$type ($uqType) is not a supported type.");
04113                         return false;
04114                 } else {
04115                         foreach($typeDef as $k => $v) {
04116                                 $this->debug("typedef, $k: $v");
04117                         }
04118                 }
04119                 $phpType = $typeDef['phpType'];
04120                 $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 
04121                 // if php type == struct, map value to the <all> element names
04122                 if ($phpType == 'struct') {
04123                         if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
04124                                 $elementName = $uqType;
04125                                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04126                                         $elementNS = " xmlns=\"$ns\"";
04127                                 }
04128                         } else {
04129                                 $elementName = $name;
04130                                 $elementNS = '';
04131                         }
04132                         if (is_null($value)) {
04133                                 if ($use == 'literal') {
04134                                         // TODO: depends on nillable
04135                                         return "<$elementName$elementNS/>";
04136                                 } else {
04137                                         return "<$elementName$elementNS xsi:nil=\"true\"/>";
04138                                 }
04139                         }
04140                         if ($use == 'literal') {
04141                                 if ($forceType) {
04142                                         $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
04143                                 } else {
04144                                         $xml = "<$elementName$elementNS>";
04145                                 }
04146                         } else {
04147                                 $xml = "<$elementName$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
04148                         }
04149                         
04150                         if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
04151                                 if (is_array($value)) {
04152                                         $xvalue = $value;
04153                                 } elseif (is_object($value)) {
04154                                         $xvalue = get_object_vars($value);
04155                                 } else {
04156                                         $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
04157                                         $xvalue = array();
04158                                 }
04159                                 // toggle whether all elements are present - ideally should validate against schema
04160                                 if(count($typeDef['elements']) != count($xvalue)){
04161                                         $optionals = true;
04162                                 }
04163                                 foreach($typeDef['elements'] as $eName => $attrs) {
04164                                         // if user took advantage of a minOccurs=0, then only serialize named parameters
04165                                         if(isset($optionals) && !isset($xvalue[$eName])){
04166                                                 // do nothing
04167                                         } else {
04168                                                 // get value
04169                                                 if (isset($xvalue[$eName])) {
04170                                                     $v = $xvalue[$eName];
04171                                                 } else {
04172                                                     $v = null;
04173                                                 }
04174                                                 // TODO: if maxOccurs > 1 (not just unbounded), then allow serialization of an array
04175                                                 if (isset($attrs['maxOccurs']) && $attrs['maxOccurs'] == 'unbounded' && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
04176                                                         $vv = $v;
04177                                                         foreach ($vv as $k => $v) {
04178                                                                 if (isset($attrs['type'])) {
04179                                                                         // serialize schema-defined type
04180                                                                     $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
04181                                                                 } else {
04182                                                                         // serialize generic type
04183                                                                     $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
04184                                                                     $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
04185                                                                 }
04186                                                         }
04187                                                 } else {
04188                                                         if (isset($attrs['type'])) {
04189                                                                 // serialize schema-defined type
04190                                                             $xml .= $this->serializeType($eName, $attrs['type'], $v, $use, $encodingStyle);
04191                                                         } else {
04192                                                                 // serialize generic type
04193                                                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
04194                                                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
04195                                                         }
04196                                                 }
04197                                         }
04198                                 } 
04199                         } else {
04200                                 $this->debug("Expected elements for XML Schema type $ns:$uqType");
04201                         }
04202                         $xml .= "</$elementName>";
04203                 } elseif ($phpType == 'array') {
04204                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04205                                 $elementNS = " xmlns=\"$ns\"";
04206                         } else {
04207                                 $elementNS = '';
04208                         }
04209                         if (is_null($value)) {
04210                                 if ($use == 'literal') {
04211                                         // TODO: depends on nillable
04212                                         return "<$name$elementNS/>";
04213                                 } else {
04214                                         return "<$name$elementNS xsi:nil=\"true\"/>";
04215                                 }
04216                         }
04217                         if (isset($typeDef['multidimensional'])) {
04218                                 $nv = array();
04219                                 foreach($value as $v) {
04220                                         $cols = ',' . sizeof($v);
04221                                         $nv = array_merge($nv, $v);
04222                                 } 
04223                                 $value = $nv;
04224                         } else {
04225                                 $cols = '';
04226                         } 
04227                         if (is_array($value) && sizeof($value) >= 1) {
04228                                 $rows = sizeof($value);
04229                                 $contents = '';
04230                                 foreach($value as $k => $v) {
04231                                         $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
04232                                         //if (strpos($typeDef['arrayType'], ':') ) {
04233                                         if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
04234                                             $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
04235                                         } else {
04236                                             $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
04237                                         } 
04238                                 }
04239                                 $this->debug('contents: '.$this->varDump($contents));
04240                         } else {
04241                                 $rows = 0;
04242                                 $contents = null;
04243                         }
04244                         // TODO: for now, an empty value will be serialized as a zero element
04245                         // array.  Revisit this when coding the handling of null/nil values.
04246                         if ($use == 'literal') {
04247                                 $xml = "<$name$elementNS>"
04248                                         .$contents
04249                                         ."</$name>";
04250                         } else {
04251                                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
04252                                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
04253                                         .':arrayType="'
04254                                         .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
04255                                         .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
04256                                         .$contents
04257                                         ."</$name>";
04258                         }
04259                 } elseif ($phpType == 'scalar') {
04260                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
04261                                 $elementNS = " xmlns=\"$ns\"";
04262                         } else {
04263                                 $elementNS = '';
04264                         }
04265                         if ($use == 'literal') {
04266                                 if ($forceType) {
04267                                         return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
04268                                 } else {
04269                                         return "<$name$elementNS>$value</$name>";
04270                                 }
04271                         } else {
04272                                 return "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
04273                         }
04274                 }
04275                 $this->debug('returning: '.$this->varDump($xml));
04276                 return $xml;
04277         }
04278         
04298         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
04299                 if (count($elements) > 0) {
04300                 foreach($elements as $n => $e){
04301                     // expand each element
04302                     foreach ($e as $k => $v) {
04303                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
04304                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
04305                             $ee[$k] = $v;
04306                         }
04307                         $eElements[$n] = $ee;
04308                 }
04309                 $elements = $eElements;
04310                 }
04311                 
04312                 if (count($attrs) > 0) {
04313                 foreach($attrs as $n => $a){
04314                     // expand each attribute
04315                     foreach ($a as $k => $v) {
04316                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
04317                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
04318                             $aa[$k] = $v;
04319                         }
04320                         $eAttrs[$n] = $aa;
04321                 }
04322                 $attrs = $eAttrs;
04323                 }
04324 
04325                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
04326                 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
04327 
04328                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04329                 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
04330         }
04331 
04342         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar') {
04343                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
04344 
04345                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
04346                 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType);
04347         }
04348 
04362         function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = ''){
04363                 if ($style == 'rpc' && $use == 'encoded') {
04364                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
04365                 } else {
04366                         $encodingStyle = '';
04367                 } 
04368                 // get binding
04369                 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
04370                 array(
04371                 'name' => $name,
04372                 'binding' => $this->serviceName . 'Binding',
04373                 'endpoint' => $this->endpoint,
04374                 'soapAction' => $soapaction,
04375                 'style' => $style,
04376                 'input' => array(
04377                         'use' => $use,
04378                         'namespace' => $namespace,
04379                         'encodingStyle' => $encodingStyle,
04380                         'message' => $name . 'Request',
04381                         'parts' => $in),
04382                 'output' => array(
04383                         'use' => $use,
04384                         'namespace' => $namespace,
04385                         'encodingStyle' => $encodingStyle,
04386                         'message' => $name . 'Response',
04387                         'parts' => $out),
04388                 'namespace' => $namespace,
04389                 'transport' => 'http://schemas.xmlsoap.org/soap/http',
04390                 'documentation' => $documentation); 
04391                 // add portTypes
04392                 // add messages
04393                 if($in)
04394                 {
04395                         foreach($in as $pName => $pType)
04396                         {
04397                                 if(strpos($pType,':')) {
04398                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
04399                                 }
04400                                 $this->messages[$name.'Request'][$pName] = $pType;
04401                         }
04402                 } else {
04403             $this->messages[$name.'Request']= '0';
04404         }
04405                 if($out)
04406                 {
04407                         foreach($out as $pName => $pType)
04408                         {
04409                                 if(strpos($pType,':')) {
04410                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
04411                                 }
04412                                 $this->messages[$name.'Response'][$pName] = $pType;
04413                         }
04414                 } else {
04415             $this->messages[$name.'Response']= '0';
04416         }
04417                 return true;
04418         } 
04419 }
04420 ?><?php
04421 
04422 
04423 
04431 class soap_parser extends nusoap_base {
04432 
04433         var $xml = '';
04434         var $xml_encoding = '';
04435         var $method = '';
04436         var $root_struct = '';
04437         var $root_struct_name = '';
04438         var $root_struct_namespace = '';
04439         var $root_header = '';
04440     var $document = '';                 // incoming SOAP body (text)
04441         // determines where in the message we are (envelope,header,body,method)
04442         var $status = '';
04443         var $position = 0;
04444         var $depth = 0;
04445         var $default_namespace = '';
04446         var $namespaces = array();
04447         var $message = array();
04448     var $parent = '';
04449         var $fault = false;
04450         var $fault_code = '';
04451         var $fault_str = '';
04452         var $fault_detail = '';
04453         var $depth_array = array();
04454         var $debug_flag = true;
04455         var $soapresponse = NULL;
04456         var $responseHeaders = '';      // incoming SOAP headers (text)
04457         var $body_position = 0;
04458         // for multiref parsing:
04459         // array of id => pos
04460         var $ids = array();
04461         // array of id => hrefs => pos
04462         var $multirefs = array();
04463         // toggle for auto-decoding element content
04464         var $decode_utf8 = false;
04465 
04475         function soap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=false){
04476                 $this->xml = $xml;
04477                 $this->xml_encoding = $encoding;
04478                 $this->method = $method;
04479                 $this->decode_utf8 = $decode_utf8;
04480 
04481                 // Check whether content has been read.
04482                 if(!empty($xml)){
04483                         $this->debug('Entering soap_parser(), length='.strlen($xml).', encoding='.$encoding);
04484                         // Create an XML parser - why not xml_parser_create_ns?
04485                         $this->parser = xml_parser_create($this->xml_encoding);
04486                         // Set the options for parsing the XML data.
04487                         //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
04488                         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
04489                         xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
04490                         // Set the object for the parser.
04491                         xml_set_object($this->parser, $this);
04492                         // Set the element handlers for the parser.
04493                         xml_set_element_handler($this->parser, 'start_element','end_element');
04494                         xml_set_character_data_handler($this->parser,'character_data');
04495 
04496                         // Parse the XML file.
04497                         if(!xml_parse($this->parser,$xml,true)){
04498                             // Display an error message.
04499                             $err = sprintf('XML error parsing SOAP payload on line %d: %s',
04500                             xml_get_current_line_number($this->parser),
04501                             xml_error_string(xml_get_error_code($this->parser)));
04502                                 $this->debug($err);
04503                                 $this->debug("XML payload:\n" . $xml);
04504                                 $this->setError($err);
04505                         } else {
04506                                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
04507                                 // get final value
04508                                 $this->soapresponse = $this->message[$this->root_struct]['result'];
04509                                 // get header value: no, because this is documented as XML string
04510 //                              if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
04511 //                                      $this->responseHeaders = $this->message[$this->root_header]['result'];
04512 //                              }
04513                                 // resolve hrefs/ids
04514                                 if(sizeof($this->multirefs) > 0){
04515                                         foreach($this->multirefs as $id => $hrefs){
04516                                                 $this->debug('resolving multirefs for id: '.$id);
04517                                                 $idVal = $this->buildVal($this->ids[$id]);
04518                                                 foreach($hrefs as $refPos => $ref){
04519                                                         $this->debug('resolving href at pos '.$refPos);
04520                                                         $this->multirefs[$id][$refPos] = $idVal;
04521                                                 }
04522                                         }
04523                                 }
04524                         }
04525                         xml_parser_free($this->parser);
04526                 } else {
04527                         $this->debug('xml was empty, didn\'t parse!');
04528                         $this->setError('xml was empty, didn\'t parse!');
04529                 }
04530         }
04531 
04540         function start_element($parser, $name, $attrs) {
04541                 // position in a total number of elements, starting from 0
04542                 // update class level pos
04543                 $pos = $this->position++;
04544                 // and set mine
04545                 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
04546                 // depth = how many levels removed from root?
04547                 // set mine as current global depth and increment global depth value
04548                 $this->message[$pos]['depth'] = $this->depth++;
04549 
04550                 // else add self as child to whoever the current parent is
04551                 if($pos != 0){
04552                         $this->message[$this->parent]['children'] .= '|'.$pos;
04553                 }
04554                 // set my parent
04555                 $this->message[$pos]['parent'] = $this->parent;
04556                 // set self as current parent
04557                 $this->parent = $pos;
04558                 // set self as current value for this depth
04559                 $this->depth_array[$this->depth] = $pos;
04560                 // get element prefix
04561                 if(strpos($name,':')){
04562                         // get ns prefix
04563                         $prefix = substr($name,0,strpos($name,':'));
04564                         // get unqualified name
04565                         $name = substr(strstr($name,':'),1);
04566                 }
04567                 // set status
04568                 if($name == 'Envelope'){
04569                         $this->status = 'envelope';
04570                 } elseif($name == 'Header'){
04571                         $this->root_header = $pos;
04572                         $this->status = 'header';
04573                 } elseif($name == 'Body'){
04574                         $this->status = 'body';
04575                         $this->body_position = $pos;
04576                 // set method
04577                 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){
04578                         $this->status = 'method';
04579                         $this->root_struct_name = $name;
04580                         $this->root_struct = $pos;
04581                         $this->message[$pos]['type'] = 'struct';
04582                         $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
04583                 }
04584                 // set my status
04585                 $this->message[$pos]['status'] = $this->status;
04586                 // set name
04587                 $this->message[$pos]['name'] = htmlspecialchars($name);
04588                 // set attrs
04589                 $this->message[$pos]['attrs'] = $attrs;
04590 
04591                 // loop through atts, logging ns and type declarations
04592         $attstr = '';
04593                 foreach($attrs as $key => $value){
04594                 $key_prefix = $this->getPrefix($key);
04595                         $key_localpart = $this->getLocalPart($key);
04596                         // if ns declarations, add to class level array of valid namespaces
04597             if($key_prefix == 'xmlns'){
04598                                 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){
04599                                         $this->XMLSchemaVersion = $value;
04600                                         $this->namespaces['xsd'] = $this->XMLSchemaVersion;
04601                                         $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
04602                                 }
04603                 $this->namespaces[$key_localpart] = $value;
04604                                 // set method namespace
04605                                 if($name == $this->root_struct_name){
04606                                         $this->methodNamespace = $value;
04607                                 }
04608                         // if it's a type declaration, set type
04609             } elseif($key_localpart == 'type'){
04610                 $value_prefix = $this->getPrefix($value);
04611                 $value_localpart = $this->getLocalPart($value);
04612                                 $this->message[$pos]['type'] = $value_localpart;
04613                                 $this->message[$pos]['typePrefix'] = $value_prefix;
04614                 if(isset($this->namespaces[$value_prefix])){
04615                         $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
04616                 } else if(isset($attrs['xmlns:'.$value_prefix])) {
04617                                         $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
04618                 }
04619                                 // should do something here with the namespace of specified type?
04620                         } elseif($key_localpart == 'arrayType'){
04621                                 $this->message[$pos]['type'] = 'array';
04622                                 /* do arrayType ereg here
04623                                 [1]    arrayTypeValue    ::=    atype asize
04624                                 [2]    atype    ::=    QName rank*
04625                                 [3]    rank    ::=    '[' (',')* ']'
04626                                 [4]    asize    ::=    '[' length~ ']'
04627                                 [5]    length    ::=    nextDimension* Digit+
04628                                 [6]    nextDimension    ::=    Digit+ ','
04629                                 */
04630                                 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]';
04631                                 if(ereg($expr,$value,$regs)){
04632                                         $this->message[$pos]['typePrefix'] = $regs[1];
04633                                         $this->message[$pos]['arrayTypePrefix'] = $regs[1];
04634                         if (isset($this->namespaces[$regs[1]])) {
04635                                 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
04636                         } else if (isset($attrs['xmlns:'.$regs[1]])) {
04637                                                 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
04638                         }
04639                                         $this->message[$pos]['arrayType'] = $regs[2];
04640                                         $this->message[$pos]['arraySize'] = $regs[3];
04641                                         $this->message[$pos]['arrayCols'] = $regs[4];
04642                                 }
04643                         }
04644                         // log id
04645                         if($key == 'id'){
04646                                 $this->ids[$value] = $pos;
04647                         }
04648                         // root
04649                         if($key_localpart == 'root' && $value == 1){
04650                                 $this->status = 'method';
04651                                 $this->root_struct_name = $name;
04652                                 $this->root_struct = $pos;
04653                                 $this->debug("found root struct $this->root_struct_name, pos $pos");
04654                         }
04655             // for doclit
04656             $attstr .= " $key=\"$value\"";
04657                 }
04658         // get namespace - must be done after namespace atts are processed
04659                 if(isset($prefix)){
04660                         $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
04661                         $this->default_namespace = $this->namespaces[$prefix];
04662                 } else {
04663                         $this->message[$pos]['namespace'] = $this->default_namespace;
04664                 }
04665         if($this->status == 'header'){
04666                 if ($this->root_header != $pos) {
04667                         $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
04668                 }
04669         } elseif($this->root_struct_name != ''){
04670                 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
04671         }
04672         }
04673 
04681         function end_element($parser, $name) {
04682                 // position of current element is equal to the last value left in depth_array for my depth
04683                 $pos = $this->depth_array[$this->depth--];
04684 
04685         // get element prefix
04686                 if(strpos($name,':')){
04687                         // get ns prefix
04688                         $prefix = substr($name,0,strpos($name,':'));
04689                         // get unqualified name
04690                         $name = substr(strstr($name,':'),1);
04691                 }
04692                 
04693                 // build to native type
04694                 if(isset($this->body_position) && $pos > $this->body_position){
04695                         // deal w/ multirefs
04696                         if(isset($this->message[$pos]['attrs']['href'])){
04697                                 // get id
04698                                 $id = substr($this->message[$pos]['attrs']['href'],1);
04699                                 // add placeholder to href array
04700                                 $this->multirefs[$id][$pos] = 'placeholder';
04701                                 // add set a reference to it as the result value
04702                                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
04703             // build complex values
04704                         } elseif($this->message[$pos]['children'] != ''){
04705                         
04706                                 // if result has already been generated (struct/array
04707                                 if(!isset($this->message[$pos]['result'])){
04708                                         $this->message[$pos]['result'] = $this->buildVal($pos);
04709                                 }
04710                                 
04711                         // set value of simple type
04712                         } else {
04713                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
04714                 if (isset($this->message[$pos]['type'])) {
04715                                         $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'] : '');
04716                                 } else {
04717                                         $parent = $this->message[$pos]['parent'];
04718                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
04719                                                 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
04720                                         } else {
04721                                                 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
04722                                         }
04723                                 }
04724 
04725                                 /* add value to parent's result, if parent is struct/array
04726                                 $parent = $this->message[$pos]['parent'];
04727                                 if($this->message[$parent]['type'] != 'map'){
04728                                         if(strtolower($this->message[$parent]['type']) == 'array'){
04729                                                 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
04730                                         } else {
04731                                                 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
04732                                         }
04733                                 }
04734                                 */
04735                         }
04736                 }
04737                 
04738         // for doclit
04739         if($this->status == 'header'){
04740                 if ($this->root_header != $pos) {
04741                         $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
04742                 }
04743         } elseif($pos >= $this->root_struct){
04744                 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
04745         }
04746                 // switch status
04747                 if($pos == $this->root_struct){
04748                         $this->status = 'body';
04749                         $this->root_struct_namespace = $this->message[$pos]['namespace'];
04750                 } elseif($name == 'Body'){
04751                         $this->status = 'envelope';
04752                  } elseif($name == 'Header'){
04753                         $this->status = 'envelope';
04754                 } elseif($name == 'Envelope'){
04755                         //
04756                 }
04757                 // set parent back to my parent
04758                 $this->parent = $this->message[$pos]['parent'];
04759         }
04760 
04768         function character_data($parser, $data){
04769                 $pos = $this->depth_array[$this->depth];
04770                 if ($this->xml_encoding=='UTF-8'){
04771                         // TODO: add an option to disable this for folks who want
04772                         // raw UTF-8 that, e.g., might not map to iso-8859-1
04773                         // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
04774                         if($this->decode_utf8){
04775                                 $data = utf8_decode($data);
04776                         }
04777                 }
04778         $this->message[$pos]['cdata'] .= $data;
04779         // for doclit
04780         if($this->status == 'header'){
04781                 $this->responseHeaders .= $data;
04782         } else {
04783                 $this->document .= $data;
04784         }
04785         }
04786 
04793         function get_response(){
04794                 return $this->soapresponse;
04795         }
04796 
04803         function getHeaders(){
04804             return $this->responseHeaders;
04805         }
04806 
04813         function decode_entities($text){
04814                 foreach($this->entities as $entity => $encoded){
04815                         $text = str_replace($encoded,$entity,$text);
04816                 }
04817                 return $text;
04818         }
04819 
04828         function decodeSimple($value, $type, $typens) {
04829                 // TODO: use the namespace!
04830                 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
04831                         return (string) $value;
04832                 }
04833                 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
04834                         return (int) $value;
04835                 }
04836                 if ($type == 'float' || $type == 'double' || $type == 'decimal') {
04837                         return (double) $value;
04838                 }
04839                 if ($type == 'boolean') {
04840                         if (strtolower($value) == 'false' || strtolower($value) == 'f') {
04841                                 return false;
04842                         }
04843                         return (boolean) $value;
04844                 }
04845                 if ($type == 'base64' || $type == 'base64Binary') {
04846                         return base64_decode($value);
04847                 }
04848                 // obscure numeric types
04849                 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
04850                         || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
04851                         || $type == 'unsignedInt'
04852                         || $type == 'unsignedShort' || $type == 'unsignedByte') {
04853                         return (int) $value;
04854                 }
04855                 // everything else
04856                 return (string) $value;
04857         }
04858 
04865         function buildVal($pos){
04866                 if(!isset($this->message[$pos]['type'])){
04867                         $this->message[$pos]['type'] = '';
04868                 }
04869                 $this->debug('inside buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
04870                 // if there are children...
04871                 if($this->message[$pos]['children'] != ''){
04872                         $children = explode('|',$this->message[$pos]['children']);
04873                         array_shift($children); // knock off empty
04874                         // md array
04875                         if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
04876                 $r=0; // rowcount
04877                 $c=0; // colcount
04878                 foreach($children as $child_pos){
04879                                         $this->debug("got an MD array element: $r, $c");
04880                                         $params[$r][] = $this->message[$child_pos]['result'];
04881                                     $c++;
04882                                     if($c == $this->message[$pos]['arrayCols']){
04883                                         $c = 0;
04884                                                 $r++;
04885                                     }
04886                 }
04887             // array
04888                         } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
04889                 $this->debug('adding array '.$this->message[$pos]['name']);
04890                 foreach($children as $child_pos){
04891                         $params[] = &$this->message[$child_pos]['result'];
04892                 }
04893             // apache Map type: java hashtable
04894             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
04895                 foreach($children as $child_pos){
04896                         $kv = explode("|",$this->message[$child_pos]['children']);
04897                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
04898                 }
04899             // generic compound type
04900             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
04901                     } else {
04902                         // Apache Vector type: treat as an array
04903                                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
04904                                         $notstruct = 1;
04905                                 } else {
04906                         // is array or struct?
04907                         foreach($children as $child_pos){
04908                                 if(isset($keys) && isset($keys[$this->message[$child_pos]['name']])){
04909                                         $notstruct = 1;
04910                                         break;
04911                                 }
04912                                 $keys[$this->message[$child_pos]['name']] = 1;
04913                         }
04914                     }
04915                 //
04916                 foreach($children as $child_pos){
04917                         if(isset($notstruct)){
04918                                 $params[] = &$this->message[$child_pos]['result'];
04919                         } else {
04920                                 if (isset($params[$this->message[$child_pos]['name']])) {
04921                                         // de-serialize repeated element name into an array
04922                                         if (!is_array($params[$this->message[$child_pos]['name']])) {
04923                                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
04924                                         }
04925                                         $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
04926                                 } else {
04927                                                 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
04928                                             }
04929                         }
04930                 }
04931                         }
04932                         return is_array($params) ? $params : array();
04933                 } else {
04934                 $this->debug('no children');
04935             if(strpos($this->message[$pos]['cdata'],'&')){
04936                         return  strtr($this->message[$pos]['cdata'],array_flip($this->entities));
04937             } else {
04938                 return $this->message[$pos]['cdata'];
04939             }
04940                 }
04941         }
04942 }
04943 
04944 
04945 
04946 ?><?php
04947 
04948 
04949 
04968 class soap_client extends nusoap_base  {
04969 
04970         var $username = '';
04971         var $password = '';
04972         var $authtype = '';
04973         var $requestHeaders = false;    // SOAP headers in request (text)
04974         var $responseHeaders = '';              // SOAP headers from response (incomplete namespace resolution) (text)
04975         var $document = '';                             // SOAP body response portion (incomplete namespace resolution) (text)
04976         var $endpoint;
04977         var $error_str = false;
04978     var $proxyhost = '';
04979     var $proxyport = '';
04980         var $proxyusername = '';
04981         var $proxypassword = '';
04982     var $xml_encoding = '';                     // character set encoding of incoming (response) messages
04983         var $http_encoding = false;
04984         var $timeout = 0;                               // HTTP connection timeout
04985         var $response_timeout = 30;             // HTTP response timeout
04986         var $endpointType = '';
04987         var $persistentConnection = false;
04988         var $defaultRpcParams = false;  // This is no longer used
04989         var $request = '';                              // HTTP request
04990         var $response = '';                             // HTTP response
04991         var $responseData = '';                 // SOAP payload of response
04992         // toggles whether the parser decodes element content w/ utf8_decode()
04993     var $decode_utf8 = true;
04994         
05004         var $fault, $faultcode, $faultstring, $faultdetail;
05005 
05020         function soap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){
05021                 $this->endpoint = $endpoint;
05022                 $this->proxyhost = $proxyhost;
05023                 $this->proxyport = $proxyport;
05024                 $this->proxyusername = $proxyusername;
05025                 $this->proxypassword = $proxypassword;
05026                 $this->timeout = $timeout;
05027                 $this->response_timeout = $response_timeout;
05028 
05029                 // make values
05030                 if($wsdl){
05031                         $this->endpointType = 'wsdl';
05032                         if (is_object($endpoint) && is_a($endpoint, 'wsdl')) {
05033                                 $this->wsdl = $endpoint;
05034                                 $this->endpoint = $this->wsdl->wsdl;
05035                                 $this->wsdlFile = $this->endpoint;
05036                                 $this->debug('existing wsdl instance created from ' . $this->endpoint);
05037                         } else {
05038                                 $this->wsdlFile = $this->endpoint;
05039                                 
05040                                 // instantiate wsdl object and parse wsdl file
05041                                 $this->debug('instantiating wsdl class with doc: '.$endpoint);
05042                                 $this->wsdl =& new wsdl($this->wsdlFile,$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout);
05043                         }
05044                         $this->debug("wsdl debug...\n".$this->wsdl->debug_str);
05045                         $this->wsdl->debug_str = '';
05046                         // catch errors
05047                         if($errstr = $this->wsdl->getError()){
05048                                 $this->debug('got wsdl error: '.$errstr);
05049                                 $this->setError('wsdl error: '.$errstr);
05050                         } elseif($this->operations = $this->wsdl->getOperations()){
05051                                 $this->debug( 'got '.count($this->operations).' operations from wsdl '.$this->wsdlFile);
05052                         } else {
05053                                 $this->debug( 'getOperations returned false');
05054                                 $this->setError('no operations defined in the WSDL document!');
05055                         }
05056                 }
05057         }
05058 
05084         function call($operation,$params=array(),$namespace='',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
05085                 $this->operation = $operation;
05086                 $this->fault = false;
05087                 $this->error_str = '';
05088                 $this->request = '';
05089                 $this->response = '';
05090                 $this->responseData = '';
05091                 $this->faultstring = '';
05092                 $this->faultcode = '';
05093                 $this->opData = array();
05094                 
05095                 $this->debug("call: $operation, $params, $namespace, $soapAction, $headers, $style, $use; endpointType: $this->endpointType");
05096                 if ($headers) {
05097                         $this->requestHeaders = $headers;
05098                 }
05099                 // serialize parameters
05100                 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
05101                         // use WSDL for operation
05102                         $this->opData = $opData;
05103                         foreach($opData as $key => $value){
05104                                 $this->debug("$key -> $value");
05105                         }
05106                         if (isset($opData['soapAction'])) {
05107                                 $soapAction = $opData['soapAction'];
05108                         }
05109                         $this->endpoint = $opData['endpoint'];
05110                         $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     ($namespace != '' ? $namespace : 'http://testuri.org');
05111                         $style = $opData['style'];
05112                         $use = $opData['input']['use'];
05113                         // add ns to ns array
05114                         if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
05115                                 $this->wsdl->namespaces['nu'] = $namespace;
05116             }
05117             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
05118                         // serialize payload
05119                         if (is_string($params)) {
05120                                 $this->debug("serializing param string for WSDL operation $operation");
05121                                 $payload = $params;
05122                         } elseif (is_array($params)) {
05123                                 $this->debug("serializing param array for WSDL operation $operation");
05124                                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params);
05125                         } else {
05126                                 $this->debug('params must be array or string');
05127                                 $this->setError('params must be array or string');
05128                                 return false;
05129                         }
05130             $usedNamespaces = $this->wsdl->usedNamespaces;
05131                         // Partial fix for multiple encoding styles in the same function call
05132                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
05133                         if (isset($opData['output']['encodingStyle']) && $encodingStyle != $opData['output']['encodingStyle']) {
05134                                 $methodEncodingStyle = ' SOAP-ENV:encodingStyle="' . $opData['output']['encodingStyle'] . '"';
05135                         } else {
05136                                 $methodEncodingStyle = '';
05137                         }
05138                         $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
05139                         $this->wsdl->debug_str = '';
05140                         if ($errstr = $this->wsdl->getError()) {
05141                                 $this->debug('got wsdl error: '.$errstr);
05142                                 $this->setError('wsdl error: '.$errstr);
05143                                 return false;
05144                         }
05145                 } elseif($this->endpointType == 'wsdl') {
05146                         // operation not in WSDL
05147                         $this->setError( 'operation '.$operation.' not present.');
05148                         $this->debug("operation '$operation' not present.");
05149                         $this->debug("wsdl debug: \n".$this->wsdl->debug_str);
05150                         $this->wsdl->debug_str = '';
05151                         return false;
05152                 } else {
05153                         // no WSDL
05154             if($namespace == ''){
05155                 $namespace = 'http://testuri.org';
05156             }
05157                         //$this->namespaces['ns1'] = $namespace;
05158                         $nsPrefix = 'ns1';
05159                         // serialize 
05160                         $payload = '';
05161                         if (is_string($params)) {
05162                                 $this->debug("serializing param string for operation $operation");
05163                                 $payload = $params;
05164                         } elseif (is_array($params)) {
05165                                 $this->debug("serializing param array for operation $operation");
05166                                 foreach($params as $k => $v){
05167                                         $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
05168                                 }
05169                         } else {
05170                                 $this->debug('params must be array or string');
05171                                 $this->setError('params must be array or string');
05172                                 return false;
05173                         }
05174                         $usedNamespaces = array();
05175                         $methodEncodingStyle = '';
05176                 }
05177                 // wrap RPC calls with method element
05178                 if ($style == 'rpc') {
05179                         if ($use == 'literal') {
05180                                 $this->debug("wrapping RPC request with literal method element");
05181                                 $payload = "<$operation xmlns=\"$namespace\">" . $payload . "</$operation>";
05182                         } else {
05183                                 $this->debug("wrapping RPC request with encoded method element");
05184                                 $payload = "<$nsPrefix:$operation$methodEncodingStyle xmlns:$nsPrefix=\"$namespace\">" .
05185                                                         $payload .
05186                                                         "</$nsPrefix:$operation>";
05187                         }
05188                 }
05189                 // serialize envelope
05190                 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use);
05191 //echo htmlentities($soapmsg)."<br><br>";
05192                 $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace, style: $style, use: $use");
05193                 $this->debug('SOAP message length: ' . strlen($soapmsg) . ' contents: ' . substr($soapmsg, 0, 1000));
05194                 // send
05195                 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
05196                 if($errstr = $this->getError()){
05197                         $this->debug('Error: '.$errstr);
05198                         return false;
05199                 } else {
05200                         $this->return = $return;
05201                         $this->debug('sent message successfully and got a(n) '.gettype($return).' back');
05202                         
05203                         // fault?
05204                         if(is_array($return) && isset($return['faultcode'])){
05205                                 $this->debug('got fault');
05206                                 $this->setError($return['faultcode'].': '.$return['faultstring']);
05207                                 $this->fault = true;
05208                                 foreach($return as $k => $v){
05209                                         $this->$k = $v;
05210                                         $this->debug("$k = $v<br>");
05211                                 }
05212                                 return $return;
05213                         } else {
05214                                 // array of return values
05215                                 if(is_array($return)){
05216                                         // multiple 'out' parameters
05217                                         if(sizeof($return) > 1){
05218                                                 return $return;
05219                                         }
05220                                         // single 'out' parameter
05221                                         return array_shift($return);
05222                                 // nothing returned (ie, echoVoid)
05223                                 } else {
05224                                         return "";
05225                                 }
05226                         }
05227                 }
05228         }
05229 
05237         function getOperationData($operation){
05238                 if(isset($this->operations[$operation])){
05239                         return $this->operations[$operation];
05240                 }
05241                 $this->debug("No data for operation: $operation");
05242         }
05243 
05258         function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
05259                 // detect transport
05260                 switch(true){
05261                         // http(s)
05262                         case ereg('^http',$this->endpoint):
05263                                 $this->debug('transporting via HTTP');
05264                                 if($this->persistentConnection == true && is_object($this->persistentConnection)){
05265                                         $http =& $this->persistentConnection;
05266                                 } else {
05267                                         $http = new soap_transport_http($this->endpoint);
05268                                         if ($this->persistentConnection) {
05269                                                 $http->usePersistentConnection();
05270                                         }
05271                                 }
05272                                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
05273                                 $http->setSOAPAction($soapaction);
05274                                 if($this->proxyhost && $this->proxyport){
05275                                         $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
05276                                 }
05277                 if($this->username != '' && $this->password != '') {
05278                                         $http->setCredentials($this->username, $this->password, $this->authtype);
05279                                 }
05280                                 if($this->http_encoding != ''){
05281                                         $http->setEncoding($this->http_encoding);
05282                                 }
05283                                 $this->debug('sending message, length: '.strlen($msg));
05284                                 if(ereg('^http:',$this->endpoint)){
05285                                 //if(strpos($this->endpoint,'http:')){
05286                                         $this->responseData = $http->send($msg,$timeout,$response_timeout);
05287                                 } elseif(ereg('^https',$this->endpoint)){
05288                                 //} elseif(strpos($this->endpoint,'https:')){
05289                                         //if(phpversion() == '4.3.0-dev'){
05290                                                 //$response = $http->send($msg,$timeout,$response_timeout);
05291                                 //$this->request = $http->outgoing_payload;
05292                                                 //$this->response = $http->incoming_payload;
05293                                         //} else
05294                                         if (extension_loaded('curl')) {
05295                                                 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout);
05296                                         } else {
05297                                                 $this->setError('CURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
05298                                         }                                                               
05299                                 } else {
05300                                         $this->setError('no http/s in endpoint url');
05301                                 }
05302                                 $this->request = $http->outgoing_payload;
05303                                 $this->response = $http->incoming_payload;
05304                                 $this->debug("transport debug data...\n".$http->debug_str);
05305                                 
05306                                 // save transport object if using persistent connections
05307                                 if ($this->persistentConnection) {
05308                                         $http->debug_str = '';
05309                                         if (!is_object($this->persistentConnection)) {
05310                                                 $this->persistentConnection = $http;
05311                                         }
05312                                 }
05313                                 
05314                                 if($err = $http->getError()){
05315                                         $this->setError('HTTP Error: '.$err);
05316                                         return false;
05317                                 } elseif($this->getError()){
05318                                         return false;
05319                                 } else {
05320                                         $this->debug('got response, length: '. strlen($this->responseData).' type: '.$http->incoming_headers['content-type']);
05321                                         return $this->parseResponse($http->incoming_headers, $this->responseData);
05322                                 }
05323                         break;
05324                         default:
05325                                 $this->setError('no transport found, or selected transport is not yet supported!');
05326                         return false;
05327                         break;
05328                 }
05329         }
05330 
05339     function parseResponse($headers, $data) {
05340                 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' and type ' . $headers['content-type']);
05341                 if (!strstr($headers['content-type'], 'text/xml')) {
05342 echo "-".$data."<br /><br />".htmlentities($data)."-";
05343                         $this->setError('Response not of type text/xml');
05344                         return false;
05345                 }
05346                 if (strpos($headers['content-type'], '=')) {
05347                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
05348                         $this->debug('Got response encoding: ' . $enc);
05349                         if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){
05350                                 $this->xml_encoding = strtoupper($enc);
05351                         } else {
05352                                 $this->xml_encoding = 'US-ASCII';
05353                         }
05354                 } else {
05355                         // should be US-ASCII, but for XML, let's be pragmatic and admit UTF-8 is most common
05356                         $this->xml_encoding = 'UTF-8';
05357                 }
05358                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating soap_parser');
05359                 $parser = new soap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
05360                 // add parser debug data to our debug
05361                 $this->debug($parser->debug_str);
05362                 // if parse errors
05363                 if($errstr = $parser->getError()){
05364                         $this->setError( $errstr);
05365                         // destroy the parser object
05366                         unset($parser);
05367                         return false;
05368                 } else {
05369                         // get SOAP headers
05370                         $this->responseHeaders = $parser->getHeaders();
05371                         // get decoded message
05372                         $return = $parser->get_response();
05373             // add document for doclit support
05374             $this->document = $parser->document;
05375                         // destroy the parser object
05376                         unset($parser);
05377                         // return decode message
05378                         return $return;
05379                 }
05380          }
05381 
05388         function setHeaders($headers){
05389                 $this->requestHeaders = $headers;
05390         }
05391 
05398         function getHeaders(){
05399             if($this->responseHeaders != '') {
05400                         return $this->responseHeaders;
05401             }
05402         }
05403 
05413         function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
05414                 $this->proxyhost = $proxyhost;
05415                 $this->proxyport = $proxyport;
05416                 $this->proxyusername = $proxyusername;
05417                 $this->proxypassword = $proxypassword;
05418         }
05419 
05428         function setCredentials($username, $password, $authtype = 'basic') {
05429                 $this->username = $username;
05430                 $this->password = $password;
05431                 $this->authtype = $authtype;
05432         }
05433         
05440         function setHTTPEncoding($enc='gzip, deflate'){
05441                 $this->http_encoding = $enc;
05442         }
05443         
05449         function useHTTPPersistentConnection(){
05450                 $this->persistentConnection = true;
05451         }
05452         
05463         function getDefaultRpcParams() {
05464                 return $this->defaultRpcParams;
05465         }
05466 
05475         function setDefaultRpcParams($rpcParams) {
05476                 $this->defaultRpcParams = $rpcParams;
05477         }
05478         
05485         function getProxy(){
05486                 $evalStr = '';
05487                 foreach($this->operations as $operation => $opData){
05488                         if($operation != ''){
05489                                 // create param string
05490                                 $paramStr = '';
05491                                 if(sizeof($opData['input']['parts']) > 0){
05492                                         foreach($opData['input']['parts'] as $name => $type){
05493                                                 $paramStr .= "\$$name,";
05494                                         }
05495                                         $paramStr = substr($paramStr,0,strlen($paramStr)-1);
05496                                 }
05497                                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
05498                                 $evalStr .= "function $operation ($paramStr){
05499                                         // load params into array
05500                                         \$params = array($paramStr);
05501                                         return \$this->call('$operation',\$params,'".$opData['namespace']."','".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
05502                                 }";
05503                                 unset($paramStr);
05504                         }
05505                 }
05506                 $r = rand();
05507                 $evalStr = 'class soap_proxy_'.$r.' extends soap_client {
05508                                 '.$evalStr.'
05509                         }';
05510                 //print "proxy class:<pre>$evalStr</pre>";
05511                 // eval the class
05512                 eval($evalStr);
05513                 // instantiate proxy object
05514                 eval("\$proxy = new soap_proxy_$r('');");
05515                 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
05516                 $proxy->endpointType = 'wsdl';
05517                 $proxy->wsdlFile = $this->wsdlFile;
05518                 $proxy->wsdl = $this->wsdl;
05519                 $proxy->operations = $this->operations;
05520                 $proxy->defaultRpcParams = $this->defaultRpcParams;
05521                 // transfer other state
05522                 $proxy->username = $this->username;
05523                 $proxy->password = $this->password;
05524                 $proxy->proxyhost = $this->proxyhost;
05525                 $proxy->proxyport = $this->proxyport;
05526                 $proxy->proxyusername = $this->proxyusername;
05527                 $proxy->proxypassword = $this->proxypassword;
05528                 $proxy->timeout = $this->timeout;
05529                 $proxy->response_timeout = $this->response_timeout;
05530                 $proxy->http_encoding = $this->http_encoding;
05531                 $proxy->persistentConnection = $this->persistentConnection;
05532                 return $proxy;
05533         }
05534 
05542         function getHTTPBody($soapmsg) {
05543                 return $soapmsg;
05544         }
05545         
05554         function getHTTPContentType() {
05555                 return 'text/xml';
05556         }
05557         
05567         function getHTTPContentTypeCharset() {
05568                 return $this->soap_defencoding;
05569         }
05570 
05571         /*
05572         * whether or not parser should decode utf8 element content
05573     *
05574     * @return   always returns true
05575     * @access   public
05576     */
05577     function decodeUTF8($bool){
05578                 $this->decode_utf8 = $bool;
05579                 return true;
05580     }
05581 }
05582 ?>

Generated on Fri Dec 13 2013 13:52:12 for ILIAS Release_3_7_x_branch .rev 46817 by  doxygen 1.7.1