Documentation TYPO3 par Ameos

class.nusoap.php

00001 <?php
00002 /*
00003 $Id: class.nusoap.php 1421 2006-04-10 09:27:15Z mundaun $
00004 
00005 NuSOAP - Web Services Toolkit for PHP
00006 
00007 Copyright (c) 2002 NuSphere Corporation
00008 
00009 This library is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU Lesser General Public
00011 License as published by the Free Software Foundation; either
00012 version 2.1 of the License, or (at your option) any later version.
00013 
00014 This library is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public
00020 License along with this library; if not, write to the Free Software
00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 §§§§§
00023 If you have any questions or comments, please email:
00024 
00025 Dietrich Ayala
00026 dietrich@ganx4.com
00027 http://dietrich.ganx4.com/nusoap
00028 
00029 NuSphere Corporation
00030 http://www.nusphere.com
00031 
00032 */
00033 
00034 /* load classes
00035 
00036 // necessary classes
00037 require_once('class.soapclient.php');
00038 require_once('class.soap_val.php');
00039 require_once('class.soap_parser.php');
00040 require_once('class.soap_fault.php');
00041 
00042 // transport classes
00043 require_once('class.soap_transport_http.php');
00044 
00045 // optional add-on classes
00046 require_once('class.xmlschema.php');
00047 require_once('class.wsdl.php');
00048 */
00049 
00050 // class variable emulation
00051 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
00052 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
00053 
00062 class nusoap_base {
00069         var $title = 'NuSOAP';
00076         var $version = '0.7.2';
00083         var $revision = '$Revision: 1421 $';
00090         var $error_str = '';
00097     var $debug_str = '';
00105         var $charencoding = true;
00112         var $debugLevel;
00113 
00120         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
00121 
00128     var $soap_defencoding = 'ISO-8859-1';
00129         //var $soap_defencoding = 'UTF-8';
00130 
00139         var $namespaces = array(
00140                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
00141                 'xsd' => 'http://www.w3.org/2001/XMLSchema',
00142                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
00143                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
00144                 );
00145 
00152         var $usedNamespaces = array();
00153 
00161         var $typemap = array(
00162         'http://www.w3.org/2001/XMLSchema' => array(
00163                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
00164                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
00165                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
00166                 // abstract "any" types
00167                 'anyType'=>'string','anySimpleType'=>'string',
00168                 // derived datatypes
00169                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
00170                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
00171                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
00172                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
00173         'http://www.w3.org/2000/10/XMLSchema' => array(
00174                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00175                 'float'=>'double','dateTime'=>'string',
00176                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00177         'http://www.w3.org/1999/XMLSchema' => array(
00178                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
00179                 'float'=>'double','dateTime'=>'string',
00180                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
00181         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
00182         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
00183     'http://xml.apache.org/xml-soap' => array('Map')
00184         );
00185 
00194         var $xmlEntities = array('quot' => '"','amp' => '&',
00195                 'lt' => '<','gt' => '>','apos' => "'");
00196 
00202         function nusoap_base() {
00203                 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
00204         }
00205 
00212         function getGlobalDebugLevel() {
00213                 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
00214         }
00215 
00222         function setGlobalDebugLevel($level) {
00223                 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
00224         }
00225 
00232         function getDebugLevel() {
00233                 return $this->debugLevel;
00234         }
00235 
00242         function setDebugLevel($level) {
00243                 $this->debugLevel = $level;
00244         }
00245 
00252         function debug($string){
00253                 if ($this->debugLevel > 0) {
00254                         $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
00255                 }
00256         }
00257 
00264         function appendDebug($string){
00265                 if ($this->debugLevel > 0) {
00266                         // it would be nice to use a memory stream here to use
00267                         // memory more efficiently
00268                         $this->debug_str .= $string;
00269                 }
00270         }
00271 
00277         function clearDebug() {
00278                 // it would be nice to use a memory stream here to use
00279                 // memory more efficiently
00280                 $this->debug_str = '';
00281         }
00282 
00289         function &getDebug() {
00290                 // it would be nice to use a memory stream here to use
00291                 // memory more efficiently
00292                 return $this->debug_str;
00293         }
00294 
00302         function &getDebugAsXMLComment() {
00303                 // it would be nice to use a memory stream here to use
00304                 // memory more efficiently
00305                 while (strpos($this->debug_str, '--')) {
00306                         $this->debug_str = str_replace('--', '- -', $this->debug_str);
00307                 }
00308         return "<!--\n" . $this->debug_str . "\n-->";
00309         }
00310 
00317         function expandEntities($val) {
00318                 if ($this->charencoding) {
00319                 $val = str_replace('&', '&amp;', $val);
00320                 $val = str_replace("'", '&apos;', $val);
00321                 $val = str_replace('"', '&quot;', $val);
00322                 $val = str_replace('<', '&lt;', $val);
00323                 $val = str_replace('>', '&gt;', $val);
00324             }
00325             return $val;
00326         }
00327 
00334         function getError(){
00335                 if($this->error_str != ''){
00336                         return $this->error_str;
00337                 }
00338                 return false;
00339         }
00340 
00347         function setError($str){
00348                 $this->error_str = $str;
00349         }
00350 
00358         function isArraySimpleOrStruct($val) {
00359         $keyList = array_keys($val);
00360                 foreach ($keyList as $keyListValue) {
00361                         if (!is_int($keyListValue)) {
00362                                 return 'arrayStruct';
00363                         }
00364                 }
00365                 return 'arraySimple';
00366         }
00367 
00382         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
00383                 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
00384                 $this->appendDebug('value=' . $this->varDump($val));
00385                 $this->appendDebug('attributes=' . $this->varDump($attributes));
00386 
00387         if(is_object($val) && get_class($val) == 'soapval'){
00388                 return $val->serialize($use);
00389         }
00390                 // force valid name if necessary
00391                 if (is_numeric($name)) {
00392                         $name = '__numeric_' . $name;
00393                 } elseif (! $name) {
00394                         $name = 'noname';
00395                 }
00396                 // if name has ns, add ns prefix to name
00397                 $xmlns = '';
00398         if($name_ns){
00399                         $prefix = 'nu'.rand(1000,9999);
00400                         $name = $prefix.':'.$name;
00401                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";
00402                 }
00403                 // if type is prefixed, create type prefix
00404                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
00405                         // need to fix this. shouldn't default to xsd if no ns specified
00406                     // w/o checking against typemap
00407                         $type_prefix = 'xsd';
00408                 } elseif($type_ns){
00409                         $type_prefix = 'ns'.rand(1000,9999);
00410                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
00411                 }
00412                 // serialize attributes if present
00413                 $atts = '';
00414                 if($attributes){
00415                         foreach($attributes as $k => $v){
00416                                 $atts .= " $k=\"".$this->expandEntities($v).'"';
00417                         }
00418                 }
00419                 // serialize null value
00420                 if (is_null($val)) {
00421                         if ($use == 'literal') {
00422                                 // TODO: depends on minOccurs
00423                         return "<$name$xmlns $atts/>";
00424                 } else {
00425                                 if (isset($type) && isset($type_prefix)) {
00426                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00427                                 } else {
00428                                         $type_str = '';
00429                                 }
00430                         return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
00431                 }
00432                 }
00433         // serialize if an xsd built-in primitive type
00434         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
00435                 if (is_bool($val)) {
00436                         if ($type == 'boolean') {
00437                                 $val = $val ? 'true' : 'false';
00438                         } elseif (! $val) {
00439                                 $val = 0;
00440                         }
00441                         } else if (is_string($val)) {
00442                                 $val = $this->expandEntities($val);
00443                         }
00444                         if ($use == 'literal') {
00445                         return "<$name$xmlns $atts>$val</$name>";
00446                 } else {
00447                         return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>";
00448                 }
00449         }
00450                 // detect type and serialize
00451                 $xml = '';
00452                 switch(true) {
00453                         case (is_bool($val) || $type == 'boolean'):
00454                         if ($type == 'boolean') {
00455                                 $val = $val ? 'true' : 'false';
00456                         } elseif (! $val) {
00457                                 $val = 0;
00458                         }
00459                                 if ($use == 'literal') {
00460                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00461                                 } else {
00462                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
00463                                 }
00464                                 break;
00465                         case (is_int($val) || is_long($val) || $type == 'int'):
00466                                 if ($use == 'literal') {
00467                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00468                                 } else {
00469                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
00470                                 }
00471                                 break;
00472                         case (is_float($val)|| is_double($val) || $type == 'float'):
00473                                 if ($use == 'literal') {
00474                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00475                                 } else {
00476                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
00477                                 }
00478                                 break;
00479                         case (is_string($val) || $type == 'string'):
00480                                 $val = $this->expandEntities($val);
00481                                 if ($use == 'literal') {
00482                                         $xml .= "<$name$xmlns $atts>$val</$name>";
00483                                 } else {
00484                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
00485                                 }
00486                                 break;
00487                         case is_object($val):
00488                                 if (! $name) {
00489                                         $name = get_class($val);
00490                                         $this->debug("In serialize_val, used class name $name as element name");
00491                                 } else {
00492                                         $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
00493                                 }
00494                                 foreach(get_object_vars($val) as $k => $v){
00495                                         $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
00496                                 }
00497                                 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
00498                                 break;
00499                         break;
00500                         case (is_array($val) || $type):
00501                                 // detect if struct or array
00502                                 $valueType = $this->isArraySimpleOrStruct($val);
00503                 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
00504                                         $i = 0;
00505                                         if(is_array($val) && count($val)> 0){
00506                                                 foreach($val as $v){
00507                                 if(is_object($v) && get_class($v) ==  'soapval'){
00508                                                                 $tt_ns = $v->type_ns;
00509                                                                 $tt = $v->type;
00510                                                         } elseif (is_array($v)) {
00511                                                                 $tt = $this->isArraySimpleOrStruct($v);
00512                                                         } else {
00513                                                                 $tt = gettype($v);
00514                                 }
00515                                                         $array_types[$tt] = 1;
00516                                                         // TODO: for literal, the name should be $name
00517                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
00518                                                         ++$i;
00519                                                 }
00520                                                 if(count($array_types) > 1){
00521                                                         $array_typename = 'xsd:anyType';
00522                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
00523                                                         if ($tt == 'integer') {
00524                                                                 $tt = 'int';
00525                                                         }
00526                                                         $array_typename = 'xsd:'.$tt;
00527                                                 } elseif(isset($tt) && $tt == 'arraySimple'){
00528                                                         $array_typename = 'SOAP-ENC:Array';
00529                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){
00530                                                         $array_typename = 'unnamed_struct_use_soapval';
00531                                                 } else {
00532                                                         // if type is prefixed, create type prefix
00533                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
00534                                                                  $array_typename = 'xsd:' . $tt;
00535                                                         } elseif ($tt_ns) {
00536                                                                 $tt_prefix = 'ns' . rand(1000, 9999);
00537                                                                 $array_typename = "$tt_prefix:$tt";
00538                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
00539                                                         } else {
00540                                                                 $array_typename = $tt;
00541                                                         }
00542                                                 }
00543                                                 $array_type = $i;
00544                                                 if ($use == 'literal') {
00545                                                         $type_str = '';
00546                                                 } else if (isset($type) && isset($type_prefix)) {
00547                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00548                                                 } else {
00549                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
00550                                                 }
00551                                         // empty array
00552                                         } else {
00553                                                 if ($use == 'literal') {
00554                                                         $type_str = '';
00555                                                 } else if (isset($type) && isset($type_prefix)) {
00556                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
00557                                                 } else {
00558                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
00559                                                 }
00560                                         }
00561                                         // TODO: for array in literal, there is no wrapper here
00562                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
00563                                 } else {
00564                                         // got a struct
00565                                         if(isset($type) && isset($type_prefix)){
00566                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";
00567                                         } else {
00568                                                 $type_str = '';
00569                                         }
00570                                         if ($use == 'literal') {
00571                                                 $xml .= "<$name$xmlns $atts>";
00572                                         } else {
00573                                                 $xml .= "<$name$xmlns$type_str$atts>";
00574                                         }
00575                                         foreach($val as $k => $v){
00576                                                 // Apache Map
00577                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
00578                                                         $xml .= '<item>';
00579                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
00580                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
00581                                                         $xml .= '</item>';
00582                                                 } else {
00583                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
00584                                                 }
00585                                         }
00586                                         $xml .= "</$name>";
00587                                 }
00588                                 break;
00589                         default:
00590                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
00591                                 break;
00592                 }
00593                 return $xml;
00594         }
00595 
00608     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
00609     // TODO: add an option to automatically run utf8_encode on $body and $headers
00610     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
00611     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
00612 
00613         $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
00614         $this->debug("headers:");
00615         $this->appendDebug($this->varDump($headers));
00616         $this->debug("namespaces:");
00617         $this->appendDebug($this->varDump($namespaces));
00618 
00619         // serialize namespaces
00620     $ns_string = '';
00621         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
00622                 $ns_string .= " xmlns:$k=\"$v\"";
00623         }
00624         if($encodingStyle) {
00625                 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
00626         }
00627 
00628         // serialize headers
00629         if($headers){
00630                 if (is_array($headers)) {
00631                         $xml = '';
00632                         foreach ($headers as $header) {
00633                                 $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
00634                         }
00635                         $headers = $xml;
00636                         $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
00637                 }
00638                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
00639         }
00640         // serialize envelope
00641         return
00642         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
00643         '<SOAP-ENV:Envelope'.$ns_string.">".
00644         $headers.
00645         "<SOAP-ENV:Body>".
00646                 $body.
00647         "</SOAP-ENV:Body>".
00648         "</SOAP-ENV:Envelope>";
00649     }
00650 
00659     function formatDump($str){
00660                 $str = htmlspecialchars($str);
00661                 return nl2br($str);
00662     }
00663 
00671         function contractQname($qname){
00672                 // get element namespace
00673                 //$this->xdebug("Contract $qname");
00674                 if (strrpos($qname, ':')) {
00675                         // get unqualified name
00676                         $name = substr($qname, strrpos($qname, ':') + 1);
00677                         // get ns
00678                         $ns = substr($qname, 0, strrpos($qname, ':'));
00679                         $p = $this->getPrefixFromNamespace($ns);
00680                         if ($p) {
00681                                 return $p . ':' . $name;
00682                         }
00683                         return $qname;
00684                 } else {
00685                         return $qname;
00686                 }
00687         }
00688 
00696         function expandQname($qname){
00697                 // get element prefix
00698                 if(strpos($qname,':') && !ereg('^http://',$qname)){
00699                         // get unqualified name
00700                         $name = substr(strstr($qname,':'),1);
00701                         // get ns prefix
00702                         $prefix = substr($qname,0,strpos($qname,':'));
00703                         if(isset($this->namespaces[$prefix])){
00704                                 return $this->namespaces[$prefix].':'.$name;
00705                         } else {
00706                                 return $qname;
00707                         }
00708                 } else {
00709                         return $qname;
00710                 }
00711         }
00712 
00721         function getLocalPart($str){
00722                 if($sstr = strrchr($str,':')){
00723                         // get unqualified name
00724                         return substr( $sstr, 1 );
00725                 } else {
00726                         return $str;
00727                 }
00728         }
00729 
00738         function getPrefix($str){
00739                 if($pos = strrpos($str,':')){
00740                         // get prefix
00741                         return substr($str,0,$pos);
00742                 }
00743                 return false;
00744         }
00745 
00753         function getNamespaceFromPrefix($prefix){
00754                 if (isset($this->namespaces[$prefix])) {
00755                         return $this->namespaces[$prefix];
00756                 }
00757                 //$this->setError("No namespace registered for prefix '$prefix'");
00758                 return false;
00759         }
00760 
00769         function getPrefixFromNamespace($ns) {
00770                 foreach ($this->namespaces as $p => $n) {
00771                         if ($ns == $n || $ns == $p) {
00772                             $this->usedNamespaces[$p] = $n;
00773                                 return $p;
00774                         }
00775                 }
00776                 return false;
00777         }
00778 
00785         function getmicrotime() {
00786                 if (function_exists('gettimeofday')) {
00787                         $tod = gettimeofday();
00788                         $sec = $tod['sec'];
00789                         $usec = $tod['usec'];
00790                 } else {
00791                         $sec = time();
00792                         $usec = 0;
00793                 }
00794                 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
00795         }
00796 
00804     function varDump($data) {
00805                 ob_start();
00806                 var_dump($data);
00807                 $ret_val = ob_get_contents();
00808                 ob_end_clean();
00809                 return $ret_val;
00810         }
00811 }
00812 
00813 // XML Schema Datatype Helper Functions
00814 
00815 //xsd:dateTime helpers
00816 
00823 function timestamp_to_iso8601($timestamp,$utc=true){
00824         $datestr = date('Y-m-d\TH:i:sO',$timestamp);
00825         if($utc){
00826                 $eregStr =
00827                 '([0-9]{4})-'.  // centuries & years CCYY-
00828                 '([0-9]{2})-'.  // months MM-
00829                 '([0-9]{2})'.   // days DD
00830                 'T'.                    // separator T
00831                 '([0-9]{2}):'.  // hours hh:
00832                 '([0-9]{2}):'.  // minutes mm:
00833                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
00834                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00835 
00836                 if(ereg($eregStr,$datestr,$regs)){
00837                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
00838                 }
00839                 return false;
00840         } else {
00841                 return $datestr;
00842         }
00843 }
00844 
00851 function iso8601_to_timestamp($datestr){
00852         $eregStr =
00853         '([0-9]{4})-'.  // centuries & years CCYY-
00854         '([0-9]{2})-'.  // months MM-
00855         '([0-9]{2})'.   // days DD
00856         'T'.                    // separator T
00857         '([0-9]{2}):'.  // hours hh:
00858         '([0-9]{2}):'.  // minutes mm:
00859         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
00860         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
00861         if(ereg($eregStr,$datestr,$regs)){
00862                 // not utc
00863                 if($regs[8] != 'Z'){
00864                         $op = substr($regs[8],0,1);
00865                         $h = substr($regs[8],1,2);
00866                         $m = substr($regs[8],strlen($regs[8])-2,2);
00867                         if($op == '-'){
00868                                 $regs[4] = $regs[4] + $h;
00869                                 $regs[5] = $regs[5] + $m;
00870                         } elseif($op == '+'){
00871                                 $regs[4] = $regs[4] - $h;
00872                                 $regs[5] = $regs[5] - $m;
00873                         }
00874                 }
00875                 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
00876         } else {
00877                 return false;
00878         }
00879 }
00880 
00888 function usleepWindows($usec)
00889 {
00890         $start = gettimeofday();
00891 
00892         do
00893         {
00894                 $stop = gettimeofday();
00895                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
00896                 + $stop['usec'] - $start['usec'];
00897         }
00898         while ($timePassed < $usec);
00899 }
00900 
00901 
00902 
00911 class soap_fault extends nusoap_base {
00917         var $faultcode;
00923         var $faultactor;
00929         var $faultstring;
00935         var $faultdetail;
00936 
00945         function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
00946                 parent::nusoap_base();
00947                 $this->faultcode = $faultcode;
00948                 $this->faultactor = $faultactor;
00949                 $this->faultstring = $faultstring;
00950                 $this->faultdetail = $faultdetail;
00951         }
00952 
00959         function serialize(){
00960                 $ns_string = '';
00961                 foreach($this->namespaces as $k => $v){
00962                         $ns_string .= "\n  xmlns:$k=\"$v\"";
00963                 }
00964                 $return_msg =
00965                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
00966                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
00967                                 '<SOAP-ENV:Body>'.
00968                                 '<SOAP-ENV:Fault>'.
00969                                         $this->serialize_val($this->faultcode, 'faultcode').
00970                                         $this->serialize_val($this->faultactor, 'faultactor').
00971                                         $this->serialize_val($this->faultstring, 'faultstring').
00972                                         $this->serialize_val($this->faultdetail, 'detail').
00973                                 '</SOAP-ENV:Fault>'.
00974                                 '</SOAP-ENV:Body>'.
00975                         '</SOAP-ENV:Envelope>';
00976                 return $return_msg;
00977         }
00978 }
00979 
00980 
00981 
00993 class XMLSchema extends nusoap_base  {
00994 
00995         // files
00996         var $schema = '';
00997         var $xml = '';
00998         // namespaces
00999         var $enclosingNamespaces;
01000         // schema info
01001         var $schemaInfo = array();
01002         var $schemaTargetNamespace = '';
01003         // types, elements, attributes defined by the schema
01004         var $attributes = array();
01005         var $complexTypes = array();
01006         var $complexTypeStack = array();
01007         var $currentComplexType = null;
01008         var $elements = array();
01009         var $elementStack = array();
01010         var $currentElement = null;
01011         var $simpleTypes = array();
01012         var $simpleTypeStack = array();
01013         var $currentSimpleType = null;
01014         // imports
01015         var $imports = array();
01016         // parser vars
01017         var $parser;
01018         var $position = 0;
01019         var $depth = 0;
01020         var $depth_array = array();
01021         var $message = array();
01022         var $defaultNamespace = array();
01023 
01032         function XMLSchema($schema='',$xml='',$namespaces=array()){
01033                 parent::nusoap_base();
01034                 $this->debug('xmlschema class instantiated, inside constructor');
01035                 // files
01036                 $this->schema = $schema;
01037                 $this->xml = $xml;
01038 
01039                 // namespaces
01040                 $this->enclosingNamespaces = $namespaces;
01041                 $this->namespaces = array_merge($this->namespaces, $namespaces);
01042 
01043                 // parse schema file
01044                 if($schema != ''){
01045                         $this->debug('initial schema file: '.$schema);
01046                         $this->parseFile($schema, 'schema');
01047                 }
01048 
01049                 // parse xml file
01050                 if($xml != ''){
01051                         $this->debug('initial xml file: '.$xml);
01052                         $this->parseFile($xml, 'xml');
01053                 }
01054 
01055         }
01056 
01065         function parseFile($xml,$type){
01066                 // parse xml file
01067                 if($xml != ""){
01068                         $xmlStr = @join("",@file($xml));
01069                         if($xmlStr == ""){
01070                                 $msg = 'Error reading XML from '.$xml;
01071                                 $this->setError($msg);
01072                                 $this->debug($msg);
01073                         return false;
01074                         } else {
01075                                 $this->debug("parsing $xml");
01076                                 $this->parseString($xmlStr,$type);
01077                                 $this->debug("done parsing $xml");
01078                         return true;
01079                         }
01080                 }
01081                 return false;
01082         }
01083 
01091         function parseString($xml,$type){
01092                 // parse xml string
01093                 if($xml != ""){
01094 
01095                 // Create an XML parser.
01096                 $this->parser = xml_parser_create();
01097                 // Set the options for parsing the XML data.
01098                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
01099 
01100                 // Set the object for the parser.
01101                 xml_set_object($this->parser, $this);
01102 
01103                 // Set the element handlers for the parser.
01104                         if($type == "schema"){
01105                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
01106                         xml_set_character_data_handler($this->parser,'schemaCharacterData');
01107                         } elseif($type == "xml"){
01108                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
01109                         xml_set_character_data_handler($this->parser,'xmlCharacterData');
01110                         }
01111 
01112                     // Parse the XML file.
01113                     if(!xml_parse($this->parser,$xml,true)){
01114                         // Display an error message.
01115                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
01116                                 xml_get_current_line_number($this->parser),
01117                                 xml_error_string(xml_get_error_code($this->parser))
01118                                 );
01119                                 $this->debug($errstr);
01120                                 $this->debug("XML payload:\n" . $xml);
01121                                 $this->setError($errstr);
01122                 }
01123 
01124                         xml_parser_free($this->parser);
01125                 } else{
01126                         $this->debug('no xml passed to parseString()!!');
01127                         $this->setError('no xml passed to parseString()!!');
01128                 }
01129         }
01130 
01139         function schemaStartElement($parser, $name, $attrs) {
01140 
01141                 // position in the total number of elements, starting from 0
01142                 $pos = $this->position++;
01143                 $depth = $this->depth++;
01144                 // set self as current value for this depth
01145                 $this->depth_array[$depth] = $pos;
01146                 $this->message[$pos] = array('cdata' => '');
01147                 if ($depth > 0) {
01148                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
01149                 } else {
01150                         $this->defaultNamespace[$pos] = false;
01151                 }
01152 
01153                 // get element prefix
01154                 if($prefix = $this->getPrefix($name)){
01155                         // get unqualified name
01156                         $name = $this->getLocalPart($name);
01157                 } else {
01158                 $prefix = '';
01159         }
01160 
01161         // loop thru attributes, expanding, and registering namespace declarations
01162         if(count($attrs) > 0){
01163                 foreach($attrs as $k => $v){
01164                 // if ns declarations, add to class level array of valid namespaces
01165                                 if(ereg("^xmlns",$k)){
01166                         //$this->xdebug("$k: $v");
01167                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
01168                         if($ns_prefix = substr(strrchr($k,':'),1)){
01169                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");
01170                                                 $this->namespaces[$ns_prefix] = $v;
01171                                         } else {
01172                                                 $this->defaultNamespace[$pos] = $v;
01173                                                 if (! $this->getPrefixFromNamespace($v)) {
01174                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
01175                                                 }
01176                                         }
01177                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
01178                                                 $this->XMLSchemaVersion = $v;
01179                                                 $this->namespaces['xsi'] = $v.'-instance';
01180                                         }
01181                                 }
01182                 }
01183                 foreach($attrs as $k => $v){
01184                 // expand each attribute
01185                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
01186                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
01187                         $eAttrs[$k] = $v;
01188                 }
01189                 $attrs = $eAttrs;
01190         } else {
01191                 $attrs = array();
01192         }
01193                 // find status, register data
01194                 switch($name){
01195                         case 'all':                     // (optional) compositor content for a complexType
01196                         case 'choice':
01197                         case 'group':
01198                         case 'sequence':
01199                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
01200                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
01201                                 //if($name == 'all' || $name == 'sequence'){
01202                                 //      $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01203                                 //}
01204                         break;
01205                         case 'attribute':       // complexType attribute
01206                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
01207                 $this->xdebug("parsing attribute:");
01208                 $this->appendDebug($this->varDump($attrs));
01209                                 if (!isset($attrs['form'])) {
01210                                         $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
01211                                 }
01212                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01213                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01214                                         if (!strpos($v, ':')) {
01215                                                 // no namespace in arrayType attribute value...
01216                                                 if ($this->defaultNamespace[$pos]) {
01217                                                         // ...so use the default
01218                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01219                                                 }
01220                                         }
01221                 }
01222                 if(isset($attrs['name'])){
01223                                         $this->attributes[$attrs['name']] = $attrs;
01224                                         $aname = $attrs['name'];
01225                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
01226                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
01227                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01228                         } else {
01229                                 $aname = '';
01230                         }
01231                                 } elseif(isset($attrs['ref'])){
01232                                         $aname = $attrs['ref'];
01233                     $this->attributes[$attrs['ref']] = $attrs;
01234                                 }
01235 
01236                                 if($this->currentComplexType){  // This should *always* be
01237                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
01238                                 }
01239                                 // arrayType attribute
01240                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
01241                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01242                         $prefix = $this->getPrefix($aname);
01243                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
01244                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
01245                                         } else {
01246                                                 $v = '';
01247                                         }
01248                     if(strpos($v,'[,]')){
01249                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
01250                     }
01251                     $v = substr($v,0,strpos($v,'[')); // clip the []
01252                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
01253                         $v = $this->XMLSchemaVersion.':'.$v;
01254                     }
01255                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
01256                                 }
01257                         break;
01258                         case 'complexContent':  // (optional) content for a complexType
01259                         break;
01260                         case 'complexType':
01261                                 array_push($this->complexTypeStack, $this->currentComplexType);
01262                                 if(isset($attrs['name'])){
01263                                         $this->xdebug('processing named complexType '.$attrs['name']);
01264                                         //$this->currentElement = false;
01265                                         $this->currentComplexType = $attrs['name'];
01266                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01267                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01268                                         // This is for constructs like
01269                                         //           <complexType name="ListOfString" base="soap:Array">
01270                                         //                <sequence>
01271                                         //                    <element name="string" type="xsd:string"
01272                                         //                        minOccurs="0" maxOccurs="unbounded" />
01273                                         //                </sequence>
01274                                         //            </complexType>
01275                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01276                                                 $this->xdebug('complexType is unusual array');
01277                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01278                                         } else {
01279                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01280                                         }
01281                                 }else{
01282                                         $this->xdebug('processing unnamed complexType for element '.$this->currentElement);
01283                                         $this->currentComplexType = $this->currentElement . '_ContainedType';
01284                                         //$this->currentElement = false;
01285                                         $this->complexTypes[$this->currentComplexType] = $attrs;
01286                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
01287                                         // This is for constructs like
01288                                         //           <complexType name="ListOfString" base="soap:Array">
01289                                         //                <sequence>
01290                                         //                    <element name="string" type="xsd:string"
01291                                         //                        minOccurs="0" maxOccurs="unbounded" />
01292                                         //                </sequence>
01293                                         //            </complexType>
01294                                         if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){
01295                                                 $this->xdebug('complexType is unusual array');
01296                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01297                                         } else {
01298                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
01299                                         }
01300                                 }
01301                         break;
01302                         case 'element':
01303                                 array_push($this->elementStack, $this->currentElement);
01304                                 // elements defined as part of a complex type should
01305                                 // not really be added to $this->elements, but for some
01306                                 // reason, they are
01307                                 if (!isset($attrs['form'])) {
01308                                         $attrs['form'] = $this->schemaInfo['elementFormDefault'];
01309                                 }
01310                                 if(isset($attrs['type'])){
01311                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
01312                                         if (! $this->getPrefix($attrs['type'])) {
01313                                                 if ($this->defaultNamespace[$pos]) {
01314                                                         $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
01315                                                         $this->xdebug('used default namespace to make type ' . $attrs['type']);
01316                                                 }
01317                                         }
01318                                         // This is for constructs like
01319                                         //           <complexType name="ListOfString" base="soap:Array">
01320                                         //                <sequence>
01321                                         //                    <element name="string" type="xsd:string"
01322                                         //                        minOccurs="0" maxOccurs="unbounded" />
01323                                         //                </sequence>
01324                                         //            </complexType>
01325                                         if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
01326                                                 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
01327                                                 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
01328                                         }
01329                                         $this->currentElement = $attrs['name'];
01330                                         $this->elements[ $attrs['name'] ] = $attrs;
01331                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01332                                         $ename = $attrs['name'];
01333                                 } elseif(isset($attrs['ref'])){
01334                                         $this->xdebug("processing element as ref to ".$attrs['ref']);
01335                                         $this->currentElement = "ref to ".$attrs['ref'];
01336                                         $ename = $this->getLocalPart($attrs['ref']);
01337                                 } else {
01338                                         $this->xdebug("processing untyped element ".$attrs['name']);
01339                                         $this->currentElement = $attrs['name'];
01340                                         $this->elements[ $attrs['name'] ] = $attrs;
01341                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
01342                                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['name'] . '_ContainedType';
01343                                         $this->elements[ $attrs['name'] ]['type'] = $attrs['type'];
01344                                         $ename = $attrs['name'];
01345                                 }
01346                                 if(isset($ename) && $this->currentComplexType){
01347                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
01348                                 }
01349                         break;
01350                         case 'enumeration':     //      restriction value list member
01351                                 $this->xdebug('enumeration ' . $attrs['value']);
01352                                 if ($this->currentSimpleType) {
01353                                         $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
01354                                 } elseif ($this->currentComplexType) {
01355                                         $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
01356                                 }
01357                         break;
01358                         case 'extension':       // simpleContent or complexContent type extension
01359                                 $this->xdebug('extension ' . $attrs['base']);
01360                                 if ($this->currentComplexType) {
01361                                         $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
01362                                 }
01363                         break;
01364                         case 'import':
01365                             if (isset($attrs['schemaLocation'])) {
01366                                         //$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
01367                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
01368                                 } else {
01369                                         //$this->xdebug('import namespace ' . $attrs['namespace']);
01370                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
01371                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
01372                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
01373                                         }
01374                                 }
01375                         break;
01376                         case 'list':    // simpleType value list
01377                         break;
01378                         case 'restriction':     // simpleType, simpleContent or complexContent value restriction
01379                                 $this->xdebug('restriction ' . $attrs['base']);
01380                                 if($this->currentSimpleType){
01381                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
01382                                 } elseif($this->currentComplexType){
01383                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
01384                                         if(strstr($attrs['base'],':') == ':Array'){
01385                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
01386                                         }
01387                                 }
01388                         break;
01389                         case 'schema':
01390                                 $this->schemaInfo = $attrs;
01391                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
01392                                 if (isset($attrs['targetNamespace'])) {
01393                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];
01394                                 }
01395                                 if (!isset($attrs['elementFormDefault'])) {
01396                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';
01397                                 }
01398                                 if (!isset($attrs['attributeFormDefault'])) {
01399                                         $this->schemaInfo['attributeFormDefault'] = 'unqualified';
01400                                 }
01401                         break;
01402                         case 'simpleContent':   // (optional) content for a complexType
01403                         break;
01404                         case 'simpleType':
01405                                 array_push($this->simpleTypeStack, $this->currentSimpleType);
01406                                 if(isset($attrs['name'])){
01407                                         $this->xdebug("processing simpleType for name " . $attrs['name']);
01408                                         $this->currentSimpleType = $attrs['name'];
01409                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;
01410                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
01411                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
01412                                 } else {
01413                                         $this->xdebug('processing unnamed simpleType for element '.$this->currentElement);
01414                                         $this->currentSimpleType = $this->currentElement . '_ContainedType';
01415                                         //$this->currentElement = false;
01416                                         $this->simpleTypes[$this->currentSimpleType] = $attrs;
01417                                         $this->simpleTypes[$