class.nusoap_base.php (29229B)
1 <?php 2 3 /* 4 $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $ 5 6 NuSOAP - Web Services Toolkit for PHP 7 8 Copyright (c) 2002 NuSphere Corporation 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 2.1 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, write to the Free Software 22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 24 The NuSOAP project home is: 25 http://sourceforge.net/projects/nusoap/ 26 27 The primary support for NuSOAP is the Help forum on the project home page. 28 29 If you have any questions or comments, please email: 30 31 Dietrich Ayala 32 dietrich@ganx4.com 33 http://dietrich.ganx4.com/nusoap 34 35 NuSphere Corporation 36 http://www.nusphere.com 37 38 */ 39 40 /* 41 * Some of the standards implmented in whole or part by NuSOAP: 42 * 43 * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) 44 * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) 45 * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) 46 * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) 47 * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) 48 * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) 49 * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies 50 * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 51 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication 52 */ 53 54 /* load classes 55 56 // necessary classes 57 require_once('class.soapclient.php'); 58 require_once('class.soap_val.php'); 59 require_once('class.soap_parser.php'); 60 require_once('class.soap_fault.php'); 61 62 // transport classes 63 require_once('class.soap_transport_http.php'); 64 65 // optional add-on classes 66 require_once('class.xmlschema.php'); 67 require_once('class.wsdl.php'); 68 69 // server class 70 require_once('class.soap_server.php');*/ 71 72 // class variable emulation 73 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html 74 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9; 75 76 /** 77 * 78 * nusoap_base 79 * 80 * @author Dietrich Ayala <dietrich@ganx4.com> 81 * @author Scott Nichol <snichol@users.sourceforge.net> 82 * @version $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $ 83 * @access public 84 */ 85 class nusoap_base { 86 /** 87 * Identification for HTTP headers. 88 * 89 * @var string 90 * @access private 91 */ 92 var $title = 'NuSOAP'; 93 /** 94 * Version for HTTP headers. 95 * 96 * @var string 97 * @access private 98 */ 99 var $version = '0.9.5'; 100 /** 101 * CVS revision for HTTP headers. 102 * 103 * @var string 104 * @access private 105 */ 106 var $revision = '$Revision: 1.56 $'; 107 /** 108 * Current error string (manipulated by getError/setError) 109 * 110 * @var string 111 * @access private 112 */ 113 var $error_str = ''; 114 /** 115 * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) 116 * 117 * @var string 118 * @access private 119 */ 120 var $debug_str = ''; 121 /** 122 * toggles automatic encoding of special characters as entities 123 * (should always be true, I think) 124 * 125 * @var boolean 126 * @access private 127 */ 128 var $charencoding = true; 129 /** 130 * the debug level for this instance 131 * 132 * @var integer 133 * @access private 134 */ 135 var $debugLevel; 136 137 /** 138 * set schema version 139 * 140 * @var string 141 * @access public 142 */ 143 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; 144 145 /** 146 * charset encoding for outgoing messages 147 * 148 * @var string 149 * @access public 150 */ 151 var $soap_defencoding = 'ISO-8859-1'; 152 //var $soap_defencoding = 'UTF-8'; 153 154 /** 155 * namespaces in an array of prefix => uri 156 * 157 * this is "seeded" by a set of constants, but it may be altered by code 158 * 159 * @var array 160 * @access public 161 */ 162 var $namespaces = array( 163 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 164 'xsd' => 'http://www.w3.org/2001/XMLSchema', 165 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 166 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' 167 ); 168 169 /** 170 * namespaces used in the current context, e.g. during serialization 171 * 172 * @var array 173 * @access private 174 */ 175 var $usedNamespaces = array(); 176 177 /** 178 * XML Schema types in an array of uri => (array of xml type => php type) 179 * is this legacy yet? 180 * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. 181 * @var array 182 * @access public 183 */ 184 var $typemap = array( 185 'http://www.w3.org/2001/XMLSchema' => array( 186 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 187 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 188 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', 189 // abstract "any" types 190 'anyType'=>'string','anySimpleType'=>'string', 191 // derived datatypes 192 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 193 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 194 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 195 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 196 'http://www.w3.org/2000/10/XMLSchema' => array( 197 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 198 'float'=>'double','dateTime'=>'string', 199 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 200 'http://www.w3.org/1999/XMLSchema' => array( 201 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 202 'float'=>'double','dateTime'=>'string', 203 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 204 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 205 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 206 'http://xml.apache.org/xml-soap' => array('Map') 207 ); 208 209 /** 210 * XML entities to convert 211 * 212 * @var array 213 * @access public 214 * @deprecated 215 * @see expandEntities 216 */ 217 var $xmlEntities = array('quot' => '"','amp' => '&', 218 'lt' => '<','gt' => '>','apos' => "'"); 219 220 /** 221 * constructor 222 * 223 * @access public 224 */ 225 function nusoap_base() { 226 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; 227 } 228 229 /** 230 * gets the global debug level, which applies to future instances 231 * 232 * @return integer Debug level 0-9, where 0 turns off 233 * @access public 234 */ 235 function getGlobalDebugLevel() { 236 return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; 237 } 238 239 /** 240 * sets the global debug level, which applies to future instances 241 * 242 * @param int $level Debug level 0-9, where 0 turns off 243 * @access public 244 */ 245 function setGlobalDebugLevel($level) { 246 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; 247 } 248 249 /** 250 * gets the debug level for this instance 251 * 252 * @return int Debug level 0-9, where 0 turns off 253 * @access public 254 */ 255 function getDebugLevel() { 256 return $this->debugLevel; 257 } 258 259 /** 260 * sets the debug level for this instance 261 * 262 * @param int $level Debug level 0-9, where 0 turns off 263 * @access public 264 */ 265 function setDebugLevel($level) { 266 $this->debugLevel = $level; 267 } 268 269 /** 270 * adds debug data to the instance debug string with formatting 271 * 272 * @param string $string debug data 273 * @access private 274 */ 275 function debug($string){ 276 if ($this->debugLevel > 0) { 277 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); 278 } 279 } 280 281 /** 282 * adds debug data to the instance debug string without formatting 283 * 284 * @param string $string debug data 285 * @access public 286 */ 287 function appendDebug($string){ 288 if ($this->debugLevel > 0) { 289 // it would be nice to use a memory stream here to use 290 // memory more efficiently 291 $this->debug_str .= $string; 292 } 293 } 294 295 /** 296 * clears the current debug data for this instance 297 * 298 * @access public 299 */ 300 function clearDebug() { 301 // it would be nice to use a memory stream here to use 302 // memory more efficiently 303 $this->debug_str = ''; 304 } 305 306 /** 307 * gets the current debug data for this instance 308 * 309 * @return debug data 310 * @access public 311 */ 312 function &getDebug() { 313 // it would be nice to use a memory stream here to use 314 // memory more efficiently 315 return $this->debug_str; 316 } 317 318 /** 319 * gets the current debug data for this instance as an XML comment 320 * this may change the contents of the debug data 321 * 322 * @return debug data as an XML comment 323 * @access public 324 */ 325 function &getDebugAsXMLComment() { 326 // it would be nice to use a memory stream here to use 327 // memory more efficiently 328 while (strpos($this->debug_str, '--')) { 329 $this->debug_str = str_replace('--', '- -', $this->debug_str); 330 } 331 $ret = "<!--\n" . $this->debug_str . "\n-->"; 332 return $ret; 333 } 334 335 /** 336 * expands entities, e.g. changes '<' to '<'. 337 * 338 * @param string $val The string in which to expand entities. 339 * @access private 340 */ 341 function expandEntities($val) { 342 if ($this->charencoding) { 343 $val = str_replace('&', '&', $val); 344 $val = str_replace("'", ''', $val); 345 $val = str_replace('"', '"', $val); 346 $val = str_replace('<', '<', $val); 347 $val = str_replace('>', '>', $val); 348 } 349 return $val; 350 } 351 352 /** 353 * returns error string if present 354 * 355 * @return mixed error string or false 356 * @access public 357 */ 358 function getError(){ 359 if($this->error_str != ''){ 360 return $this->error_str; 361 } 362 return false; 363 } 364 365 /** 366 * sets error string 367 * 368 * @return boolean $string error string 369 * @access private 370 */ 371 function setError($str){ 372 $this->error_str = $str; 373 } 374 375 /** 376 * detect if array is a simple array or a struct (associative array) 377 * 378 * @param mixed $val The PHP array 379 * @return string (arraySimple|arrayStruct) 380 * @access private 381 */ 382 function isArraySimpleOrStruct($val) { 383 $keyList = array_keys($val); 384 foreach ($keyList as $keyListValue) { 385 if (!is_int($keyListValue)) { 386 return 'arrayStruct'; 387 } 388 } 389 return 'arraySimple'; 390 } 391 392 /** 393 * serializes PHP values in accordance w/ section 5. Type information is 394 * not serialized if $use == 'literal'. 395 * 396 * @param mixed $val The value to serialize 397 * @param string $name The name (local part) of the XML element 398 * @param string $type The XML schema type (local part) for the element 399 * @param string $name_ns The namespace for the name of the XML element 400 * @param string $type_ns The namespace for the type of the element 401 * @param array $attributes The attributes to serialize as name=>value pairs 402 * @param string $use The WSDL "use" (encoded|literal) 403 * @param boolean $soapval Whether this is called from soapval. 404 * @return string The serialized element, possibly with child elements 405 * @access public 406 */ 407 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { 408 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); 409 $this->appendDebug('value=' . $this->varDump($val)); 410 $this->appendDebug('attributes=' . $this->varDump($attributes)); 411 412 if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { 413 $this->debug("serialize_val: serialize soapval"); 414 $xml = $val->serialize($use); 415 $this->appendDebug($val->getDebug()); 416 $val->clearDebug(); 417 $this->debug("serialize_val of soapval returning $xml"); 418 return $xml; 419 } 420 // force valid name if necessary 421 if (is_numeric($name)) { 422 $name = '__numeric_' . $name; 423 } elseif (! $name) { 424 $name = 'noname'; 425 } 426 // if name has ns, add ns prefix to name 427 $xmlns = ''; 428 if($name_ns){ 429 $prefix = 'nu'.rand(1000,9999); 430 $name = $prefix.':'.$name; 431 $xmlns .= " xmlns:$prefix=\"$name_ns\""; 432 } 433 // if type is prefixed, create type prefix 434 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ 435 // need to fix this. shouldn't default to xsd if no ns specified 436 // w/o checking against typemap 437 $type_prefix = 'xsd'; 438 } elseif($type_ns){ 439 $type_prefix = 'ns'.rand(1000,9999); 440 $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; 441 } 442 // serialize attributes if present 443 $atts = ''; 444 if($attributes){ 445 foreach($attributes as $k => $v){ 446 $atts .= " $k=\"".$this->expandEntities($v).'"'; 447 } 448 } 449 // serialize null value 450 if (is_null($val)) { 451 $this->debug("serialize_val: serialize null"); 452 if ($use == 'literal') { 453 // TODO: depends on minOccurs 454 $xml = "<$name$xmlns$atts/>"; 455 $this->debug("serialize_val returning $xml"); 456 return $xml; 457 } else { 458 if (isset($type) && isset($type_prefix)) { 459 $type_str = " xsi:type=\"$type_prefix:$type\""; 460 } else { 461 $type_str = ''; 462 } 463 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; 464 $this->debug("serialize_val returning $xml"); 465 return $xml; 466 } 467 } 468 // serialize if an xsd built-in primitive type 469 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ 470 $this->debug("serialize_val: serialize xsd built-in primitive type"); 471 if (is_bool($val)) { 472 if ($type == 'boolean') { 473 $val = $val ? 'true' : 'false'; 474 } elseif (! $val) { 475 $val = 0; 476 } 477 } else if (is_string($val)) { 478 $val = $this->expandEntities($val); 479 } 480 if ($use == 'literal') { 481 $xml = "<$name$xmlns$atts>$val</$name>"; 482 $this->debug("serialize_val returning $xml"); 483 return $xml; 484 } else { 485 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>"; 486 $this->debug("serialize_val returning $xml"); 487 return $xml; 488 } 489 } 490 // detect type and serialize 491 $xml = ''; 492 switch(true) { 493 case (is_bool($val) || $type == 'boolean'): 494 $this->debug("serialize_val: serialize boolean"); 495 if ($type == 'boolean') { 496 $val = $val ? 'true' : 'false'; 497 } elseif (! $val) { 498 $val = 0; 499 } 500 if ($use == 'literal') { 501 $xml .= "<$name$xmlns$atts>$val</$name>"; 502 } else { 503 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; 504 } 505 break; 506 case (is_int($val) || is_long($val) || $type == 'int'): 507 $this->debug("serialize_val: serialize int"); 508 if ($use == 'literal') { 509 $xml .= "<$name$xmlns$atts>$val</$name>"; 510 } else { 511 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; 512 } 513 break; 514 case (is_float($val)|| is_double($val) || $type == 'float'): 515 $this->debug("serialize_val: serialize float"); 516 if ($use == 'literal') { 517 $xml .= "<$name$xmlns$atts>$val</$name>"; 518 } else { 519 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; 520 } 521 break; 522 case (is_string($val) || $type == 'string'): 523 $this->debug("serialize_val: serialize string"); 524 $val = $this->expandEntities($val); 525 if ($use == 'literal') { 526 $xml .= "<$name$xmlns$atts>$val</$name>"; 527 } else { 528 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; 529 } 530 break; 531 case is_object($val): 532 $this->debug("serialize_val: serialize object"); 533 if (get_class($val) == 'soapval') { 534 $this->debug("serialize_val: serialize soapval object"); 535 $pXml = $val->serialize($use); 536 $this->appendDebug($val->getDebug()); 537 $val->clearDebug(); 538 } else { 539 if (! $name) { 540 $name = get_class($val); 541 $this->debug("In serialize_val, used class name $name as element name"); 542 } else { 543 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); 544 } 545 foreach(get_object_vars($val) as $k => $v){ 546 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); 547 } 548 } 549 if(isset($type) && isset($type_prefix)){ 550 $type_str = " xsi:type=\"$type_prefix:$type\""; 551 } else { 552 $type_str = ''; 553 } 554 if ($use == 'literal') { 555 $xml .= "<$name$xmlns$atts>$pXml</$name>"; 556 } else { 557 $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>"; 558 } 559 break; 560 break; 561 case (is_array($val) || $type): 562 // detect if struct or array 563 $valueType = $this->isArraySimpleOrStruct($val); 564 if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ 565 $this->debug("serialize_val: serialize array"); 566 $i = 0; 567 if(is_array($val) && count($val)> 0){ 568 foreach($val as $v){ 569 if(is_object($v) && get_class($v) == 'soapval'){ 570 $tt_ns = $v->type_ns; 571 $tt = $v->type; 572 } elseif (is_array($v)) { 573 $tt = $this->isArraySimpleOrStruct($v); 574 } else { 575 $tt = gettype($v); 576 } 577 $array_types[$tt] = 1; 578 // TODO: for literal, the name should be $name 579 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); 580 ++$i; 581 } 582 if(count($array_types) > 1){ 583 $array_typename = 'xsd:anyType'; 584 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { 585 if ($tt == 'integer') { 586 $tt = 'int'; 587 } 588 $array_typename = 'xsd:'.$tt; 589 } elseif(isset($tt) && $tt == 'arraySimple'){ 590 $array_typename = 'SOAP-ENC:Array'; 591 } elseif(isset($tt) && $tt == 'arrayStruct'){ 592 $array_typename = 'unnamed_struct_use_soapval'; 593 } else { 594 // if type is prefixed, create type prefix 595 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ 596 $array_typename = 'xsd:' . $tt; 597 } elseif ($tt_ns) { 598 $tt_prefix = 'ns' . rand(1000, 9999); 599 $array_typename = "$tt_prefix:$tt"; 600 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; 601 } else { 602 $array_typename = $tt; 603 } 604 } 605 $array_type = $i; 606 if ($use == 'literal') { 607 $type_str = ''; 608 } else if (isset($type) && isset($type_prefix)) { 609 $type_str = " xsi:type=\"$type_prefix:$type\""; 610 } else { 611 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; 612 } 613 // empty array 614 } else { 615 if ($use == 'literal') { 616 $type_str = ''; 617 } else if (isset($type) && isset($type_prefix)) { 618 $type_str = " xsi:type=\"$type_prefix:$type\""; 619 } else { 620 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; 621 } 622 } 623 // TODO: for array in literal, there is no wrapper here 624 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>"; 625 } else { 626 // got a struct 627 $this->debug("serialize_val: serialize struct"); 628 if(isset($type) && isset($type_prefix)){ 629 $type_str = " xsi:type=\"$type_prefix:$type\""; 630 } else { 631 $type_str = ''; 632 } 633 if ($use == 'literal') { 634 $xml .= "<$name$xmlns$atts>"; 635 } else { 636 $xml .= "<$name$xmlns$type_str$atts>"; 637 } 638 foreach($val as $k => $v){ 639 // Apache Map 640 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { 641 $xml .= '<item>'; 642 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); 643 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); 644 $xml .= '</item>'; 645 } else { 646 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); 647 } 648 } 649 $xml .= "</$name>"; 650 } 651 break; 652 default: 653 $this->debug("serialize_val: serialize unknown"); 654 $xml .= 'not detected, got '.gettype($val).' for '.$val; 655 break; 656 } 657 $this->debug("serialize_val returning $xml"); 658 return $xml; 659 } 660 661 /** 662 * serializes a message 663 * 664 * @param string $body the XML of the SOAP body 665 * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array 666 * @param array $namespaces optional the namespaces used in generating the body and headers 667 * @param string $style optional (rpc|document) 668 * @param string $use optional (encoded|literal) 669 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) 670 * @return string the message 671 * @access public 672 */ 673 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ 674 // TODO: add an option to automatically run utf8_encode on $body and $headers 675 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows 676 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 677 678 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); 679 $this->debug("headers:"); 680 $this->appendDebug($this->varDump($headers)); 681 $this->debug("namespaces:"); 682 $this->appendDebug($this->varDump($namespaces)); 683 684 // serialize namespaces 685 $ns_string = ''; 686 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ 687 $ns_string .= " xmlns:$k=\"$v\""; 688 } 689 if($encodingStyle) { 690 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; 691 } 692 693 // serialize headers 694 if($headers){ 695 if (is_array($headers)) { 696 $xml = ''; 697 foreach ($headers as $k => $v) { 698 if (is_object($v) && get_class($v) == 'soapval') { 699 $xml .= $this->serialize_val($v, false, false, false, false, false, $use); 700 } else { 701 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); 702 } 703 } 704 $headers = $xml; 705 $this->debug("In serializeEnvelope, serialized array of headers to $headers"); 706 } 707 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; 708 } 709 // serialize envelope 710 return 711 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". 712 '<SOAP-ENV:Envelope'.$ns_string.">". 713 $headers. 714 "<SOAP-ENV:Body>". 715 $body. 716 "</SOAP-ENV:Body>". 717 "</SOAP-ENV:Envelope>"; 718 } 719 720 /** 721 * formats a string to be inserted into an HTML stream 722 * 723 * @param string $str The string to format 724 * @return string The formatted string 725 * @access public 726 * @deprecated 727 */ 728 function formatDump($str){ 729 $str = htmlspecialchars($str); 730 return nl2br($str); 731 } 732 733 /** 734 * contracts (changes namespace to prefix) a qualified name 735 * 736 * @param string $qname qname 737 * @return string contracted qname 738 * @access private 739 */ 740 function contractQname($qname){ 741 // get element namespace 742 //$this->xdebug("Contract $qname"); 743 if (strrpos($qname, ':')) { 744 // get unqualified name 745 $name = substr($qname, strrpos($qname, ':') + 1); 746 // get ns 747 $ns = substr($qname, 0, strrpos($qname, ':')); 748 $p = $this->getPrefixFromNamespace($ns); 749 if ($p) { 750 return $p . ':' . $name; 751 } 752 return $qname; 753 } else { 754 return $qname; 755 } 756 } 757 758 /** 759 * expands (changes prefix to namespace) a qualified name 760 * 761 * @param string $qname qname 762 * @return string expanded qname 763 * @access private 764 */ 765 function expandQname($qname){ 766 // get element prefix 767 if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ 768 // get unqualified name 769 $name = substr(strstr($qname,':'),1); 770 // get ns prefix 771 $prefix = substr($qname,0,strpos($qname,':')); 772 if(isset($this->namespaces[$prefix])){ 773 return $this->namespaces[$prefix].':'.$name; 774 } else { 775 return $qname; 776 } 777 } else { 778 return $qname; 779 } 780 } 781 782 /** 783 * returns the local part of a prefixed string 784 * returns the original string, if not prefixed 785 * 786 * @param string $str The prefixed string 787 * @return string The local part 788 * @access public 789 */ 790 function getLocalPart($str){ 791 if($sstr = strrchr($str,':')){ 792 // get unqualified name 793 return substr( $sstr, 1 ); 794 } else { 795 return $str; 796 } 797 } 798 799 /** 800 * returns the prefix part of a prefixed string 801 * returns false, if not prefixed 802 * 803 * @param string $str The prefixed string 804 * @return mixed The prefix or false if there is no prefix 805 * @access public 806 */ 807 function getPrefix($str){ 808 if($pos = strrpos($str,':')){ 809 // get prefix 810 return substr($str,0,$pos); 811 } 812 return false; 813 } 814 815 /** 816 * pass it a prefix, it returns a namespace 817 * 818 * @param string $prefix The prefix 819 * @return mixed The namespace, false if no namespace has the specified prefix 820 * @access public 821 */ 822 function getNamespaceFromPrefix($prefix){ 823 if (isset($this->namespaces[$prefix])) { 824 return $this->namespaces[$prefix]; 825 } 826 //$this->setError("No namespace registered for prefix '$prefix'"); 827 return false; 828 } 829 830 /** 831 * returns the prefix for a given namespace (or prefix) 832 * or false if no prefixes registered for the given namespace 833 * 834 * @param string $ns The namespace 835 * @return mixed The prefix, false if the namespace has no prefixes 836 * @access public 837 */ 838 function getPrefixFromNamespace($ns) { 839 foreach ($this->namespaces as $p => $n) { 840 if ($ns == $n || $ns == $p) { 841 $this->usedNamespaces[$p] = $n; 842 return $p; 843 } 844 } 845 return false; 846 } 847 848 /** 849 * returns the time in ODBC canonical form with microseconds 850 * 851 * @return string The time in ODBC canonical form with microseconds 852 * @access public 853 */ 854 function getmicrotime() { 855 if (function_exists('gettimeofday')) { 856 $tod = gettimeofday(); 857 $sec = $tod['sec']; 858 $usec = $tod['usec']; 859 } else { 860 $sec = time(); 861 $usec = 0; 862 } 863 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); 864 } 865 866 /** 867 * Returns a string with the output of var_dump 868 * 869 * @param mixed $data The variable to var_dump 870 * @return string The output of var_dump 871 * @access public 872 */ 873 function varDump($data) { 874 ob_start(); 875 var_dump($data); 876 $ret_val = ob_get_contents(); 877 ob_end_clean(); 878 return $ret_val; 879 } 880 881 /** 882 * represents the object as a string 883 * 884 * @return string 885 * @access public 886 */ 887 function __toString() { 888 return $this->varDump($this); 889 } 890 } 891 892 // XML Schema Datatype Helper Functions 893 894 //xsd:dateTime helpers 895 896 /** 897 * convert unix timestamp to ISO 8601 compliant date string 898 * 899 * @param int $timestamp Unix time stamp 900 * @param boolean $utc Whether the time stamp is UTC or local 901 * @return mixed ISO 8601 date string or false 902 * @access public 903 */ 904 function timestamp_to_iso8601($timestamp,$utc=true){ 905 $datestr = date('Y-m-d\TH:i:sO',$timestamp); 906 $pos = strrpos($datestr, "+"); 907 if ($pos === FALSE) { 908 $pos = strrpos($datestr, "-"); 909 } 910 if ($pos !== FALSE) { 911 if (strlen($datestr) == $pos + 5) { 912 $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); 913 } 914 } 915 if($utc){ 916 $pattern = '/'. 917 '([0-9]{4})-'. // centuries & years CCYY- 918 '([0-9]{2})-'. // months MM- 919 '([0-9]{2})'. // days DD 920 'T'. // separator T 921 '([0-9]{2}):'. // hours hh: 922 '([0-9]{2}):'. // minutes mm: 923 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... 924 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 925 '/'; 926 927 if(preg_match($pattern,$datestr,$regs)){ 928 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); 929 } 930 return false; 931 } else { 932 return $datestr; 933 } 934 } 935 936 /** 937 * convert ISO 8601 compliant date string to unix timestamp 938 * 939 * @param string $datestr ISO 8601 compliant date string 940 * @return mixed Unix timestamp (int) or false 941 * @access public 942 */ 943 function iso8601_to_timestamp($datestr){ 944 $pattern = '/'. 945 '([0-9]{4})-'. // centuries & years CCYY- 946 '([0-9]{2})-'. // months MM- 947 '([0-9]{2})'. // days DD 948 'T'. // separator T 949 '([0-9]{2}):'. // hours hh: 950 '([0-9]{2}):'. // minutes mm: 951 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... 952 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 953 '/'; 954 if(preg_match($pattern,$datestr,$regs)){ 955 // not utc 956 if($regs[8] != 'Z'){ 957 $op = substr($regs[8],0,1); 958 $h = substr($regs[8],1,2); 959 $m = substr($regs[8],strlen($regs[8])-2,2); 960 if($op == '-'){ 961 $regs[4] = $regs[4] + $h; 962 $regs[5] = $regs[5] + $m; 963 } elseif($op == '+'){ 964 $regs[4] = $regs[4] - $h; 965 $regs[5] = $regs[5] - $m; 966 } 967 } 968 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 969 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); 970 } else { 971 return false; 972 } 973 } 974 975 /** 976 * sleeps some number of microseconds 977 * 978 * @param string $usec the number of microseconds to sleep 979 * @access public 980 * @deprecated 981 */ 982 function usleepWindows($usec) 983 { 984 $start = gettimeofday(); 985 986 do 987 { 988 $stop = gettimeofday(); 989 $timePassed = 1000000 * ($stop['sec'] - $start['sec']) 990 + $stop['usec'] - $start['usec']; 991 } 992 while ($timePassed < $usec); 993 } 994 995 996 ?>