00001 <?php 00002 00003 /* 00004 $Id: nusoap.php,v 1.121 2008/03/14 20:52:11 snichol Exp $ 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 The NuSOAP project home is: 00025 http://sourceforge.net/projects/nusoap/ 00026 00027 The primary support for NuSOAP is the Help forum on the project home page. 00028 00029 If you have any questions or comments, please email: 00030 00031 Dietrich Ayala 00032 dietrich@ganx4.com 00033 http://dietrich.ganx4.com/nusoap 00034 00035 NuSphere Corporation 00036 http://www.nusphere.com 00037 00038 */ 00039 00040 /* 00041 * Some of the standards implmented in whole or part by NuSOAP: 00042 * 00043 * SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/) 00044 * WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315) 00045 * SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments) 00046 * XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/) 00047 * Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/) 00048 * XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/) 00049 * RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies 00050 * RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1 00051 * RFC 2617 HTTP Authentication: Basic and Digest Access Authentication 00052 */ 00053 00054 /* load classes 00055 00056 // necessary classes 00057 require_once('class.soapclient.php'); 00058 require_once('class.soap_val.php'); 00059 require_once('class.soap_parser.php'); 00060 require_once('class.soap_fault.php'); 00061 00062 // transport classes 00063 require_once('class.soap_transport_http.php'); 00064 00065 // optional add-on classes 00066 require_once('class.xmlschema.php'); 00067 require_once('class.wsdl.php'); 00068 00069 // server class 00070 require_once('class.soap_server.php');*/ 00071 00072 // class variable emulation 00073 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html 00074 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9; 00075 00085 class nusoap_base { 00092 var $title = 'NuSOAP'; 00099 var $version = '1.0rc1'; 00106 var $revision = '$Revision: 1.121 $'; 00113 var $error_str = ''; 00120 var $debug_str = ''; 00128 var $charencoding = true; 00135 var $debugLevel; 00136 00143 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; 00144 00151 var $soap_defencoding = 'ISO-8859-1'; 00152 //var $soap_defencoding = 'UTF-8'; 00153 00162 var $namespaces = array( 00163 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 00164 'xsd' => 'http://www.w3.org/2001/XMLSchema', 00165 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 00166 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' 00167 ); 00168 00175 var $usedNamespaces = array(); 00176 00184 var $typemap = array( 00185 'http://www.w3.org/2001/XMLSchema' => array( 00186 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 00187 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 00188 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', 00189 // abstract "any" types 00190 'anyType'=>'string','anySimpleType'=>'string', 00191 // derived datatypes 00192 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 00193 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 00194 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 00195 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 00196 'http://www.w3.org/2000/10/XMLSchema' => array( 00197 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 00198 'float'=>'double','dateTime'=>'string', 00199 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 00200 'http://www.w3.org/1999/XMLSchema' => array( 00201 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 00202 'float'=>'double','dateTime'=>'string', 00203 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 00204 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 00205 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 00206 'http://xml.apache.org/xml-soap' => array('Map') 00207 ); 00208 00217 var $xmlEntities = array('quot' => '"','amp' => '&', 00218 'lt' => '<','gt' => '>','apos' => "'"); 00219 00225 function nusoap_base() { 00226 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; 00227 } 00228 00235 function getGlobalDebugLevel() { 00236 return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; 00237 } 00238 00245 function setGlobalDebugLevel($level) { 00246 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; 00247 } 00248 00255 function getDebugLevel() { 00256 return $this->debugLevel; 00257 } 00258 00265 function setDebugLevel($level) { 00266 $this->debugLevel = $level; 00267 } 00268 00275 function debug($string){ 00276 if ($this->debugLevel > 0) { 00277 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); 00278 } 00279 } 00280 00287 function appendDebug($string){ 00288 if ($this->debugLevel > 0) { 00289 // it would be nice to use a memory stream here to use 00290 // memory more efficiently 00291 $this->debug_str .= $string; 00292 } 00293 } 00294 00300 function clearDebug() { 00301 // it would be nice to use a memory stream here to use 00302 // memory more efficiently 00303 $this->debug_str = ''; 00304 } 00305 00312 function &getDebug() { 00313 // it would be nice to use a memory stream here to use 00314 // memory more efficiently 00315 return $this->debug_str; 00316 } 00317 00325 function &getDebugAsXMLComment() { 00326 // it would be nice to use a memory stream here to use 00327 // memory more efficiently 00328 while (strpos($this->debug_str, '--')) { 00329 $this->debug_str = str_replace('--', '- -', $this->debug_str); 00330 } 00331 $ret = "<!--\n" . $this->debug_str . "\n-->"; 00332 return $ret; 00333 } 00334 00341 function expandEntities($val) { 00342 if ($this->charencoding) { 00343 $val = str_replace('&', '&', $val); 00344 $val = str_replace("'", ''', $val); 00345 $val = str_replace('"', '"', $val); 00346 $val = str_replace('<', '<', $val); 00347 $val = str_replace('>', '>', $val); 00348 } 00349 return $val; 00350 } 00351 00358 function getError(){ 00359 if($this->error_str != ''){ 00360 return $this->error_str; 00361 } 00362 return false; 00363 } 00364 00371 function setError($str){ 00372 $this->error_str = $str; 00373 } 00374 00382 function isArraySimpleOrStruct($val) { 00383 $keyList = array_keys($val); 00384 foreach ($keyList as $keyListValue) { 00385 if (!is_int($keyListValue)) { 00386 return 'arrayStruct'; 00387 } 00388 } 00389 return 'arraySimple'; 00390 } 00391 00407 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { 00408 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); 00409 $this->appendDebug('value=' . $this->varDump($val)); 00410 $this->appendDebug('attributes=' . $this->varDump($attributes)); 00411 00412 if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { 00413 $this->debug("serialize_val: serialize soapval"); 00414 $xml = $val->serialize($use); 00415 $this->appendDebug($val->getDebug()); 00416 $val->clearDebug(); 00417 $this->debug("serialize_val of soapval returning $xml"); 00418 return $xml; 00419 } 00420 // force valid name if necessary 00421 if (is_numeric($name)) { 00422 $name = '__numeric_' . $name; 00423 } elseif (! $name) { 00424 $name = 'noname'; 00425 } 00426 // if name has ns, add ns prefix to name 00427 $xmlns = ''; 00428 if($name_ns){ 00429 $prefix = 'nu'.rand(1000,9999); 00430 $name = $prefix.':'.$name; 00431 $xmlns .= " xmlns:$prefix=\"$name_ns\""; 00432 } 00433 // if type is prefixed, create type prefix 00434 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ 00435 // need to fix this. shouldn't default to xsd if no ns specified 00436 // w/o checking against typemap 00437 $type_prefix = 'xsd'; 00438 } elseif($type_ns){ 00439 $type_prefix = 'ns'.rand(1000,9999); 00440 $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; 00441 } 00442 // serialize attributes if present 00443 $atts = ''; 00444 if($attributes){ 00445 foreach($attributes as $k => $v){ 00446 $atts .= " $k=\"".$this->expandEntities($v).'"'; 00447 } 00448 } 00449 // serialize null value 00450 if (is_null($val)) { 00451 $this->debug("serialize_val: serialize null"); 00452 if ($use == 'literal') { 00453 // TODO: depends on minOccurs 00454 $xml = "<$name$xmlns$atts/>"; 00455 $this->debug("serialize_val returning $xml"); 00456 return $xml; 00457 } else { 00458 if (isset($type) && isset($type_prefix)) { 00459 $type_str = " xsi:type=\"$type_prefix:$type\""; 00460 } else { 00461 $type_str = ''; 00462 } 00463 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; 00464 $this->debug("serialize_val returning $xml"); 00465 return $xml; 00466 } 00467 } 00468 // serialize if an xsd built-in primitive type 00469 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ 00470 $this->debug("serialize_val: serialize xsd built-in primitive type"); 00471 if (is_bool($val)) { 00472 if ($type == 'boolean') { 00473 $val = $val ? 'true' : 'false'; 00474 } elseif (! $val) { 00475 $val = 0; 00476 } 00477 } else if (is_string($val)) { 00478 $val = $this->expandEntities($val); 00479 } 00480 if ($use == 'literal') { 00481 $xml = "<$name$xmlns$atts>$val</$name>"; 00482 $this->debug("serialize_val returning $xml"); 00483 return $xml; 00484 } else { 00485 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>"; 00486 $this->debug("serialize_val returning $xml"); 00487 return $xml; 00488 } 00489 } 00490 // detect type and serialize 00491 $xml = ''; 00492 switch(true) { 00493 case (is_bool($val) || $type == 'boolean'): 00494 $this->debug("serialize_val: serialize boolean"); 00495 if ($type == 'boolean') { 00496 $val = $val ? 'true' : 'false'; 00497 } elseif (! $val) { 00498 $val = 0; 00499 } 00500 if ($use == 'literal') { 00501 $xml .= "<$name$xmlns$atts>$val</$name>"; 00502 } else { 00503 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>"; 00504 } 00505 break; 00506 case (is_int($val) || is_long($val) || $type == 'int'): 00507 $this->debug("serialize_val: serialize int"); 00508 if ($use == 'literal') { 00509 $xml .= "<$name$xmlns$atts>$val</$name>"; 00510 } else { 00511 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>"; 00512 } 00513 break; 00514 case (is_float($val)|| is_double($val) || $type == 'float'): 00515 $this->debug("serialize_val: serialize float"); 00516 if ($use == 'literal') { 00517 $xml .= "<$name$xmlns$atts>$val</$name>"; 00518 } else { 00519 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>"; 00520 } 00521 break; 00522 case (is_string($val) || $type == 'string'): 00523 $this->debug("serialize_val: serialize string"); 00524 $val = $this->expandEntities($val); 00525 if ($use == 'literal') { 00526 $xml .= "<$name$xmlns$atts>$val</$name>"; 00527 } else { 00528 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>"; 00529 } 00530 break; 00531 case is_object($val): 00532 $this->debug("serialize_val: serialize object"); 00533 if (get_class($val) == 'soapval') { 00534 $this->debug("serialize_val: serialize soapval object"); 00535 $pXml = $val->serialize($use); 00536 $this->appendDebug($val->getDebug()); 00537 $val->clearDebug(); 00538 } else { 00539 if (! $name) { 00540 $name = get_class($val); 00541 $this->debug("In serialize_val, used class name $name as element name"); 00542 } else { 00543 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); 00544 } 00545 foreach(get_object_vars($val) as $k => $v){ 00546 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); 00547 } 00548 } 00549 if(isset($type) && isset($type_prefix)){ 00550 $type_str = " xsi:type=\"$type_prefix:$type\""; 00551 } else { 00552 $type_str = ''; 00553 } 00554 if ($use == 'literal') { 00555 $xml .= "<$name$xmlns$atts>$pXml</$name>"; 00556 } else { 00557 $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>"; 00558 } 00559 break; 00560 break; 00561 case (is_array($val) || $type): 00562 // detect if struct or array 00563 $valueType = $this->isArraySimpleOrStruct($val); 00564 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){ 00565 $this->debug("serialize_val: serialize array"); 00566 $i = 0; 00567 if(is_array($val) && count($val)> 0){ 00568 foreach($val as $v){ 00569 if(is_object($v) && get_class($v) == 'soapval'){ 00570 $tt_ns = $v->type_ns; 00571 $tt = $v->type; 00572 } elseif (is_array($v)) { 00573 $tt = $this->isArraySimpleOrStruct($v); 00574 } else { 00575 $tt = gettype($v); 00576 } 00577 $array_types[$tt] = 1; 00578 // TODO: for literal, the name should be $name 00579 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); 00580 ++$i; 00581 } 00582 if(count($array_types) > 1){ 00583 $array_typename = 'xsd:anyType'; 00584 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { 00585 if ($tt == 'integer') { 00586 $tt = 'int'; 00587 } 00588 $array_typename = 'xsd:'.$tt; 00589 } elseif(isset($tt) && $tt == 'arraySimple'){ 00590 $array_typename = 'SOAP-ENC:Array'; 00591 } elseif(isset($tt) && $tt == 'arrayStruct'){ 00592 $array_typename = 'unnamed_struct_use_soapval'; 00593 } else { 00594 // if type is prefixed, create type prefix 00595 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ 00596 $array_typename = 'xsd:' . $tt; 00597 } elseif ($tt_ns) { 00598 $tt_prefix = 'ns' . rand(1000, 9999); 00599 $array_typename = "$tt_prefix:$tt"; 00600 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; 00601 } else { 00602 $array_typename = $tt; 00603 } 00604 } 00605 $array_type = $i; 00606 if ($use == 'literal') { 00607 $type_str = ''; 00608 } else if (isset($type) && isset($type_prefix)) { 00609 $type_str = " xsi:type=\"$type_prefix:$type\""; 00610 } else { 00611 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; 00612 } 00613 // empty array 00614 } else { 00615 if ($use == 'literal') { 00616 $type_str = ''; 00617 } else if (isset($type) && isset($type_prefix)) { 00618 $type_str = " xsi:type=\"$type_prefix:$type\""; 00619 } else { 00620 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; 00621 } 00622 } 00623 // TODO: for array in literal, there is no wrapper here 00624 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>"; 00625 } else { 00626 // got a struct 00627 $this->debug("serialize_val: serialize struct"); 00628 if(isset($type) && isset($type_prefix)){ 00629 $type_str = " xsi:type=\"$type_prefix:$type\""; 00630 } else { 00631 $type_str = ''; 00632 } 00633 if ($use == 'literal') { 00634 $xml .= "<$name$xmlns$atts>"; 00635 } else { 00636 $xml .= "<$name$xmlns$type_str$atts>"; 00637 } 00638 foreach($val as $k => $v){ 00639 // Apache Map 00640 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { 00641 $xml .= '<item>'; 00642 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); 00643 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); 00644 $xml .= '</item>'; 00645 } else { 00646 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); 00647 } 00648 } 00649 $xml .= "</$name>"; 00650 } 00651 break; 00652 default: 00653 $this->debug("serialize_val: serialize unknown"); 00654 $xml .= 'not detected, got '.gettype($val).' for '.$val; 00655 break; 00656 } 00657 $this->debug("serialize_val returning $xml"); 00658 return $xml; 00659 } 00660 00673 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ 00674 // TODO: add an option to automatically run utf8_encode on $body and $headers 00675 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows 00676 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 00677 00678 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); 00679 $this->debug("headers:"); 00680 $this->appendDebug($this->varDump($headers)); 00681 $this->debug("namespaces:"); 00682 $this->appendDebug($this->varDump($namespaces)); 00683 00684 // serialize namespaces 00685 $ns_string = ''; 00686 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ 00687 $ns_string .= " xmlns:$k=\"$v\""; 00688 } 00689 if($encodingStyle) { 00690 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; 00691 } 00692 00693 // serialize headers 00694 if($headers){ 00695 if (is_array($headers)) { 00696 $xml = ''; 00697 foreach ($headers as $k => $v) { 00698 if (is_object($v) && get_class($v) == 'soapval') { 00699 $xml .= $this->serialize_val($v, false, false, false, false, false, $use); 00700 } else { 00701 $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); 00702 } 00703 } 00704 $headers = $xml; 00705 $this->debug("In serializeEnvelope, serialized array of headers to $headers"); 00706 } 00707 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>"; 00708 } 00709 // serialize envelope 00710 return 00711 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">". 00712 '<SOAP-ENV:Envelope'.$ns_string.">". 00713 $headers. 00714 "<SOAP-ENV:Body>". 00715 $body. 00716 "</SOAP-ENV:Body>". 00717 "</SOAP-ENV:Envelope>"; 00718 } 00719 00728 function formatDump($str){ 00729 $str = htmlspecialchars($str); 00730 return nl2br($str); 00731 } 00732 00740 function contractQname($qname){ 00741 // get element namespace 00742 //$this->xdebug("Contract $qname"); 00743 if (strrpos($qname, ':')) { 00744 // get unqualified name 00745 $name = substr($qname, strrpos($qname, ':') + 1); 00746 // get ns 00747 $ns = substr($qname, 0, strrpos($qname, ':')); 00748 $p = $this->getPrefixFromNamespace($ns); 00749 if ($p) { 00750 return $p . ':' . $name; 00751 } 00752 return $qname; 00753 } else { 00754 return $qname; 00755 } 00756 } 00757 00765 function expandQname($qname){ 00766 // get element prefix 00767 if(strpos($qname,':') && !ereg('^http://',$qname)){ 00768 // get unqualified name 00769 $name = substr(strstr($qname,':'),1); 00770 // get ns prefix 00771 $prefix = substr($qname,0,strpos($qname,':')); 00772 if(isset($this->namespaces[$prefix])){ 00773 return $this->namespaces[$prefix].':'.$name; 00774 } else { 00775 return $qname; 00776 } 00777 } else { 00778 return $qname; 00779 } 00780 } 00781 00790 function getLocalPart($str){ 00791 if($sstr = strrchr($str,':')){ 00792 // get unqualified name 00793 return substr( $sstr, 1 ); 00794 } else { 00795 return $str; 00796 } 00797 } 00798 00807 function getPrefix($str){ 00808 if($pos = strrpos($str,':')){ 00809 // get prefix 00810 return substr($str,0,$pos); 00811 } 00812 return false; 00813 } 00814 00822 function getNamespaceFromPrefix($prefix){ 00823 if (isset($this->namespaces[$prefix])) { 00824 return $this->namespaces[$prefix]; 00825 } 00826 //$this->setError("No namespace registered for prefix '$prefix'"); 00827 return false; 00828 } 00829 00838 function getPrefixFromNamespace($ns) { 00839 foreach ($this->namespaces as $p => $n) { 00840 if ($ns == $n || $ns == $p) { 00841 $this->usedNamespaces[$p] = $n; 00842 return $p; 00843 } 00844 } 00845 return false; 00846 } 00847 00854 function getmicrotime() { 00855 if (function_exists('gettimeofday')) { 00856 $tod = gettimeofday(); 00857 $sec = $tod['sec']; 00858 $usec = $tod['usec']; 00859 } else { 00860 $sec = time(); 00861 $usec = 0; 00862 } 00863 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); 00864 } 00865 00873 function varDump($data) { 00874 ob_start(); 00875 var_dump($data); 00876 $ret_val = ob_get_contents(); 00877 ob_end_clean(); 00878 return $ret_val; 00879 } 00880 00887 function __toString() { 00888 return $this->varDump($this); 00889 } 00890 } 00891 00892 // XML Schema Datatype Helper Functions 00893 00894 //xsd:dateTime helpers 00895 00904 function timestamp_to_iso8601($timestamp,$utc=true){ 00905 $datestr = date('Y-m-d\TH:i:sO',$timestamp); 00906 $pos = strrpos($datestr, "+"); 00907 if ($pos === FALSE) { 00908 $pos = strrpos($datestr, "-"); 00909 } 00910 if ($pos !== FALSE) { 00911 if (strlen($datestr) == $pos + 5) { 00912 $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); 00913 } 00914 } 00915 if($utc){ 00916 $eregStr = 00917 '([0-9]{4})-'. // centuries & years CCYY- 00918 '([0-9]{2})-'. // months MM- 00919 '([0-9]{2})'. // days DD 00920 'T'. // separator T 00921 '([0-9]{2}):'. // hours hh: 00922 '([0-9]{2}):'. // minutes mm: 00923 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... 00924 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 00925 00926 if(ereg($eregStr,$datestr,$regs)){ 00927 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); 00928 } 00929 return false; 00930 } else { 00931 return $datestr; 00932 } 00933 } 00934 00942 function iso8601_to_timestamp($datestr){ 00943 $eregStr = 00944 '([0-9]{4})-'. // centuries & years CCYY- 00945 '([0-9]{2})-'. // months MM- 00946 '([0-9]{2})'. // days DD 00947 'T'. // separator T 00948 '([0-9]{2}):'. // hours hh: 00949 '([0-9]{2}):'. // minutes mm: 00950 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... 00951 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's 00952 if(ereg($eregStr,$datestr,$regs)){ 00953 // not utc 00954 if($regs[8] != 'Z'){ 00955 $op = substr($regs[8],0,1); 00956 $h = substr($regs[8],1,2); 00957 $m = substr($regs[8],strlen($regs[8])-2,2); 00958 if($op == '-'){ 00959 $regs[4] = $regs[4] + $h; 00960 $regs[5] = $regs[5] + $m; 00961 } elseif($op == '+'){ 00962 $regs[4] = $regs[4] - $h; 00963 $regs[5] = $regs[5] - $m; 00964 } 00965 } 00966 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); 00967 // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); 00968 } else { 00969 return false; 00970 } 00971 } 00972 00980 function usleepWindows($usec) 00981 { 00982 $start = gettimeofday(); 00983 00984 do 00985 { 00986 $stop = gettimeofday(); 00987 $timePassed = 1000000 * ($stop['sec'] - $start['sec']) 00988 + $stop['usec'] - $start['usec']; 00989 } 00990 while ($timePassed < $usec); 00991 } 00992 00993 ?><?php 00994 00995 00996 01005 class nusoap_fault extends nusoap_base { 01011 var $faultcode; 01017 var $faultactor; 01023 var $faultstring; 01029 var $faultdetail; 01030 01039 function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ 01040 parent::nusoap_base(); 01041 $this->faultcode = $faultcode; 01042 $this->faultactor = $faultactor; 01043 $this->faultstring = $faultstring; 01044 $this->faultdetail = $faultdetail; 01045 } 01046 01053 function serialize(){ 01054 $ns_string = ''; 01055 foreach($this->namespaces as $k => $v){ 01056 $ns_string .= "\n xmlns:$k=\"$v\""; 01057 } 01058 $return_msg = 01059 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'. 01060 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". 01061 '<SOAP-ENV:Body>'. 01062 '<SOAP-ENV:Fault>'. 01063 $this->serialize_val($this->faultcode, 'faultcode'). 01064 $this->serialize_val($this->faultactor, 'faultactor'). 01065 $this->serialize_val($this->faultstring, 'faultstring'). 01066 $this->serialize_val($this->faultdetail, 'detail'). 01067 '</SOAP-ENV:Fault>'. 01068 '</SOAP-ENV:Body>'. 01069 '</SOAP-ENV:Envelope>'; 01070 return $return_msg; 01071 } 01072 } 01073 01077 class soap_fault extends nusoap_fault { 01078 } 01079 01080 ?><?php 01081 01082 01083 01093 class nusoap_xmlschema extends nusoap_base { 01094 01095 // files 01096 var $schema = ''; 01097 var $xml = ''; 01098 // namespaces 01099 var $enclosingNamespaces; 01100 // schema info 01101 var $schemaInfo = array(); 01102 var $schemaTargetNamespace = ''; 01103 // types, elements, attributes defined by the schema 01104 var $attributes = array(); 01105 var $complexTypes = array(); 01106 var $complexTypeStack = array(); 01107 var $currentComplexType = null; 01108 var $elements = array(); 01109 var $elementStack = array(); 01110 var $currentElement = null; 01111 var $simpleTypes = array(); 01112 var $simpleTypeStack = array(); 01113 var $currentSimpleType = null; 01114 // imports 01115 var $imports = array(); 01116 // parser vars 01117 var $parser; 01118 var $position = 0; 01119 var $depth = 0; 01120 var $depth_array = array(); 01121 var $message = array(); 01122 var $defaultNamespace = array(); 01123 01132 function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ 01133 parent::nusoap_base(); 01134 $this->debug('nusoap_xmlschema class instantiated, inside constructor'); 01135 // files 01136 $this->schema = $schema; 01137 $this->xml = $xml; 01138 01139 // namespaces 01140 $this->enclosingNamespaces = $namespaces; 01141 $this->namespaces = array_merge($this->namespaces, $namespaces); 01142 01143 // parse schema file 01144 if($schema != ''){ 01145 $this->debug('initial schema file: '.$schema); 01146 $this->parseFile($schema, 'schema'); 01147 } 01148 01149 // parse xml file 01150 if($xml != ''){ 01151 $this->debug('initial xml file: '.$xml); 01152 $this->parseFile($xml, 'xml'); 01153 } 01154 01155 } 01156 01165 function parseFile($xml,$type){ 01166 // parse xml file 01167 if($xml != ""){ 01168 $xmlStr = @join("",@file($xml)); 01169 if($xmlStr == ""){ 01170 $msg = 'Error reading XML from '.$xml; 01171 $this->setError($msg); 01172 $this->debug($msg); 01173 return false; 01174 } else { 01175 $this->debug("parsing $xml"); 01176 $this->parseString($xmlStr,$type); 01177 $this->debug("done parsing $xml"); 01178 return true; 01179 } 01180 } 01181 return false; 01182 } 01183 01191 function parseString($xml,$type){ 01192 // parse xml string 01193 if($xml != ""){ 01194 01195 // Create an XML parser. 01196 $this->parser = xml_parser_create(); 01197 // Set the options for parsing the XML data. 01198 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 01199 01200 // Set the object for the parser. 01201 xml_set_object($this->parser, $this); 01202 01203 // Set the element handlers for the parser. 01204 if($type == "schema"){ 01205 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); 01206 xml_set_character_data_handler($this->parser,'schemaCharacterData'); 01207 } elseif($type == "xml"){ 01208 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); 01209 xml_set_character_data_handler($this->parser,'xmlCharacterData'); 01210 } 01211 01212 // Parse the XML file. 01213 if(!xml_parse($this->parser,$xml,true)){ 01214 // Display an error message. 01215 $errstr = sprintf('XML error parsing XML schema on line %d: %s', 01216 xml_get_current_line_number($this->parser), 01217 xml_error_string(xml_get_error_code($this->parser)) 01218 ); 01219 $this->debug($errstr); 01220 $this->debug("XML payload:\n" . $xml); 01221 $this->setError($errstr); 01222 } 01223 01224 xml_parser_free($this->parser); 01225 } else{ 01226 $this->debug('no xml passed to parseString()!!'); 01227 $this->setError('no xml passed to parseString()!!'); 01228 } 01229 } 01230 01238 function CreateTypeName($ename) { 01239 $scope = ''; 01240 for ($i = 0; $i < count($this->complexTypeStack); $i++) { 01241 $scope .= $this->complexTypeStack[$i] . '_'; 01242 } 01243 return $scope . $ename . '_ContainedType'; 01244 } 01245 01254 function schemaStartElement($parser, $name, $attrs) { 01255 01256 // position in the total number of elements, starting from 0 01257 $pos = $this->position++; 01258 $depth = $this->depth++; 01259 // set self as current value for this depth 01260 $this->depth_array[$depth] = $pos; 01261 $this->message[$pos] = array('cdata' => ''); 01262 if ($depth > 0) { 01263 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; 01264 } else { 01265 $this->defaultNamespace[$pos] = false; 01266 } 01267 01268 // get element prefix 01269 if($prefix = $this->getPrefix($name)){ 01270 // get unqualified name 01271 $name = $this->getLocalPart($name); 01272 } else { 01273 $prefix = ''; 01274 } 01275 01276 // loop thru attributes, expanding, and registering namespace declarations 01277 if(count($attrs) > 0){ 01278 foreach($attrs as $k => $v){ 01279 // if ns declarations, add to class level array of valid namespaces 01280 if(ereg("^xmlns",$k)){ 01281 //$this->xdebug("$k: $v"); 01282 //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); 01283 if($ns_prefix = substr(strrchr($k,':'),1)){ 01284 //$this->xdebug("Add namespace[$ns_prefix] = $v"); 01285 $this->namespaces[$ns_prefix] = $v; 01286 } else { 01287 $this->defaultNamespace[$pos] = $v; 01288 if (! $this->getPrefixFromNamespace($v)) { 01289 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; 01290 } 01291 } 01292 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ 01293 $this->XMLSchemaVersion = $v; 01294 $this->namespaces['xsi'] = $v.'-instance'; 01295 } 01296 } 01297 } 01298 foreach($attrs as $k => $v){ 01299 // expand each attribute 01300 $k = strpos($k,':') ? $this->expandQname($k) : $k; 01301 $v = strpos($v,':') ? $this->expandQname($v) : $v; 01302 $eAttrs[$k] = $v; 01303 } 01304 $attrs = $eAttrs; 01305 } else { 01306 $attrs = array(); 01307 } 01308 // find status, register data 01309 switch($name){ 01310 case 'all': // (optional) compositor content for a complexType 01311 case 'choice': 01312 case 'group': 01313 case 'sequence': 01314 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); 01315 $this->complexTypes[$this->currentComplexType]['compositor'] = $name; 01316 //if($name == 'all' || $name == 'sequence'){ 01317 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01318 //} 01319 break; 01320 case 'attribute': // complexType attribute 01321 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); 01322 $this->xdebug("parsing attribute:"); 01323 $this->appendDebug($this->varDump($attrs)); 01324 if (!isset($attrs['form'])) { 01325 // TODO: handle globals 01326 $attrs['form'] = $this->schemaInfo['attributeFormDefault']; 01327 } 01328 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 01329 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01330 if (!strpos($v, ':')) { 01331 // no namespace in arrayType attribute value... 01332 if ($this->defaultNamespace[$pos]) { 01333 // ...so use the default 01334 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01335 } 01336 } 01337 } 01338 if(isset($attrs['name'])){ 01339 $this->attributes[$attrs['name']] = $attrs; 01340 $aname = $attrs['name']; 01341 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ 01342 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { 01343 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01344 } else { 01345 $aname = ''; 01346 } 01347 } elseif(isset($attrs['ref'])){ 01348 $aname = $attrs['ref']; 01349 $this->attributes[$attrs['ref']] = $attrs; 01350 } 01351 01352 if($this->currentComplexType){ // This should *always* be 01353 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; 01354 } 01355 // arrayType attribute 01356 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ 01357 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01358 $prefix = $this->getPrefix($aname); 01359 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ 01360 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; 01361 } else { 01362 $v = ''; 01363 } 01364 if(strpos($v,'[,]')){ 01365 $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; 01366 } 01367 $v = substr($v,0,strpos($v,'[')); // clip the [] 01368 if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ 01369 $v = $this->XMLSchemaVersion.':'.$v; 01370 } 01371 $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; 01372 } 01373 break; 01374 case 'complexContent': // (optional) content for a complexType 01375 $this->xdebug("do nothing for element $name"); 01376 break; 01377 case 'complexType': 01378 array_push($this->complexTypeStack, $this->currentComplexType); 01379 if(isset($attrs['name'])){ 01380 // TODO: what is the scope of named complexTypes that appear 01381 // nested within other c complexTypes? 01382 $this->xdebug('processing named complexType '.$attrs['name']); 01383 //$this->currentElement = false; 01384 $this->currentComplexType = $attrs['name']; 01385 $this->complexTypes[$this->currentComplexType] = $attrs; 01386 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 01387 // This is for constructs like 01388 // <complexType name="ListOfString" base="soap:Array"> 01389 // <sequence> 01390 // <element name="string" type="xsd:string" 01391 // minOccurs="0" maxOccurs="unbounded" /> 01392 // </sequence> 01393 // </complexType> 01394 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 01395 $this->xdebug('complexType is unusual array'); 01396 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01397 } else { 01398 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01399 } 01400 } else { 01401 $name = $this->CreateTypeName($this->currentElement); 01402 $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); 01403 $this->currentComplexType = $name; 01404 //$this->currentElement = false; 01405 $this->complexTypes[$this->currentComplexType] = $attrs; 01406 $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; 01407 // This is for constructs like 01408 // <complexType name="ListOfString" base="soap:Array"> 01409 // <sequence> 01410 // <element name="string" type="xsd:string" 01411 // minOccurs="0" maxOccurs="unbounded" /> 01412 // </sequence> 01413 // </complexType> 01414 if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ 01415 $this->xdebug('complexType is unusual array'); 01416 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01417 } else { 01418 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; 01419 } 01420 } 01421 break; 01422 case 'element': 01423 array_push($this->elementStack, $this->currentElement); 01424 if (!isset($attrs['form'])) { 01425 if ($this->currentComplexType) { 01426 $attrs['form'] = $this->schemaInfo['elementFormDefault']; 01427 } else { 01428 // global 01429 $attrs['form'] = 'qualified'; 01430 } 01431 } 01432 if(isset($attrs['type'])){ 01433 $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); 01434 if (! $this->getPrefix($attrs['type'])) { 01435 if ($this->defaultNamespace[$pos]) { 01436 $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; 01437 $this->xdebug('used default namespace to make type ' . $attrs['type']); 01438 } 01439 } 01440 // This is for constructs like 01441 // <complexType name="ListOfString" base="soap:Array"> 01442 // <sequence> 01443 // <element name="string" type="xsd:string" 01444 // minOccurs="0" maxOccurs="unbounded" /> 01445 // </sequence> 01446 // </complexType> 01447 if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { 01448 $this->xdebug('arrayType for unusual array is ' . $attrs['type']); 01449 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; 01450 } 01451 $this->currentElement = $attrs['name']; 01452 $ename = $attrs['name']; 01453 } elseif(isset($attrs['ref'])){ 01454 $this->xdebug("processing element as ref to ".$attrs['ref']); 01455 $this->currentElement = "ref to ".$attrs['ref']; 01456 $ename = $this->getLocalPart($attrs['ref']); 01457 } else { 01458 $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); 01459 $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); 01460 $this->currentElement = $attrs['name']; 01461 $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; 01462 $ename = $attrs['name']; 01463 } 01464 if (isset($ename) && $this->currentComplexType) { 01465 $this->xdebug("add element $ename to complexType $this->currentComplexType"); 01466 $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; 01467 } elseif (!isset($attrs['ref'])) { 01468 $this->xdebug("add element $ename to elements array"); 01469 $this->elements[ $attrs['name'] ] = $attrs; 01470 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 01471 } 01472 break; 01473 case 'enumeration': // restriction value list member 01474 $this->xdebug('enumeration ' . $attrs['value']); 01475 if ($this->currentSimpleType) { 01476 $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; 01477 } elseif ($this->currentComplexType) { 01478 $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; 01479 } 01480 break; 01481 case 'extension': // simpleContent or complexContent type extension 01482 $this->xdebug('extension ' . $attrs['base']); 01483 if ($this->currentComplexType) { 01484 $ns = $this->getPrefix($attrs['base']); 01485 if ($ns == '') { 01486 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; 01487 } elseif ($this->getNamespaceFromPrefix($ns)) { 01488 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; 01489 } 01490 } 01491 break; 01492 case 'import': 01493 if (isset($attrs['schemaLocation'])) { 01494 $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); 01495 $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); 01496 } else { 01497 $this->xdebug('import namespace ' . $attrs['namespace']); 01498 $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 01499 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 01500 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 01501 } 01502 } 01503 break; 01504 case 'include': 01505 if (isset($attrs['schemaLocation'])) { 01506 $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); 01507 $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); 01508 } else { 01509 $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); 01510 } 01511 break; 01512 case 'list': // simpleType value list 01513 $this->xdebug("do nothing for element $name"); 01514 break; 01515 case 'restriction': // simpleType, simpleContent or complexContent value restriction 01516 $this->xdebug('restriction ' . $attrs['base']); 01517 if($this->currentSimpleType){ 01518 $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; 01519 } elseif($this->currentComplexType){ 01520 $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; 01521 if(strstr($attrs['base'],':') == ':Array'){ 01522 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; 01523 } 01524 } 01525 break; 01526 case 'schema': 01527 $this->schemaInfo = $attrs; 01528 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); 01529 if (isset($attrs['targetNamespace'])) { 01530 $this->schemaTargetNamespace = $attrs['targetNamespace']; 01531 } 01532 if (!isset($attrs['elementFormDefault'])) { 01533 $this->schemaInfo['elementFormDefault'] = 'unqualified'; 01534 } 01535 if (!isset($attrs['attributeFormDefault'])) { 01536 $this->schemaInfo['attributeFormDefault'] = 'unqualified'; 01537 } 01538 break; 01539 case 'simpleContent': // (optional) content for a complexType 01540 $this->xdebug("do nothing for element $name"); 01541 break; 01542 case 'simpleType': 01543 array_push($this->simpleTypeStack, $this->currentSimpleType); 01544 if(isset($attrs['name'])){ 01545 $this->xdebug("processing simpleType for name " . $attrs['name']); 01546 $this->currentSimpleType = $attrs['name']; 01547 $this->simpleTypes[ $attrs['name'] ] = $attrs; 01548 $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; 01549 $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; 01550 } else { 01551 $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); 01552 $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); 01553 $this->currentSimpleType = $name; 01554 //$this->currentElement = false; 01555 $this->simpleTypes[$this->currentSimpleType] = $attrs; 01556 $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; 01557 } 01558 break; 01559 case 'union': // simpleType type list 01560 $this->xdebug("do nothing for element $name"); 01561 break; 01562 default: 01563 $this->xdebug("do not have any logic to process element $name"); 01564 } 01565 } 01566 01574 function schemaEndElement($parser, $name) { 01575 // bring depth down a notch 01576 $this->depth--; 01577 // position of current element is equal to the last value left in depth_array for my depth 01578 if(isset($this->depth_array[$this->depth])){ 01579 $pos = $this->depth_array[$this->depth]; 01580 } 01581 // get element prefix 01582 if ($prefix = $this->getPrefix($name)){ 01583 // get unqualified name 01584 $name = $this->getLocalPart($name); 01585 } else { 01586 $prefix = ''; 01587 } 01588 // move on... 01589 if($name == 'complexType'){ 01590 $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); 01591 $this->currentComplexType = array_pop($this->complexTypeStack); 01592 //$this->currentElement = false; 01593 } 01594 if($name == 'element'){ 01595 $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); 01596 $this->currentElement = array_pop($this->elementStack); 01597 } 01598 if($name == 'simpleType'){ 01599 $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); 01600 $this->currentSimpleType = array_pop($this->simpleTypeStack); 01601 } 01602 } 01603 01611 function schemaCharacterData($parser, $data){ 01612 $pos = $this->depth_array[$this->depth - 1]; 01613 $this->message[$pos]['cdata'] .= $data; 01614 } 01615 01621 function serializeSchema(){ 01622 01623 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); 01624 $xml = ''; 01625 // imports 01626 if (sizeof($this->imports) > 0) { 01627 foreach($this->imports as $ns => $list) { 01628 foreach ($list as $ii) { 01629 if ($ii['location'] != '') { 01630 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; 01631 } else { 01632 $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; 01633 } 01634 } 01635 } 01636 } 01637 // complex types 01638 foreach($this->complexTypes as $typeName => $attrs){ 01639 $contentStr = ''; 01640 // serialize child elements 01641 if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ 01642 foreach($attrs['elements'] as $element => $eParts){ 01643 if(isset($eParts['ref'])){ 01644 $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; 01645 } else { 01646 $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; 01647 foreach ($eParts as $aName => $aValue) { 01648 // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable 01649 if ($aName != 'name' && $aName != 'type') { 01650 $contentStr .= " $aName=\"$aValue\""; 01651 } 01652 } 01653 $contentStr .= "/>\n"; 01654 } 01655 } 01656 // compositor wraps elements 01657 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { 01658 $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; 01659 } 01660 } 01661 // attributes 01662 if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ 01663 foreach($attrs['attrs'] as $attr => $aParts){ 01664 $contentStr .= " <$schemaPrefix:attribute"; 01665 foreach ($aParts as $a => $v) { 01666 if ($a == 'ref' || $a == 'type') { 01667 $contentStr .= " $a=\"".$this->contractQName($v).'"'; 01668 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { 01669 $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; 01670 $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; 01671 } else { 01672 $contentStr .= " $a=\"$v\""; 01673 } 01674 } 01675 $contentStr .= "/>\n"; 01676 } 01677 } 01678 // if restriction 01679 if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ 01680 $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; 01681 // complex or simple content 01682 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ 01683 $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n"; 01684 } 01685 } 01686 // finalize complex type 01687 if($contentStr != ''){ 01688 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n"; 01689 } else { 01690 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; 01691 } 01692 $xml .= $contentStr; 01693 } 01694 // simple types 01695 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ 01696 foreach($this->simpleTypes as $typeName => $eParts){ 01697 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; 01698 if (isset($eParts['enumeration'])) { 01699 foreach ($eParts['enumeration'] as $e) { 01700 $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; 01701 } 01702 } 01703 $xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>"; 01704 } 01705 } 01706 // elements 01707 if(isset($this->elements) && count($this->elements) > 0){ 01708 foreach($this->elements as $element => $eParts){ 01709 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; 01710 } 01711 } 01712 // attributes 01713 if(isset($this->attributes) && count($this->attributes) > 0){ 01714 foreach($this->attributes as $attr => $aParts){ 01715 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; 01716 } 01717 } 01718 // finish 'er up 01719 $attr = ''; 01720 foreach ($this->schemaInfo as $k => $v) { 01721 if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { 01722 $attr .= " $k=\"$v\""; 01723 } 01724 } 01725 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; 01726 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { 01727 $el .= " xmlns:$nsp=\"$ns\""; 01728 } 01729 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n"; 01730 return $xml; 01731 } 01732 01739 function xdebug($string){ 01740 $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); 01741 } 01742 01755 function getPHPType($type,$ns){ 01756 if(isset($this->typemap[$ns][$type])){ 01757 //print "found type '$type' and ns $ns in typemap<br>"; 01758 return $this->typemap[$ns][$type]; 01759 } elseif(isset($this->complexTypes[$type])){ 01760 //print "getting type '$type' and ns $ns from complexTypes array<br>"; 01761 return $this->complexTypes[$type]['phpType']; 01762 } 01763 return false; 01764 } 01765 01788 function getTypeDef($type){ 01789 //$this->debug("in getTypeDef for type $type"); 01790 if (substr($type, -1) == '^') { 01791 $is_element = 1; 01792 $type = substr($type, 0, -1); 01793 } else { 01794 $is_element = 0; 01795 } 01796 01797 if((! $is_element) && isset($this->complexTypes[$type])){ 01798 $this->xdebug("in getTypeDef, found complexType $type"); 01799 return $this->complexTypes[$type]; 01800 } elseif((! $is_element) && isset($this->simpleTypes[$type])){ 01801 $this->xdebug("in getTypeDef, found simpleType $type"); 01802 if (!isset($this->simpleTypes[$type]['phpType'])) { 01803 // get info for type to tack onto the simple type 01804 // TODO: can this ever really apply (i.e. what is a simpleType really?) 01805 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); 01806 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); 01807 $etype = $this->getTypeDef($uqType); 01808 if ($etype) { 01809 $this->xdebug("in getTypeDef, found type for simpleType $type:"); 01810 $this->xdebug($this->varDump($etype)); 01811 if (isset($etype['phpType'])) { 01812 $this->simpleTypes[$type]['phpType'] = $etype['phpType']; 01813 } 01814 if (isset($etype['elements'])) { 01815 $this->simpleTypes[$type]['elements'] = $etype['elements']; 01816 } 01817 } 01818 } 01819 return $this->simpleTypes[$type]; 01820 } elseif(isset($this->elements[$type])){ 01821 $this->xdebug("in getTypeDef, found element $type"); 01822 if (!isset($this->elements[$type]['phpType'])) { 01823 // get info for type to tack onto the element 01824 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); 01825 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); 01826 $etype = $this->getTypeDef($uqType); 01827 if ($etype) { 01828 $this->xdebug("in getTypeDef, found type for element $type:"); 01829 $this->xdebug($this->varDump($etype)); 01830 if (isset($etype['phpType'])) { 01831 $this->elements[$type]['phpType'] = $etype['phpType']; 01832 } 01833 if (isset($etype['elements'])) { 01834 $this->elements[$type]['elements'] = $etype['elements']; 01835 } 01836 if (isset($etype['extensionBase'])) { 01837 $this->elements[$type]['extensionBase'] = $etype['extensionBase']; 01838 } 01839 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { 01840 $this->xdebug("in getTypeDef, element $type is an XSD type"); 01841 $this->elements[$type]['phpType'] = 'scalar'; 01842 } 01843 } 01844 return $this->elements[$type]; 01845 } elseif(isset($this->attributes[$type])){ 01846 $this->xdebug("in getTypeDef, found attribute $type"); 01847 return $this->attributes[$type]; 01848 } elseif (ereg('_ContainedType$', $type)) { 01849 $this->xdebug("in getTypeDef, have an untyped element $type"); 01850 $typeDef['typeClass'] = 'simpleType'; 01851 $typeDef['phpType'] = 'scalar'; 01852 $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; 01853 return $typeDef; 01854 } 01855 $this->xdebug("in getTypeDef, did not find $type"); 01856 return false; 01857 } 01858 01867 function serializeTypeDef($type){ 01868 //print "in sTD() for type $type<br>"; 01869 if($typeDef = $this->getTypeDef($type)){ 01870 $str .= '<'.$type; 01871 if(is_array($typeDef['attrs'])){ 01872 foreach($typeDef['attrs'] as $attName => $data){ 01873 $str .= " $attName=\"{type = ".$data['type']."}\""; 01874 } 01875 } 01876 $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; 01877 if(count($typeDef['elements']) > 0){ 01878 $str .= ">"; 01879 foreach($typeDef['elements'] as $element => $eData){ 01880 $str .= $this->serializeTypeDef($element); 01881 } 01882 $str .= "</$type>"; 01883 } elseif($typeDef['typeClass'] == 'element') { 01884 $str .= "></$type>"; 01885 } else { 01886 $str .= "/>"; 01887 } 01888 return $str; 01889 } 01890 return false; 01891 } 01892 01903 function typeToForm($name,$type){ 01904 // get typedef 01905 if($typeDef = $this->getTypeDef($type)){ 01906 // if struct 01907 if($typeDef['phpType'] == 'struct'){ 01908 $buffer .= '<table>'; 01909 foreach($typeDef['elements'] as $child => $childDef){ 01910 $buffer .= " 01911 <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> 01912 <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; 01913 } 01914 $buffer .= '</table>'; 01915 // if array 01916 } elseif($typeDef['phpType'] == 'array'){ 01917 $buffer .= '<table>'; 01918 for($i=0;$i < 3; $i++){ 01919 $buffer .= " 01920 <tr><td align='right'>array item (type: $typeDef[arrayType]):</td> 01921 <td><input type='text' name='parameters[".$name."][]'></td></tr>"; 01922 } 01923 $buffer .= '</table>'; 01924 // if scalar 01925 } else { 01926 $buffer .= "<input type='text' name='parameters[$name]'>"; 01927 } 01928 } else { 01929 $buffer .= "<input type='text' name='parameters[$name]'>"; 01930 } 01931 return $buffer; 01932 } 01933 01975 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ 01976 $this->complexTypes[$name] = array( 01977 'name' => $name, 01978 'typeClass' => $typeClass, 01979 'phpType' => $phpType, 01980 'compositor'=> $compositor, 01981 'restrictionBase' => $restrictionBase, 01982 'elements' => $elements, 01983 'attrs' => $attrs, 01984 'arrayType' => $arrayType 01985 ); 01986 01987 $this->xdebug("addComplexType $name:"); 01988 $this->appendDebug($this->varDump($this->complexTypes[$name])); 01989 } 01990 02003 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 02004 $this->simpleTypes[$name] = array( 02005 'name' => $name, 02006 'typeClass' => $typeClass, 02007 'phpType' => $phpType, 02008 'type' => $restrictionBase, 02009 'enumeration' => $enumeration 02010 ); 02011 02012 $this->xdebug("addSimpleType $name:"); 02013 $this->appendDebug($this->varDump($this->simpleTypes[$name])); 02014 } 02015 02023 function addElement($attrs) { 02024 if (! $this->getPrefix($attrs['type'])) { 02025 $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; 02026 } 02027 $this->elements[ $attrs['name'] ] = $attrs; 02028 $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; 02029 02030 $this->xdebug("addElement " . $attrs['name']); 02031 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); 02032 } 02033 } 02034 02038 class XMLSchema extends nusoap_xmlschema { 02039 } 02040 02041 ?><?php 02042 02043 02044 02056 class soapval extends nusoap_base { 02063 var $name; 02070 var $type; 02077 var $value; 02084 var $element_ns; 02091 var $type_ns; 02098 var $attributes; 02099 02111 function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { 02112 parent::nusoap_base(); 02113 $this->name = $name; 02114 $this->type = $type; 02115 $this->value = $value; 02116 $this->element_ns = $element_ns; 02117 $this->type_ns = $type_ns; 02118 $this->attributes = $attributes; 02119 } 02120 02128 function serialize($use='encoded') { 02129 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); 02130 } 02131 02138 function decode(){ 02139 return $this->value; 02140 } 02141 } 02142 02143 02144 02145 ?><?php 02146 02147 02148 02158 class soap_transport_http extends nusoap_base { 02159 02160 var $url = ''; 02161 var $uri = ''; 02162 var $digest_uri = ''; 02163 var $scheme = ''; 02164 var $host = ''; 02165 var $port = ''; 02166 var $path = ''; 02167 var $request_method = 'POST'; 02168 var $protocol_version = '1.0'; 02169 var $encoding = ''; 02170 var $outgoing_headers = array(); 02171 var $incoming_headers = array(); 02172 var $incoming_cookies = array(); 02173 var $outgoing_payload = ''; 02174 var $incoming_payload = ''; 02175 var $response_status_line; // HTTP response status line 02176 var $useSOAPAction = true; 02177 var $persistentConnection = false; 02178 var $ch = false; // cURL handle 02179 var $ch_options = array(); // cURL custom options 02180 var $use_curl = false; // force cURL use 02181 var $proxy = null; // proxy information (associative array) 02182 var $username = ''; 02183 var $password = ''; 02184 var $authtype = ''; 02185 var $digestRequest = array(); 02186 var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) 02187 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' 02188 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' 02189 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' 02190 // passphrase: SSL key password/passphrase 02191 // certpassword: SSL certificate password 02192 // verifypeer: default is 1 02193 // verifyhost: default is 1 02194 02203 function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ 02204 parent::nusoap_base(); 02205 $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); 02206 $this->appendDebug($this->varDump($curl_options)); 02207 $this->setURL($url); 02208 if (is_array($curl_options)) { 02209 $this->ch_options = $curl_options; 02210 } 02211 $this->use_curl = $use_curl; 02212 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 02213 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); 02214 } 02215 02223 function setCurlOption($option, $value) { 02224 $this->debug("setCurlOption option=$option, value="); 02225 $this->appendDebug($this->varDump($value)); 02226 curl_setopt($this->ch, $option, $value); 02227 } 02228 02236 function setHeader($name, $value) { 02237 $this->outgoing_headers[$name] = $value; 02238 $this->debug("set header $name: $value"); 02239 } 02240 02247 function unsetHeader($name) { 02248 if (isset($this->outgoing_headers[$name])) { 02249 $this->debug("unset header $name"); 02250 unset($this->outgoing_headers[$name]); 02251 } 02252 } 02253 02260 function setURL($url) { 02261 $this->url = $url; 02262 02263 $u = parse_url($url); 02264 foreach($u as $k => $v){ 02265 $this->debug("parsed URL $k = $v"); 02266 $this->$k = $v; 02267 } 02268 02269 // add any GET params to path 02270 if(isset($u['query']) && $u['query'] != ''){ 02271 $this->path .= '?' . $u['query']; 02272 } 02273 02274 // set default port 02275 if(!isset($u['port'])){ 02276 if($u['scheme'] == 'https'){ 02277 $this->port = 443; 02278 } else { 02279 $this->port = 80; 02280 } 02281 } 02282 02283 $this->uri = $this->path; 02284 $this->digest_uri = $this->uri; 02285 02286 // build headers 02287 if (!isset($u['port'])) { 02288 $this->setHeader('Host', $this->host); 02289 } else { 02290 $this->setHeader('Host', $this->host.':'.$this->port); 02291 } 02292 02293 if (isset($u['user']) && $u['user'] != '') { 02294 $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); 02295 } 02296 } 02297 02304 function io_method() { 02305 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) 02306 return 'curl'; 02307 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) 02308 return 'socket'; 02309 return 'unknown'; 02310 } 02311 02320 function connect($connection_timeout=0,$response_timeout=30){ 02321 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like 02322 // "regular" socket. 02323 // TODO: disabled for now because OpenSSL must be *compiled* in (not just 02324 // loaded), and until PHP5 stream_get_wrappers is not available. 02325 // if ($this->scheme == 'https') { 02326 // if (version_compare(phpversion(), '4.3.0') >= 0) { 02327 // if (extension_loaded('openssl')) { 02328 // $this->scheme = 'ssl'; 02329 // $this->debug('Using SSL over OpenSSL'); 02330 // } 02331 // } 02332 // } 02333 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); 02334 if ($this->io_method() == 'socket') { 02335 if (!is_array($this->proxy)) { 02336 $host = $this->host; 02337 $port = $this->port; 02338 } else { 02339 $host = $this->proxy['host']; 02340 $port = $this->proxy['port']; 02341 } 02342 02343 // use persistent connection 02344 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ 02345 if (!feof($this->fp)) { 02346 $this->debug('Re-use persistent connection'); 02347 return true; 02348 } 02349 fclose($this->fp); 02350 $this->debug('Closed persistent connection at EOF'); 02351 } 02352 02353 // munge host if using OpenSSL 02354 if ($this->scheme == 'ssl') { 02355 $host = 'ssl://' . $host; 02356 } 02357 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); 02358 02359 // open socket 02360 if($connection_timeout > 0){ 02361 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); 02362 } else { 02363 $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); 02364 } 02365 02366 // test pointer 02367 if(!$this->fp) { 02368 $msg = 'Couldn\'t open socket connection to server ' . $this->url; 02369 if ($this->errno) { 02370 $msg .= ', Error ('.$this->errno.'): '.$this->error_str; 02371 } else { 02372 $msg .= ' prior to connect(). This is often a problem looking up the host name.'; 02373 } 02374 $this->debug($msg); 02375 $this->setError($msg); 02376 return false; 02377 } 02378 02379 // set response timeout 02380 $this->debug('set response timeout to ' . $response_timeout); 02381 socket_set_timeout( $this->fp, $response_timeout); 02382 02383 $this->debug('socket connected'); 02384 return true; 02385 } else if ($this->io_method() == 'curl') { 02386 if (!extension_loaded('curl')) { 02387 // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); 02388 $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to included cURL.'); 02389 return false; 02390 } 02391 // Avoid warnings when PHP does not have these options 02392 if (defined('CURLOPT_CONNECTIONTIMEOUT')) 02393 $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; 02394 else 02395 $CURLOPT_CONNECTIONTIMEOUT = 78; 02396 if (defined('CURLOPT_HTTPAUTH')) 02397 $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; 02398 else 02399 $CURLOPT_HTTPAUTH = 107; 02400 if (defined('CURLOPT_PROXYAUTH')) 02401 $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; 02402 else 02403 $CURLOPT_PROXYAUTH = 111; 02404 if (defined('CURLAUTH_BASIC')) 02405 $CURLAUTH_BASIC = CURLAUTH_BASIC; 02406 else 02407 $CURLAUTH_BASIC = 1; 02408 if (defined('CURLAUTH_DIGEST')) 02409 $CURLAUTH_DIGEST = CURLAUTH_DIGEST; 02410 else 02411 $CURLAUTH_DIGEST = 2; 02412 if (defined('CURLAUTH_NTLM')) 02413 $CURLAUTH_NTLM = CURLAUTH_NTLM; 02414 else 02415 $CURLAUTH_NTLM = 8; 02416 02417 $this->debug('connect using cURL'); 02418 // init CURL 02419 $this->ch = curl_init(); 02420 // set url 02421 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; 02422 // add path 02423 $hostURL .= $this->path; 02424 $this->setCurlOption(CURLOPT_URL, $hostURL); 02425 // follow location headers (re-directs) 02426 if (ini_get('safe_mode') || ini_get('open_basedir')) { 02427 $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); 02428 $this->debug('safe_mode = '); 02429 $this->appendDebug($this->varDump(ini_get('safe_mode'))); 02430 $this->debug('open_basedir = '); 02431 $this->appendDebug($this->varDump(ini_get('open_basedir'))); 02432 } else { 02433 $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); 02434 } 02435 // ask for headers in the response output 02436 $this->setCurlOption(CURLOPT_HEADER, 1); 02437 // ask for the response output as the return value 02438 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); 02439 // encode 02440 // We manage this ourselves through headers and encoding 02441 // if(function_exists('gzuncompress')){ 02442 // $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); 02443 // } 02444 // persistent connection 02445 if ($this->persistentConnection) { 02446 // I believe the following comment is now bogus, having applied to 02447 // the code when it used CURLOPT_CUSTOMREQUEST to send the request. 02448 // The way we send data, we cannot use persistent connections, since 02449 // there will be some "junk" at the end of our request. 02450 //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); 02451 $this->persistentConnection = false; 02452 $this->setHeader('Connection', 'close'); 02453 } 02454 // set timeouts 02455 if ($connection_timeout != 0) { 02456 $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); 02457 } 02458 if ($response_timeout != 0) { 02459 $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); 02460 } 02461 02462 if ($this->scheme == 'https') { 02463 $this->debug('set cURL SSL verify options'); 02464 // recent versions of cURL turn on peer/host checking by default, 02465 // while PHP binaries are not compiled with a default location for the 02466 // CA cert bundle, so disable peer/host checking. 02467 //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); 02468 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); 02469 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); 02470 02471 // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) 02472 if ($this->authtype == 'certificate') { 02473 $this->debug('set cURL certificate options'); 02474 if (isset($this->certRequest['cainfofile'])) { 02475 $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); 02476 } 02477 if (isset($this->certRequest['verifypeer'])) { 02478 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); 02479 } else { 02480 $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); 02481 } 02482 if (isset($this->certRequest['verifyhost'])) { 02483 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); 02484 } else { 02485 $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); 02486 } 02487 if (isset($this->certRequest['sslcertfile'])) { 02488 $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); 02489 } 02490 if (isset($this->certRequest['sslkeyfile'])) { 02491 $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); 02492 } 02493 if (isset($this->certRequest['passphrase'])) { 02494 $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); 02495 } 02496 if (isset($this->certRequest['certpassword'])) { 02497 $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); 02498 } 02499 } 02500 } 02501 if ($this->authtype && ($this->authtype != 'certificate')) { 02502 if ($this->username) { 02503 $this->debug('set cURL username/password'); 02504 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); 02505 } 02506 if ($this->authtype == 'basic') { 02507 $this->debug('set cURL for Basic authentication'); 02508 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); 02509 } 02510 if ($this->authtype == 'digest') { 02511 $this->debug('set cURL for digest authentication'); 02512 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); 02513 } 02514 if ($this->authtype == 'ntlm') { 02515 $this->debug('set cURL for NTLM authentication'); 02516 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); 02517 } 02518 } 02519 if (is_array($this->proxy)) { 02520 $this->debug('set cURL proxy options'); 02521 if ($this->proxy['port'] != '') { 02522 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); 02523 } else { 02524 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); 02525 } 02526 if ($this->proxy['username'] || $this->proxy['password']) { 02527 $this->debug('set cURL proxy authentication options'); 02528 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); 02529 if ($this->proxy['authtype'] == 'basic') { 02530 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); 02531 } 02532 if ($this->proxy['authtype'] == 'ntlm') { 02533 $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); 02534 } 02535 } 02536 } 02537 $this->debug('cURL connection set up'); 02538 return true; 02539 } else { 02540 $this->setError('Unknown scheme ' . $this->scheme); 02541 $this->debug('Unknown scheme ' . $this->scheme); 02542 return false; 02543 } 02544 } 02545 02556 function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { 02557 02558 $this->debug('entered send() with data of length: '.strlen($data)); 02559 02560 $this->tryagain = true; 02561 $tries = 0; 02562 while ($this->tryagain) { 02563 $this->tryagain = false; 02564 if ($tries++ < 2) { 02565 // make connnection 02566 if (!$this->connect($timeout, $response_timeout)){ 02567 return false; 02568 } 02569 02570 // send request 02571 if (!$this->sendRequest($data, $cookies)){ 02572 return false; 02573 } 02574 02575 // get response 02576 $respdata = $this->getResponse(); 02577 } else { 02578 $this->setError("Too many tries to get an OK response ($this->response_status_line)"); 02579 } 02580 } 02581 $this->debug('end of send()'); 02582 return $respdata; 02583 } 02584 02585 02597 function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { 02598 return $this->send($data, $timeout, $response_timeout, $cookies); 02599 } 02600 02611 function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { 02612 $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); 02613 $this->appendDebug($this->varDump($digestRequest)); 02614 $this->debug("certRequest="); 02615 $this->appendDebug($this->varDump($certRequest)); 02616 // cf. RFC 2617 02617 if ($authtype == 'basic') { 02618 $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); 02619 } elseif ($authtype == 'digest') { 02620 if (isset($digestRequest['nonce'])) { 02621 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; 02622 02623 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) 02624 02625 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd 02626 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; 02627 02628 // H(A1) = MD5(A1) 02629 $HA1 = md5($A1); 02630 02631 // A2 = Method ":" digest-uri-value 02632 $A2 = $this->request_method . ':' . $this->digest_uri; 02633 02634 // H(A2) 02635 $HA2 = md5($A2); 02636 02637 // KD(secret, data) = H(concat(secret, ":", data)) 02638 // if qop == auth: 02639 // request-digest = <"> < KD ( H(A1), unq(nonce-value) 02640 // ":" nc-value 02641 // ":" unq(cnonce-value) 02642 // ":" unq(qop-value) 02643 // ":" H(A2) 02644 // ) <"> 02645 // if qop is missing, 02646 // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> 02647 02648 $unhashedDigest = ''; 02649 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; 02650 $cnonce = $nonce; 02651 if ($digestRequest['qop'] != '') { 02652 $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; 02653 } else { 02654 $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; 02655 } 02656 02657 $hashedDigest = md5($unhashedDigest); 02658 02659 $opaque = ''; 02660 if (isset($digestRequest['opaque'])) { 02661 $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; 02662 } 02663 02664 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); 02665 } 02666 } elseif ($authtype == 'certificate') { 02667 $this->certRequest = $certRequest; 02668 $this->debug('Authorization header not set for certificate'); 02669 } elseif ($authtype == 'ntlm') { 02670 // do nothing 02671 $this->debug('Authorization header not set for ntlm'); 02672 } 02673 $this->username = $username; 02674 $this->password = $password; 02675 $this->authtype = $authtype; 02676 $this->digestRequest = $digestRequest; 02677 } 02678 02685 function setSOAPAction($soapaction) { 02686 $this->setHeader('SOAPAction', '"' . $soapaction . '"'); 02687 } 02688 02695 function setEncoding($enc='gzip, deflate') { 02696 if (function_exists('gzdeflate')) { 02697 $this->protocol_version = '1.1'; 02698 $this->setHeader('Accept-Encoding', $enc); 02699 if (!isset($this->outgoing_headers['Connection'])) { 02700 $this->setHeader('Connection', 'close'); 02701 $this->persistentConnection = false; 02702 } 02703 set_magic_quotes_runtime(0); 02704 // deprecated 02705 $this->encoding = $enc; 02706 } 02707 } 02708 02719 function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { 02720 if ($proxyhost) { 02721 $this->proxy = array( 02722 'host' => $proxyhost, 02723 'port' => $proxyport, 02724 'username' => $proxyusername, 02725 'password' => $proxypassword, 02726 'authtype' => $proxyauthtype 02727 ); 02728 if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { 02729 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); 02730 } 02731 } else { 02732 $this->debug('remove proxy'); 02733 $proxy = null; 02734 unsetHeader('Proxy-Authorization'); 02735 } 02736 } 02737 02738 02747 function isSkippableCurlHeader(&$data) { 02748 $skipHeaders = array( 'HTTP/1.1 100', 02749 'HTTP/1.0 301', 02750 'HTTP/1.1 301', 02751 'HTTP/1.0 302', 02752 'HTTP/1.1 302', 02753 'HTTP/1.0 401', 02754 'HTTP/1.1 401', 02755 'HTTP/1.0 200 Connection established'); 02756 foreach ($skipHeaders as $hd) { 02757 $prefix = substr($data, 0, strlen($hd)); 02758 if ($prefix == $hd) return true; 02759 } 02760 02761 return false; 02762 } 02763 02774 function decodeChunked($buffer, $lb){ 02775 // length := 0 02776 $length = 0; 02777 $new = ''; 02778 02779 // read chunk-size, chunk-extension (if any) and CRLF 02780 // get the position of the linebreak 02781 $chunkend = strpos($buffer, $lb); 02782 if ($chunkend == FALSE) { 02783 $this->debug('no linebreak found in decodeChunked'); 02784 return $new; 02785 } 02786 $temp = substr($buffer,0,$chunkend); 02787 $chunk_size = hexdec( trim($temp) ); 02788 $chunkstart = $chunkend + strlen($lb); 02789 // while (chunk-size > 0) { 02790 while ($chunk_size > 0) { 02791 $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); 02792 $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); 02793 02794 // Just in case we got a broken connection 02795 if ($chunkend == FALSE) { 02796 $chunk = substr($buffer,$chunkstart); 02797 // append chunk-data to entity-body 02798 $new .= $chunk; 02799 $length += strlen($chunk); 02800 break; 02801 } 02802 02803 // read chunk-data and CRLF 02804 $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); 02805 // append chunk-data to entity-body 02806 $new .= $chunk; 02807 // length := length + chunk-size 02808 $length += strlen($chunk); 02809 // read chunk-size and CRLF 02810 $chunkstart = $chunkend + strlen($lb); 02811 02812 $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); 02813 if ($chunkend == FALSE) { 02814 break; //Just in case we got a broken connection 02815 } 02816 $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); 02817 $chunk_size = hexdec( trim($temp) ); 02818 $chunkstart = $chunkend; 02819 } 02820 return $new; 02821 } 02822 02831 function buildPayload($data, $cookie_str = '') { 02832 // Note: for cURL connections, $this->outgoing_payload is ignored, 02833 // as is the Content-Length header, but these are still created as 02834 // debugging guides. 02835 02836 // add content-length header 02837 if ($this->request_method != 'GET') { 02838 $this->setHeader('Content-Length', strlen($data)); 02839 } 02840 02841 // start building outgoing payload: 02842 if ($this->proxy) { 02843 $uri = $this->url; 02844 } else { 02845 $uri = $this->uri; 02846 } 02847 $req = "$this->request_method $uri HTTP/$this->protocol_version"; 02848 $this->debug("HTTP request: $req"); 02849 $this->outgoing_payload = "$req\r\n"; 02850 02851 // loop thru headers, serializing 02852 foreach($this->outgoing_headers as $k => $v){ 02853 $hdr = $k.': '.$v; 02854 $this->debug("HTTP header: $hdr"); 02855 $this->outgoing_payload .= "$hdr\r\n"; 02856 } 02857 02858 // add any cookies 02859 if ($cookie_str != '') { 02860 $hdr = 'Cookie: '.$cookie_str; 02861 $this->debug("HTTP header: $hdr"); 02862 $this->outgoing_payload .= "$hdr\r\n"; 02863 } 02864 02865 // header/body separator 02866 $this->outgoing_payload .= "\r\n"; 02867 02868 // add data 02869 $this->outgoing_payload .= $data; 02870 } 02871 02880 function sendRequest($data, $cookies = NULL) { 02881 // build cookie string 02882 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); 02883 02884 // build payload 02885 $this->buildPayload($data, $cookie_str); 02886 02887 if ($this->io_method() == 'socket') { 02888 // send payload 02889 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { 02890 $this->setError('couldn\'t write message data to socket'); 02891 $this->debug('couldn\'t write message data to socket'); 02892 return false; 02893 } 02894 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); 02895 return true; 02896 } else if ($this->io_method() == 'curl') { 02897 // set payload 02898 // cURL does say this should only be the verb, and in fact it 02899 // turns out that the URI and HTTP version are appended to this, which 02900 // some servers refuse to work with (so we no longer use this method!) 02901 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); 02902 $curl_headers = array(); 02903 foreach($this->outgoing_headers as $k => $v){ 02904 if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { 02905 $this->debug("Skip cURL header $k: $v"); 02906 } else { 02907 $curl_headers[] = "$k: $v"; 02908 } 02909 } 02910 if ($cookie_str != '') { 02911 $curl_headers[] = 'Cookie: ' . $cookie_str; 02912 } 02913 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); 02914 $this->debug('set cURL HTTP headers'); 02915 if ($this->request_method == "POST") { 02916 $this->setCurlOption(CURLOPT_POST, 1); 02917 $this->setCurlOption(CURLOPT_POSTFIELDS, $data); 02918 $this->debug('set cURL POST data'); 02919 } else { 02920 } 02921 // insert custom user-set cURL options 02922 foreach ($this->ch_options as $key => $val) { 02923 $this->setCurlOption($key, $val); 02924 } 02925 02926 $this->debug('set cURL payload'); 02927 return true; 02928 } 02929 } 02930 02937 function getResponse(){ 02938 $this->incoming_payload = ''; 02939 02940 if ($this->io_method() == 'socket') { 02941 // loop until headers have been retrieved 02942 $data = ''; 02943 while (!isset($lb)){ 02944 02945 // We might EOF during header read. 02946 if(feof($this->fp)) { 02947 $this->incoming_payload = $data; 02948 $this->debug('found no headers before EOF after length ' . strlen($data)); 02949 $this->debug("received before EOF:\n" . $data); 02950 $this->setError('server failed to send headers'); 02951 return false; 02952 } 02953 02954 $tmp = fgets($this->fp, 256); 02955 $tmplen = strlen($tmp); 02956 $this->debug("read line of $tmplen bytes: " . trim($tmp)); 02957 02958 if ($tmplen == 0) { 02959 $this->incoming_payload = $data; 02960 $this->debug('socket read of headers timed out after length ' . strlen($data)); 02961 $this->debug("read before timeout: " . $data); 02962 $this->setError('socket read of headers timed out'); 02963 return false; 02964 } 02965 02966 $data .= $tmp; 02967 $pos = strpos($data,"\r\n\r\n"); 02968 if($pos > 1){ 02969 $lb = "\r\n"; 02970 } else { 02971 $pos = strpos($data,"\n\n"); 02972 if($pos > 1){ 02973 $lb = "\n"; 02974 } 02975 } 02976 // remove 100 headers 02977 if (isset($lb) && ereg('^HTTP/1.1 100',$data)) { 02978 unset($lb); 02979 $data = ''; 02980 }// 02981 } 02982 // store header data 02983 $this->incoming_payload .= $data; 02984 $this->debug('found end of headers after length ' . strlen($data)); 02985 // process headers 02986 $header_data = trim(substr($data,0,$pos)); 02987 $header_array = explode($lb,$header_data); 02988 $this->incoming_headers = array(); 02989 $this->incoming_cookies = array(); 02990 foreach($header_array as $header_line){ 02991 $arr = explode(':',$header_line, 2); 02992 if(count($arr) > 1){ 02993 $header_name = strtolower(trim($arr[0])); 02994 $this->incoming_headers[$header_name] = trim($arr[1]); 02995 if ($header_name == 'set-cookie') { 02996 // TODO: allow multiple cookies from parseCookie 02997 $cookie = $this->parseCookie(trim($arr[1])); 02998 if ($cookie) { 02999 $this->incoming_cookies[] = $cookie; 03000 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 03001 } else { 03002 $this->debug('did not find cookie in ' . trim($arr[1])); 03003 } 03004 } 03005 } else if (isset($header_name)) { 03006 // append continuation line to previous header 03007 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 03008 } 03009 } 03010 03011 // loop until msg has been received 03012 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { 03013 $content_length = 2147483647; // ignore any content-length header 03014 $chunked = true; 03015 $this->debug("want to read chunked content"); 03016 } elseif (isset($this->incoming_headers['content-length'])) { 03017 $content_length = $this->incoming_headers['content-length']; 03018 $chunked = false; 03019 $this->debug("want to read content of length $content_length"); 03020 } else { 03021 $content_length = 2147483647; 03022 $chunked = false; 03023 $this->debug("want to read content to EOF"); 03024 } 03025 $data = ''; 03026 do { 03027 if ($chunked) { 03028 $tmp = fgets($this->fp, 256); 03029 $tmplen = strlen($tmp); 03030 $this->debug("read chunk line of $tmplen bytes"); 03031 if ($tmplen == 0) { 03032 $this->incoming_payload = $data; 03033 $this->debug('socket read of chunk length timed out after length ' . strlen($data)); 03034 $this->debug("read before timeout:\n" . $data); 03035 $this->setError('socket read of chunk length timed out'); 03036 return false; 03037 } 03038 $content_length = hexdec(trim($tmp)); 03039 $this->debug("chunk length $content_length"); 03040 } 03041 $strlen = 0; 03042 while (($strlen < $content_length) && (!feof($this->fp))) { 03043 $readlen = min(8192, $content_length - $strlen); 03044 $tmp = fread($this->fp, $readlen); 03045 $tmplen = strlen($tmp); 03046 $this->debug("read buffer of $tmplen bytes"); 03047 if (($tmplen == 0) && (!feof($this->fp))) { 03048 $this->incoming_payload = $data; 03049 $this->debug('socket read of body timed out after length ' . strlen($data)); 03050 $this->debug("read before timeout:\n" . $data); 03051 $this->setError('socket read of body timed out'); 03052 return false; 03053 } 03054 $strlen += $tmplen; 03055 $data .= $tmp; 03056 } 03057 if ($chunked && ($content_length > 0)) { 03058 $tmp = fgets($this->fp, 256); 03059 $tmplen = strlen($tmp); 03060 $this->debug("read chunk terminator of $tmplen bytes"); 03061 if ($tmplen == 0) { 03062 $this->incoming_payload = $data; 03063 $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); 03064 $this->debug("read before timeout:\n" . $data); 03065 $this->setError('socket read of chunk terminator timed out'); 03066 return false; 03067 } 03068 } 03069 } while ($chunked && ($content_length > 0) && (!feof($this->fp))); 03070 if (feof($this->fp)) { 03071 $this->debug('read to EOF'); 03072 } 03073 $this->debug('read body of length ' . strlen($data)); 03074 $this->incoming_payload .= $data; 03075 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); 03076 03077 // close filepointer 03078 if( 03079 (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || 03080 (! $this->persistentConnection) || feof($this->fp)){ 03081 fclose($this->fp); 03082 $this->fp = false; 03083 $this->debug('closed socket'); 03084 } 03085 03086 // connection was closed unexpectedly 03087 if($this->incoming_payload == ''){ 03088 $this->setError('no response from server'); 03089 return false; 03090 } 03091 03092 // decode transfer-encoding 03093 // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ 03094 // if(!$data = $this->decodeChunked($data, $lb)){ 03095 // $this->setError('Decoding of chunked data failed'); 03096 // return false; 03097 // } 03098 //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>"; 03099 // set decoded payload 03100 // $this->incoming_payload = $header_data.$lb.$lb.$data; 03101 // } 03102 03103 } else if ($this->io_method() == 'curl') { 03104 // send and receive 03105 $this->debug('send and receive with cURL'); 03106 $this->incoming_payload = curl_exec($this->ch); 03107 $data = $this->incoming_payload; 03108 03109 $cErr = curl_error($this->ch); 03110 if ($cErr != '') { 03111 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>'; 03112 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE 03113 foreach(curl_getinfo($this->ch) as $k => $v){ 03114 $err .= "$k: $v<br>"; 03115 } 03116 $this->debug($err); 03117 $this->setError($err); 03118 curl_close($this->ch); 03119 return false; 03120 } else { 03121 //echo '<pre>'; 03122 //var_dump(curl_getinfo($this->ch)); 03123 //echo '</pre>'; 03124 } 03125 // close curl 03126 $this->debug('No cURL error, closing cURL'); 03127 curl_close($this->ch); 03128 03129 // try removing skippable headers 03130 $savedata = $data; 03131 while ($this->isSkippableCurlHeader($data)) { 03132 $this->debug("Found HTTP header to skip"); 03133 if ($pos = strpos($data,"\r\n\r\n")) { 03134 $data = ltrim(substr($data,$pos)); 03135 } elseif($pos = strpos($data,"\n\n") ) { 03136 $data = ltrim(substr($data,$pos)); 03137 } 03138 } 03139 03140 if ($data == '') { 03141 // have nothing left; just remove 100 header(s) 03142 $data = $savedata; 03143 while (ereg('^HTTP/1.1 100',$data)) { 03144 if ($pos = strpos($data,"\r\n\r\n")) { 03145 $data = ltrim(substr($data,$pos)); 03146 } elseif($pos = strpos($data,"\n\n") ) { 03147 $data = ltrim(substr($data,$pos)); 03148 } 03149 } 03150 } 03151 03152 // separate content from HTTP headers 03153 if ($pos = strpos($data,"\r\n\r\n")) { 03154 $lb = "\r\n"; 03155 } elseif( $pos = strpos($data,"\n\n")) { 03156 $lb = "\n"; 03157 } else { 03158 $this->debug('no proper separation of headers and document'); 03159 $this->setError('no proper separation of headers and document'); 03160 return false; 03161 } 03162 $header_data = trim(substr($data,0,$pos)); 03163 $header_array = explode($lb,$header_data); 03164 $data = ltrim(substr($data,$pos)); 03165 $this->debug('found proper separation of headers and document'); 03166 $this->debug('cleaned data, stringlen: '.strlen($data)); 03167 // clean headers 03168 foreach ($header_array as $header_line) { 03169 $arr = explode(':',$header_line,2); 03170 if(count($arr) > 1){ 03171 $header_name = strtolower(trim($arr[0])); 03172 $this->incoming_headers[$header_name] = trim($arr[1]); 03173 if ($header_name == 'set-cookie') { 03174 // TODO: allow multiple cookies from parseCookie 03175 $cookie = $this->parseCookie(trim($arr[1])); 03176 if ($cookie) { 03177 $this->incoming_cookies[] = $cookie; 03178 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); 03179 } else { 03180 $this->debug('did not find cookie in ' . trim($arr[1])); 03181 } 03182 } 03183 } else if (isset($header_name)) { 03184 // append continuation line to previous header 03185 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; 03186 } 03187 } 03188 } 03189 03190 $this->response_status_line = $header_array[0]; 03191 $arr = explode(' ', $this->response_status_line, 3); 03192 $http_version = $arr[0]; 03193 $http_status = intval($arr[1]); 03194 $http_reason = count($arr) > 2 ? $arr[2] : ''; 03195 03196 // see if we need to resend the request with http digest authentication 03197 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { 03198 $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); 03199 $this->setURL($this->incoming_headers['location']); 03200 $this->tryagain = true; 03201 return false; 03202 } 03203 03204 // see if we need to resend the request with http digest authentication 03205 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { 03206 $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); 03207 if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { 03208 $this->debug('Server wants digest authentication'); 03209 // remove "Digest " from our elements 03210 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); 03211 03212 // parse elements into array 03213 $digestElements = explode(',', $digestString); 03214 foreach ($digestElements as $val) { 03215 $tempElement = explode('=', trim($val), 2); 03216 $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); 03217 } 03218 03219 // should have (at least) qop, realm, nonce 03220 if (isset($digestRequest['nonce'])) { 03221 $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); 03222 $this->tryagain = true; 03223 return false; 03224 } 03225 } 03226 $this->debug('HTTP authentication failed'); 03227 $this->setError('HTTP authentication failed'); 03228 return false; 03229 } 03230 03231 if ( 03232 ($http_status >= 300 && $http_status <= 307) || 03233 ($http_status >= 400 && $http_status <= 417) || 03234 ($http_status >= 501 && $http_status <= 505) 03235 ) { 03236 $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); 03237 return false; 03238 } 03239 03240 // decode content-encoding 03241 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ 03242 if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ 03243 // if decoding works, use it. else assume data wasn't gzencoded 03244 if(function_exists('gzinflate')){ 03245 //$timer->setMarker('starting decoding of gzip/deflated content'); 03246 // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) 03247 // this means there are no Zlib headers, although there should be 03248 $this->debug('The gzinflate function exists'); 03249 $datalen = strlen($data); 03250 if ($this->incoming_headers['content-encoding'] == 'deflate') { 03251 if ($degzdata = @gzinflate($data)) { 03252 $data = $degzdata; 03253 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); 03254 if (strlen($data) < $datalen) { 03255 // test for the case that the payload has been compressed twice 03256 $this->debug('The inflated payload is smaller than the gzipped one; try again'); 03257 if ($degzdata = @gzinflate($data)) { 03258 $data = $degzdata; 03259 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); 03260 } 03261 } 03262 } else { 03263 $this->debug('Error using gzinflate to inflate the payload'); 03264 $this->setError('Error using gzinflate to inflate the payload'); 03265 } 03266 } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { 03267 if ($degzdata = @gzinflate(substr($data, 10))) { // do our best 03268 $data = $degzdata; 03269 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); 03270 if (strlen($data) < $datalen) { 03271 // test for the case that the payload has been compressed twice 03272 $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); 03273 if ($degzdata = @gzinflate(substr($data, 10))) { 03274 $data = $degzdata; 03275 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); 03276 } 03277 } 03278 } else { 03279 $this->debug('Error using gzinflate to un-gzip the payload'); 03280 $this->setError('Error using gzinflate to un-gzip the payload'); 03281 } 03282 } 03283 //$timer->setMarker('finished decoding of gzip/deflated content'); 03284 //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>"; 03285 // set decoded payload 03286 $this->incoming_payload = $header_data.$lb.$lb.$data; 03287 } else { 03288 $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 03289 $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); 03290 } 03291 } else { 03292 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 03293 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); 03294 } 03295 } else { 03296 $this->debug('No Content-Encoding header'); 03297 } 03298 03299 if(strlen($data) == 0){ 03300 $this->debug('no data after headers!'); 03301 $this->setError('no data present after HTTP headers'); 03302 return false; 03303 } 03304 03305 return $data; 03306 } 03307 03315 function setContentType($type, $charset = false) { 03316 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); 03317 } 03318 03325 function usePersistentConnection(){ 03326 if (isset($this->outgoing_headers['Accept-Encoding'])) { 03327 return false; 03328 } 03329 $this->protocol_version = '1.1'; 03330 $this->persistentConnection = true; 03331 $this->setHeader('Connection', 'Keep-Alive'); 03332 return true; 03333 } 03334 03342 /* 03343 * TODO: allow a Set-Cookie string to be parsed into multiple cookies 03344 */ 03345 function parseCookie($cookie_str) { 03346 $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; 03347 $data = split(';', $cookie_str); 03348 $value_str = $data[0]; 03349 03350 $cookie_param = 'domain='; 03351 $start = strpos($cookie_str, $cookie_param); 03352 if ($start > 0) { 03353 $domain = substr($cookie_str, $start + strlen($cookie_param)); 03354 $domain = substr($domain, 0, strpos($domain, ';')); 03355 } else { 03356 $domain = ''; 03357 } 03358 03359 $cookie_param = 'expires='; 03360 $start = strpos($cookie_str, $cookie_param); 03361 if ($start > 0) { 03362 $expires = substr($cookie_str, $start + strlen($cookie_param)); 03363 $expires = substr($expires, 0, strpos($expires, ';')); 03364 } else { 03365 $expires = ''; 03366 } 03367 03368 $cookie_param = 'path='; 03369 $start = strpos($cookie_str, $cookie_param); 03370 if ( $start > 0 ) { 03371 $path = substr($cookie_str, $start + strlen($cookie_param)); 03372 $path = substr($path, 0, strpos($path, ';')); 03373 } else { 03374 $path = '/'; 03375 } 03376 03377 $cookie_param = ';secure;'; 03378 if (strpos($cookie_str, $cookie_param) !== FALSE) { 03379 $secure = true; 03380 } else { 03381 $secure = false; 03382 } 03383 03384 $sep_pos = strpos($value_str, '='); 03385 03386 if ($sep_pos) { 03387 $name = substr($value_str, 0, $sep_pos); 03388 $value = substr($value_str, $sep_pos + 1); 03389 $cookie= array( 'name' => $name, 03390 'value' => $value, 03391 'domain' => $domain, 03392 'path' => $path, 03393 'expires' => $expires, 03394 'secure' => $secure 03395 ); 03396 return $cookie; 03397 } 03398 return false; 03399 } 03400 03409 function getCookiesForRequest($cookies, $secure=false) { 03410 $cookie_str = ''; 03411 if ((! is_null($cookies)) && (is_array($cookies))) { 03412 foreach ($cookies as $cookie) { 03413 if (! is_array($cookie)) { 03414 continue; 03415 } 03416 $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); 03417 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 03418 if (strtotime($cookie['expires']) <= time()) { 03419 $this->debug('cookie has expired'); 03420 continue; 03421 } 03422 } 03423 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { 03424 $domain = preg_quote($cookie['domain']); 03425 if (! preg_match("'.*$domain$'i", $this->host)) { 03426 $this->debug('cookie has different domain'); 03427 continue; 03428 } 03429 } 03430 if ((isset($cookie['path'])) && (! empty($cookie['path']))) { 03431 $path = preg_quote($cookie['path']); 03432 if (! preg_match("'^$path.*'i", $this->path)) { 03433 $this->debug('cookie is for a different path'); 03434 continue; 03435 } 03436 } 03437 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { 03438 $this->debug('cookie is secure, transport is not'); 03439 continue; 03440 } 03441 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; 03442 $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); 03443 } 03444 } 03445 return $cookie_str; 03446 } 03447 } 03448 03449 ?><?php 03450 03451 03452 03463 class nusoap_server extends nusoap_base { 03469 var $headers = array(); 03475 var $request = ''; 03481 var $requestHeaders = ''; 03487 var $requestHeader = NULL; 03493 var $document = ''; 03499 var $requestSOAP = ''; 03505 var $methodURI = ''; 03511 var $methodname = ''; 03517 var $methodparams = array(); 03523 var $SOAPAction = ''; 03529 var $xml_encoding = ''; 03535 var $decode_utf8 = true; 03536 03542 var $outgoing_headers = array(); 03548 var $response = ''; 03554 var $responseHeaders = ''; 03560 var $responseSOAP = ''; 03566 var $methodreturn = false; 03572 var $methodreturnisliteralxml = false; 03578 var $fault = false; 03584 var $result = 'successful'; 03585 03592 var $operations = array(); 03598 var $wsdl = false; 03604 var $externalWSDLURL = false; 03610 var $debug_flag = false; 03611 03612 03620 function nusoap_server($wsdl=false){ 03621 parent::nusoap_base(); 03622 // turn on debugging? 03623 global $debug; 03624 global $HTTP_SERVER_VARS; 03625 03626 if (isset($_SERVER)) { 03627 $this->debug("_SERVER is defined:"); 03628 $this->appendDebug($this->varDump($_SERVER)); 03629 } elseif (isset($HTTP_SERVER_VARS)) { 03630 $this->debug("HTTP_SERVER_VARS is defined:"); 03631 $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); 03632 } else { 03633 $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); 03634 } 03635 03636 if (isset($debug)) { 03637 $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); 03638 $this->debug_flag = $debug; 03639 } elseif (isset($_SERVER['QUERY_STRING'])) { 03640 $qs = explode('&', $_SERVER['QUERY_STRING']); 03641 foreach ($qs as $v) { 03642 if (substr($v, 0, 6) == 'debug=') { 03643 $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); 03644 $this->debug_flag = substr($v, 6); 03645 } 03646 } 03647 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 03648 $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); 03649 foreach ($qs as $v) { 03650 if (substr($v, 0, 6) == 'debug=') { 03651 $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); 03652 $this->debug_flag = substr($v, 6); 03653 } 03654 } 03655 } 03656 03657 // wsdl 03658 if($wsdl){ 03659 $this->debug("In nusoap_server, WSDL is specified"); 03660 if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { 03661 $this->wsdl = $wsdl; 03662 $this->externalWSDLURL = $this->wsdl->wsdl; 03663 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); 03664 } else { 03665 $this->debug('Create wsdl from ' . $wsdl); 03666 $this->wsdl = new wsdl($wsdl); 03667 $this->externalWSDLURL = $wsdl; 03668 } 03669 $this->appendDebug($this->wsdl->getDebug()); 03670 $this->wsdl->clearDebug(); 03671 if($err = $this->wsdl->getError()){ 03672 die('WSDL ERROR: '.$err); 03673 } 03674 } 03675 } 03676 03683 function service($data){ 03684 global $HTTP_SERVER_VARS; 03685 03686 if (isset($_SERVER['REQUEST_METHOD'])) { 03687 $rm = $_SERVER['REQUEST_METHOD']; 03688 } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { 03689 $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; 03690 } else { 03691 $rm = ''; 03692 } 03693 03694 if (isset($_SERVER['QUERY_STRING'])) { 03695 $qs = $_SERVER['QUERY_STRING']; 03696 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { 03697 $qs = $HTTP_SERVER_VARS['QUERY_STRING']; 03698 } else { 03699 $qs = ''; 03700 } 03701 $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); 03702 03703 if ($rm == 'POST') { 03704 $this->debug("In service, invoke the request"); 03705 $this->parse_request($data); 03706 if (! $this->fault) { 03707 $this->invoke_method(); 03708 } 03709 if (! $this->fault) { 03710 $this->serialize_return(); 03711 } 03712 $this->send_response(); 03713 } elseif (ereg('wsdl', $qs) ){ 03714 $this->debug("In service, this is a request for WSDL"); 03715 if ($this->externalWSDLURL){ 03716 if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL 03717 $this->debug("In service, re-direct for WSDL"); 03718 header('Location: '.$this->externalWSDLURL); 03719 } else { // assume file 03720 $this->debug("In service, use file passthru for WSDL"); 03721 header("Content-Type: text/xml\r\n"); 03722 $pos = strpos($this->externalWSDLURL, "file://"); 03723 if ($pos === false) { 03724 $filename = $this->externalWSDLURL; 03725 } else { 03726 $filename = substr($this->externalWSDLURL, $pos + 7); 03727 } 03728 $fp = fopen($this->externalWSDLURL, 'r'); 03729 fpassthru($fp); 03730 } 03731 } elseif ($this->wsdl) { 03732 $this->debug("In service, serialize WSDL"); 03733 header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); 03734 print $this->wsdl->serialize($this->debug_flag); 03735 if ($this->debug_flag) { 03736 $this->debug('wsdl:'); 03737 $this->appendDebug($this->varDump($this->wsdl)); 03738 print $this->getDebugAsXMLComment(); 03739 } 03740 } else { 03741 $this->debug("In service, there is no WSDL"); 03742 header("Content-Type: text/html; charset=ISO-8859-1\r\n"); 03743 print "This service does not provide WSDL"; 03744 } 03745 } elseif ($this->wsdl) { 03746 $this->debug("In service, return Web description"); 03747 print $this->wsdl->webDescription(); 03748 } else { 03749 $this->debug("In service, no Web description"); 03750 header("Content-Type: text/html; charset=ISO-8859-1\r\n"); 03751 print "This service does not provide a Web description"; 03752 } 03753 } 03754 03767 function parse_http_headers() { 03768 global $HTTP_SERVER_VARS; 03769 03770 $this->request = ''; 03771 $this->SOAPAction = ''; 03772 if(function_exists('getallheaders')){ 03773 $this->debug("In parse_http_headers, use getallheaders"); 03774 $headers = getallheaders(); 03775 foreach($headers as $k=>$v){ 03776 $k = strtolower($k); 03777 $this->headers[$k] = $v; 03778 $this->request .= "$k: $v\r\n"; 03779 $this->debug("$k: $v"); 03780 } 03781 // get SOAPAction header 03782 if(isset($this->headers['soapaction'])){ 03783 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); 03784 } 03785 // get the character encoding of the incoming request 03786 if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ 03787 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); 03788 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 03789 $this->xml_encoding = strtoupper($enc); 03790 } else { 03791 $this->xml_encoding = 'US-ASCII'; 03792 } 03793 } else { 03794 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 03795 $this->xml_encoding = 'ISO-8859-1'; 03796 } 03797 } elseif(isset($_SERVER) && is_array($_SERVER)){ 03798 $this->debug("In parse_http_headers, use _SERVER"); 03799 foreach ($_SERVER as $k => $v) { 03800 if (substr($k, 0, 5) == 'HTTP_') { 03801 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); 03802 } else { 03803 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); 03804 } 03805 if ($k == 'soapaction') { 03806 // get SOAPAction header 03807 $k = 'SOAPAction'; 03808 $v = str_replace('"', '', $v); 03809 $v = str_replace('\\', '', $v); 03810 $this->SOAPAction = $v; 03811 } else if ($k == 'content-type') { 03812 // get the character encoding of the incoming request 03813 if (strpos($v, '=')) { 03814 $enc = substr(strstr($v, '='), 1); 03815 $enc = str_replace('"', '', $enc); 03816 $enc = str_replace('\\', '', $enc); 03817 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 03818 $this->xml_encoding = strtoupper($enc); 03819 } else { 03820 $this->xml_encoding = 'US-ASCII'; 03821 } 03822 } else { 03823 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 03824 $this->xml_encoding = 'ISO-8859-1'; 03825 } 03826 } 03827 $this->headers[$k] = $v; 03828 $this->request .= "$k: $v\r\n"; 03829 $this->debug("$k: $v"); 03830 } 03831 } elseif (is_array($HTTP_SERVER_VARS)) { 03832 $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); 03833 foreach ($HTTP_SERVER_VARS as $k => $v) { 03834 if (substr($k, 0, 5) == 'HTTP_') { 03835 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); 03836 } else { 03837 $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); 03838 } 03839 if ($k == 'soapaction') { 03840 // get SOAPAction header 03841 $k = 'SOAPAction'; 03842 $v = str_replace('"', '', $v); 03843 $v = str_replace('\\', '', $v); 03844 $this->SOAPAction = $v; 03845 } else if ($k == 'content-type') { 03846 // get the character encoding of the incoming request 03847 if (strpos($v, '=')) { 03848 $enc = substr(strstr($v, '='), 1); 03849 $enc = str_replace('"', '', $enc); 03850 $enc = str_replace('\\', '', $enc); 03851 if (eregi('^(ISO-8859-1|US-ASCII|UTF-8)$', $enc)) { 03852 $this->xml_encoding = strtoupper($enc); 03853 } else { 03854 $this->xml_encoding = 'US-ASCII'; 03855 } 03856 } else { 03857 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 03858 $this->xml_encoding = 'ISO-8859-1'; 03859 } 03860 } 03861 $this->headers[$k] = $v; 03862 $this->request .= "$k: $v\r\n"; 03863 $this->debug("$k: $v"); 03864 } 03865 } else { 03866 $this->debug("In parse_http_headers, HTTP headers not accessible"); 03867 $this->setError("HTTP headers not accessible"); 03868 } 03869 } 03870 03893 function parse_request($data='') { 03894 $this->debug('entering parse_request()'); 03895 $this->parse_http_headers(); 03896 $this->debug('got character encoding: '.$this->xml_encoding); 03897 // uncompress if necessary 03898 if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { 03899 $this->debug('got content encoding: ' . $this->headers['content-encoding']); 03900 if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { 03901 // if decoding works, use it. else assume data wasn't gzencoded 03902 if (function_exists('gzuncompress')) { 03903 if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { 03904 $data = $degzdata; 03905 } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { 03906 $data = $degzdata; 03907 } else { 03908 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); 03909 return; 03910 } 03911 } else { 03912 $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); 03913 return; 03914 } 03915 } 03916 } 03917 $this->request .= "\r\n".$data; 03918 $data = $this->parseRequest($this->headers, $data); 03919 $this->requestSOAP = $data; 03920 $this->debug('leaving parse_request'); 03921 } 03922 03940 function invoke_method() { 03941 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); 03942 03943 if ($this->wsdl) { 03944 if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { 03945 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); 03946 $this->appendDebug('opData=' . $this->varDump($this->opData)); 03947 } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { 03948 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element 03949 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); 03950 $this->appendDebug('opData=' . $this->varDump($this->opData)); 03951 $this->methodname = $this->opData['name']; 03952 } else { 03953 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); 03954 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); 03955 return; 03956 } 03957 } else { 03958 $this->debug('in invoke_method, no WSDL to validate method'); 03959 } 03960 03961 // if a . is present in $this->methodname, we see if there is a class in scope, 03962 // which could be referred to. We will also distinguish between two deliminators, 03963 // to allow methods to be called a the class or an instance 03964 $class = ''; 03965 $method = ''; 03966 if (strpos($this->methodname, '..') > 0) { 03967 $delim = '..'; 03968 } else if (strpos($this->methodname, '.') > 0) { 03969 $delim = '.'; 03970 } else { 03971 $delim = ''; 03972 } 03973 03974 if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1 && 03975 class_exists(substr($this->methodname, 0, strpos($this->methodname, $delim)))) { 03976 // get the class and method name 03977 $class = substr($this->methodname, 0, strpos($this->methodname, $delim)); 03978 $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); 03979 $this->debug("in invoke_method, class=$class method=$method delim=$delim"); 03980 } 03981 03982 // does method exist? 03983 if ($class == '') { 03984 if (!function_exists($this->methodname)) { 03985 $this->debug("in invoke_method, function '$this->methodname' not found!"); 03986 $this->result = 'fault: method not found'; 03987 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 03988 return; 03989 } 03990 } else { 03991 $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; 03992 if (!in_array($method_to_compare, get_class_methods($class))) { 03993 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); 03994 $this->result = 'fault: method not found'; 03995 $this->fault('SOAP-ENV:Client',"method '$this->methodname' not defined in service"); 03996 return; 03997 } 03998 } 03999 04000 // evaluate message, getting back parameters 04001 // verify that request parameters match the method's signature 04002 if(! $this->verify_method($this->methodname,$this->methodparams)){ 04003 // debug 04004 $this->debug('ERROR: request not verified against method signature'); 04005 $this->result = 'fault: request failed validation against method signature'; 04006 // return fault 04007 $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); 04008 return; 04009 } 04010 04011 // if there are parameters to pass 04012 $this->debug('in invoke_method, params:'); 04013 $this->appendDebug($this->varDump($this->methodparams)); 04014 $this->debug("in invoke_method, calling '$this->methodname'"); 04015 if (!function_exists('call_user_func_array')) { 04016 if ($class == '') { 04017 $this->debug('in invoke_method, calling function using eval()'); 04018 $funcCall = "\$this->methodreturn = $this->methodname("; 04019 } else { 04020 if ($delim == '..') { 04021 $this->debug('in invoke_method, calling class method using eval()'); 04022 $funcCall = "\$this->methodreturn = ".$class."::".$method."("; 04023 } else { 04024 $this->debug('in invoke_method, calling instance method using eval()'); 04025 // generate unique instance name 04026 $instname = "\$inst_".time(); 04027 $funcCall = $instname." = new ".$class."(); "; 04028 $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; 04029 } 04030 } 04031 if ($this->methodparams) { 04032 foreach ($this->methodparams as $param) { 04033 if (is_array($param) || is_object($param)) { 04034 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); 04035 return; 04036 } 04037 $funcCall .= "\"$param\","; 04038 } 04039 $funcCall = substr($funcCall, 0, -1); 04040 } 04041 $funcCall .= ');'; 04042 $this->debug('in invoke_method, function call: '.$funcCall); 04043 @eval($funcCall); 04044 } else { 04045 if ($class == '') { 04046 $this->debug('in invoke_method, calling function using call_user_func_array()'); 04047 $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() 04048 } elseif ($delim == '..') { 04049 $this->debug('in invoke_method, calling class method using call_user_func_array()'); 04050 $call_arg = array ($class, $method); 04051 } else { 04052 $this->debug('in invoke_method, calling instance method using call_user_func_array()'); 04053 $instance = new $class (); 04054 $call_arg = array(&$instance, $method); 04055 } 04056 if (is_array($this->methodparams)) { 04057 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); 04058 } else { 04059 $this->methodreturn = call_user_func_array($call_arg, array()); 04060 } 04061 } 04062 $this->debug('in invoke_method, methodreturn:'); 04063 $this->appendDebug($this->varDump($this->methodreturn)); 04064 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); 04065 } 04066 04078 function serialize_return() { 04079 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); 04080 // if fault 04081 if (isset($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { 04082 $this->debug('got a fault object from method'); 04083 $this->fault = $this->methodreturn; 04084 return; 04085 } elseif ($this->methodreturnisliteralxml) { 04086 $return_val = $this->methodreturn; 04087 // returned value(s) 04088 } else { 04089 $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); 04090 $this->debug('serializing return value'); 04091 if($this->wsdl){ 04092 if (sizeof($this->opData['output']['parts']) > 1) { 04093 $this->debug('more than one output part, so use the method return unchanged'); 04094 $opParams = $this->methodreturn; 04095 } elseif (sizeof($this->opData['output']['parts']) == 1) { 04096 $this->debug('exactly one output part, so wrap the method return in a simple array'); 04097 // TODO: verify that it is not already wrapped! 04098 //foreach ($this->opData['output']['parts'] as $name => $type) { 04099 // $this->debug('wrap in element named ' . $name); 04100 //} 04101 $opParams = array($this->methodreturn); 04102 } 04103 $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); 04104 $this->appendDebug($this->wsdl->getDebug()); 04105 $this->wsdl->clearDebug(); 04106 if($errstr = $this->wsdl->getError()){ 04107 $this->debug('got wsdl error: '.$errstr); 04108 $this->fault('SOAP-ENV:Server', 'unable to serialize result'); 04109 return; 04110 } 04111 } else { 04112 if (isset($this->methodreturn)) { 04113 $return_val = $this->serialize_val($this->methodreturn, 'return'); 04114 } else { 04115 $return_val = ''; 04116 $this->debug('in absence of WSDL, assume void return for backward compatibility'); 04117 } 04118 } 04119 } 04120 $this->debug('return value:'); 04121 $this->appendDebug($this->varDump($return_val)); 04122 04123 $this->debug('serializing response'); 04124 if ($this->wsdl) { 04125 $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); 04126 if ($this->opData['style'] == 'rpc') { 04127 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); 04128 if ($this->opData['output']['use'] == 'literal') { 04129 // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace 04130 if ($this->methodURI) { 04131 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 04132 } else { 04133 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>'; 04134 } 04135 } else { 04136 if ($this->methodURI) { 04137 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 04138 } else { 04139 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>'; 04140 } 04141 } 04142 } else { 04143 $this->debug('style is not rpc for serialization: assume document'); 04144 $payload = $return_val; 04145 } 04146 } else { 04147 $this->debug('do not have WSDL for serialization: assume rpc/encoded'); 04148 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>"; 04149 } 04150 $this->result = 'successful'; 04151 if($this->wsdl){ 04152 //if($this->debug_flag){ 04153 $this->appendDebug($this->wsdl->getDebug()); 04154 // } 04155 if (isset($opData['output']['encodingStyle'])) { 04156 $encodingStyle = $opData['output']['encodingStyle']; 04157 } else { 04158 $encodingStyle = ''; 04159 } 04160 // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. 04161 $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); 04162 } else { 04163 $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); 04164 } 04165 $this->debug("Leaving serialize_return"); 04166 } 04167 04178 function send_response() { 04179 $this->debug('Enter send_response'); 04180 if ($this->fault) { 04181 $payload = $this->fault->serialize(); 04182 $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; 04183 $this->outgoing_headers[] = "Status: 500 Internal Server Error"; 04184 } else { 04185 $payload = $this->responseSOAP; 04186 // Some combinations of PHP+Web server allow the Status 04187 // to come through as a header. Since OK is the default 04188 // just do nothing. 04189 // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; 04190 // $this->outgoing_headers[] = "Status: 200 OK"; 04191 } 04192 // add debug data if in debug mode 04193 if(isset($this->debug_flag) && $this->debug_flag){ 04194 $payload .= $this->getDebugAsXMLComment(); 04195 } 04196 $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; 04197 ereg('\$Revisio' . 'n: ([^ ]+)', $this->revision, $rev); 04198 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; 04199 // Let the Web server decide about this 04200 //$this->outgoing_headers[] = "Connection: Close\r\n"; 04201 $payload = $this->getHTTPBody($payload); 04202 $type = $this->getHTTPContentType(); 04203 $charset = $this->getHTTPContentTypeCharset(); 04204 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); 04205 //begin code to compress payload - by John 04206 // NOTE: there is no way to know whether the Web server will also compress 04207 // this data. 04208 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { 04209 if (strstr($this->headers['accept-encoding'], 'gzip')) { 04210 if (function_exists('gzencode')) { 04211 if (isset($this->debug_flag) && $this->debug_flag) { 04212 $payload .= "<!-- Content being gzipped -->"; 04213 } 04214 $this->outgoing_headers[] = "Content-Encoding: gzip"; 04215 $payload = gzencode($payload); 04216 } else { 04217 if (isset($this->debug_flag) && $this->debug_flag) { 04218 $payload .= "<!-- Content will not be gzipped: no gzencode -->"; 04219 } 04220 } 04221 } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { 04222 // Note: MSIE requires gzdeflate output (no Zlib header and checksum), 04223 // instead of gzcompress output, 04224 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) 04225 if (function_exists('gzdeflate')) { 04226 if (isset($this->debug_flag) && $this->debug_flag) { 04227 $payload .= "<!-- Content being deflated -->"; 04228 } 04229 $this->outgoing_headers[] = "Content-Encoding: deflate"; 04230 $payload = gzdeflate($payload); 04231 } else { 04232 if (isset($this->debug_flag) && $this->debug_flag) { 04233 $payload .= "<!-- Content will not be deflated: no gzcompress -->"; 04234 } 04235 } 04236 } 04237 } 04238 //end code 04239 $this->outgoing_headers[] = "Content-Length: ".strlen($payload); 04240 reset($this->outgoing_headers); 04241 foreach($this->outgoing_headers as $hdr){ 04242 header($hdr, false); 04243 } 04244 print $payload; 04245 $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; 04246 } 04247 04257 function verify_method($operation,$request){ 04258 if(isset($this->wsdl) && is_object($this->wsdl)){ 04259 if($this->wsdl->getOperationData($operation)){ 04260 return true; 04261 } 04262 } elseif(isset($this->operations[$operation])){ 04263 return true; 04264 } 04265 return false; 04266 } 04267 04276 function parseRequest($headers, $data) { 04277 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); 04278 $this->appendDebug($this->varDump($headers)); 04279 if (!isset($headers['content-type'])) { 04280 $this->setError('Request not of type text/xml (no content-type header)'); 04281 return false; 04282 } 04283 if (!strstr($headers['content-type'], 'text/xml')) { 04284 $this->setError('Request not of type text/xml'); 04285 return false; 04286 } 04287 if (strpos($headers['content-type'], '=')) { 04288 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 04289 $this->debug('Got response encoding: ' . $enc); 04290 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 04291 $this->xml_encoding = strtoupper($enc); 04292 } else { 04293 $this->xml_encoding = 'US-ASCII'; 04294 } 04295 } else { 04296 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 04297 $this->xml_encoding = 'ISO-8859-1'; 04298 } 04299 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 04300 // parse response, get soap parser obj 04301 $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); 04302 // parser debug 04303 $this->debug("parser debug: \n".$parser->getDebug()); 04304 // if fault occurred during message parsing 04305 if($err = $parser->getError()){ 04306 $this->result = 'fault: error in msg parsing: '.$err; 04307 $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); 04308 // else successfully parsed request into soapval object 04309 } else { 04310 // get/set methodname 04311 $this->methodURI = $parser->root_struct_namespace; 04312 $this->methodname = $parser->root_struct_name; 04313 $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); 04314 $this->debug('calling parser->get_soapbody()'); 04315 $this->methodparams = $parser->get_soapbody(); 04316 // get SOAP headers 04317 $this->requestHeaders = $parser->getHeaders(); 04318 // get SOAP Header 04319 $this->requestHeader = $parser->get_soapheader(); 04320 // add document for doclit support 04321 $this->document = $parser->document; 04322 } 04323 } 04324 04332 function getHTTPBody($soapmsg) { 04333 return $soapmsg; 04334 } 04335 04344 function getHTTPContentType() { 04345 return 'text/xml'; 04346 } 04347 04357 function getHTTPContentTypeCharset() { 04358 return $this->soap_defencoding; 04359 } 04360 04370 function add_to_map($methodname,$in,$out){ 04371 $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); 04372 } 04373 04388 function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ 04389 global $HTTP_SERVER_VARS; 04390 04391 if($this->externalWSDLURL){ 04392 die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); 04393 } 04394 if (! $name) { 04395 die('You must specify a name when you register an operation'); 04396 } 04397 if (!is_array($in)) { 04398 die('You must provide an array for operation inputs'); 04399 } 04400 if (!is_array($out)) { 04401 die('You must provide an array for operation outputs'); 04402 } 04403 if(false == $namespace) { 04404 } 04405 if(false == $soapaction) { 04406 if (isset($_SERVER)) { 04407 $SERVER_NAME = $_SERVER['SERVER_NAME']; 04408 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 04409 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 04410 } elseif (isset($HTTP_SERVER_VARS)) { 04411 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 04412 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 04413 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 04414 } else { 04415 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 04416 } 04417 if ($HTTPS == '1' || $HTTPS == 'on') { 04418 $SCHEME = 'https'; 04419 } else { 04420 $SCHEME = 'http'; 04421 } 04422 $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; 04423 } 04424 if(false == $style) { 04425 $style = "rpc"; 04426 } 04427 if(false == $use) { 04428 $use = "encoded"; 04429 } 04430 if ($use == 'encoded' && $encodingStyle == '') { 04431 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 04432 } 04433 04434 $this->operations[$name] = array( 04435 'name' => $name, 04436 'in' => $in, 04437 'out' => $out, 04438 'namespace' => $namespace, 04439 'soapaction' => $soapaction, 04440 'style' => $style); 04441 if($this->wsdl){ 04442 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); 04443 } 04444 return true; 04445 } 04446 04457 function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ 04458 if ($faultdetail == '' && $this->debug_flag) { 04459 $faultdetail = $this->getDebug(); 04460 } 04461 $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); 04462 $this->fault->soap_defencoding = $this->soap_defencoding; 04463 } 04464 04476 function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) 04477 { 04478 global $HTTP_SERVER_VARS; 04479 04480 if (isset($_SERVER)) { 04481 $SERVER_NAME = $_SERVER['SERVER_NAME']; 04482 $SERVER_PORT = $_SERVER['SERVER_PORT']; 04483 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; 04484 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); 04485 } elseif (isset($HTTP_SERVER_VARS)) { 04486 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; 04487 $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; 04488 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; 04489 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; 04490 } else { 04491 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 04492 } 04493 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) 04494 $colon = strpos($SERVER_NAME,":"); 04495 if ($colon) { 04496 $SERVER_NAME = substr($SERVER_NAME, 0, $colon); 04497 } 04498 if ($SERVER_PORT == 80) { 04499 $SERVER_PORT = ''; 04500 } else { 04501 $SERVER_PORT = ':' . $SERVER_PORT; 04502 } 04503 if(false == $namespace) { 04504 $namespace = "http://$SERVER_NAME/soap/$serviceName"; 04505 } 04506 04507 if(false == $endpoint) { 04508 if ($HTTPS == '1' || $HTTPS == 'on') { 04509 $SCHEME = 'https'; 04510 } else { 04511 $SCHEME = 'http'; 04512 } 04513 $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; 04514 } 04515 04516 if(false == $schemaTargetNamespace) { 04517 $schemaTargetNamespace = $namespace; 04518 } 04519 04520 $this->wsdl = new wsdl; 04521 $this->wsdl->serviceName = $serviceName; 04522 $this->wsdl->endpoint = $endpoint; 04523 $this->wsdl->namespaces['tns'] = $namespace; 04524 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; 04525 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; 04526 if ($schemaTargetNamespace != $namespace) { 04527 $this->wsdl->namespaces['types'] = $schemaTargetNamespace; 04528 } 04529 $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); 04530 if ($style == 'document') { 04531 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; 04532 } 04533 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; 04534 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); 04535 $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); 04536 $this->wsdl->bindings[$serviceName.'Binding'] = array( 04537 'name'=>$serviceName.'Binding', 04538 'style'=>$style, 04539 'transport'=>$transport, 04540 'portType'=>$serviceName.'PortType'); 04541 $this->wsdl->ports[$serviceName.'Port'] = array( 04542 'binding'=>$serviceName.'Binding', 04543 'location'=>$endpoint, 04544 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); 04545 } 04546 } 04547 04551 class soap_server extends nusoap_server { 04552 } 04553 04554 ?><?php 04555 04556 04557 04567 class wsdl extends nusoap_base { 04568 // URL or filename of the root of this WSDL 04569 var $wsdl; 04570 // define internal arrays of bindings, ports, operations, messages, etc. 04571 var $schemas = array(); 04572 var $currentSchema; 04573 var $message = array(); 04574 var $complexTypes = array(); 04575 var $messages = array(); 04576 var $currentMessage; 04577 var $currentOperation; 04578 var $portTypes = array(); 04579 var $currentPortType; 04580 var $bindings = array(); 04581 var $currentBinding; 04582 var $ports = array(); 04583 var $currentPort; 04584 var $opData = array(); 04585 var $status = ''; 04586 var $documentation = false; 04587 var $endpoint = ''; 04588 // array of wsdl docs to import 04589 var $import = array(); 04590 // parser vars 04591 var $parser; 04592 var $position = 0; 04593 var $depth = 0; 04594 var $depth_array = array(); 04595 // for getting wsdl 04596 var $proxyhost = ''; 04597 var $proxyport = ''; 04598 var $proxyusername = ''; 04599 var $proxypassword = ''; 04600 var $timeout = 0; 04601 var $response_timeout = 30; 04602 var $curl_options = array(); // User-specified cURL options 04603 var $use_curl = false; // whether to always try to use cURL 04604 // for HTTP authentication 04605 var $username = ''; // Username for HTTP authentication 04606 var $password = ''; // Password for HTTP authentication 04607 var $authtype = ''; // Type of HTTP authentication 04608 var $certRequest = array(); // Certificate for HTTP SSL authentication 04609 04624 function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ 04625 parent::nusoap_base(); 04626 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 04627 $this->proxyhost = $proxyhost; 04628 $this->proxyport = $proxyport; 04629 $this->proxyusername = $proxyusername; 04630 $this->proxypassword = $proxypassword; 04631 $this->timeout = $timeout; 04632 $this->response_timeout = $response_timeout; 04633 if (is_array($curl_options)) 04634 $this->curl_options = $curl_options; 04635 $this->use_curl = $use_curl; 04636 $this->fetchWSDL($wsdl); 04637 } 04638 04644 function fetchWSDL($wsdl) { 04645 $this->debug("parse and process WSDL path=$wsdl"); 04646 $this->wsdl = $wsdl; 04647 // parse wsdl file 04648 if ($this->wsdl != "") { 04649 $this->parseWSDL($this->wsdl); 04650 } 04651 // imports 04652 // TODO: handle imports more properly, grabbing them in-line and nesting them 04653 $imported_urls = array(); 04654 $imported = 1; 04655 while ($imported > 0) { 04656 $imported = 0; 04657 // Schema imports 04658 foreach ($this->schemas as $ns => $list) { 04659 foreach ($list as $xs) { 04660 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 04661 foreach ($xs->imports as $ns2 => $list2) { 04662 for ($ii = 0; $ii < count($list2); $ii++) { 04663 if (! $list2[$ii]['loaded']) { 04664 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; 04665 $url = $list2[$ii]['location']; 04666 if ($url != '') { 04667 $urlparts = parse_url($url); 04668 if (!isset($urlparts['host'])) { 04669 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . 04670 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 04671 } 04672 if (! in_array($url, $imported_urls)) { 04673 $this->parseWSDL($url); 04674 $imported++; 04675 $imported_urls[] = $url; 04676 } 04677 } else { 04678 $this->debug("Unexpected scenario: empty URL for unloaded import"); 04679 } 04680 } 04681 } 04682 } 04683 } 04684 } 04685 // WSDL imports 04686 $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! 04687 foreach ($this->import as $ns => $list) { 04688 for ($ii = 0; $ii < count($list); $ii++) { 04689 if (! $list[$ii]['loaded']) { 04690 $this->import[$ns][$ii]['loaded'] = true; 04691 $url = $list[$ii]['location']; 04692 if ($url != '') { 04693 $urlparts = parse_url($url); 04694 if (!isset($urlparts['host'])) { 04695 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . 04696 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; 04697 } 04698 if (! in_array($url, $imported_urls)) { 04699 $this->parseWSDL($url); 04700 $imported++; 04701 $imported_urls[] = $url; 04702 } 04703 } else { 04704 $this->debug("Unexpected scenario: empty URL for unloaded import"); 04705 } 04706 } 04707 } 04708 } 04709 } 04710 // add new data to operation data 04711 foreach($this->bindings as $binding => $bindingData) { 04712 if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { 04713 foreach($bindingData['operations'] as $operation => $data) { 04714 $this->debug('post-parse data gathering for ' . $operation); 04715 $this->bindings[$binding]['operations'][$operation]['input'] = 04716 isset($this->bindings[$binding]['operations'][$operation]['input']) ? 04717 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : 04718 $this->portTypes[ $bindingData['portType'] ][$operation]['input']; 04719 $this->bindings[$binding]['operations'][$operation]['output'] = 04720 isset($this->bindings[$binding]['operations'][$operation]['output']) ? 04721 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : 04722 $this->portTypes[ $bindingData['portType'] ][$operation]['output']; 04723 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ 04724 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; 04725 } 04726 if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ 04727 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; 04728 } 04729 // Set operation style if necessary, but do not override one already provided 04730 if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { 04731 $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; 04732 } 04733 $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; 04734 $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; 04735 $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; 04736 } 04737 } 04738 } 04739 } 04740 04747 function parseWSDL($wsdl = '') { 04748 $this->debug("parse WSDL at path=$wsdl"); 04749 04750 if ($wsdl == '') { 04751 $this->debug('no wsdl passed to parseWSDL()!!'); 04752 $this->setError('no wsdl passed to parseWSDL()!!'); 04753 return false; 04754 } 04755 04756 // parse $wsdl for url format 04757 $wsdl_props = parse_url($wsdl); 04758 04759 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { 04760 $this->debug('getting WSDL http(s) URL ' . $wsdl); 04761 // get wsdl 04762 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); 04763 $tr->request_method = 'GET'; 04764 $tr->useSOAPAction = false; 04765 if($this->proxyhost && $this->proxyport){ 04766 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 04767 } 04768 if ($this->authtype != '') { 04769 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 04770 } 04771 $tr->setEncoding('gzip, deflate'); 04772 $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); 04773 //$this->debug("WSDL request\n" . $tr->outgoing_payload); 04774 //$this->debug("WSDL response\n" . $tr->incoming_payload); 04775 $this->appendDebug($tr->getDebug()); 04776 // catch errors 04777 if($err = $tr->getError() ){ 04778 $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; 04779 $this->debug($errstr); 04780 $this->setError($errstr); 04781 unset($tr); 04782 return false; 04783 } 04784 unset($tr); 04785 $this->debug("got WSDL URL"); 04786 } else { 04787 // $wsdl is not http(s), so treat it as a file URL or plain file path 04788 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { 04789 $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; 04790 } else { 04791 $path = $wsdl; 04792 } 04793 $this->debug('getting WSDL file ' . $path); 04794 if ($fp = @fopen($path, 'r')) { 04795 $wsdl_string = ''; 04796 while ($data = fread($fp, 32768)) { 04797 $wsdl_string .= $data; 04798 } 04799 fclose($fp); 04800 } else { 04801 $errstr = "Bad path to WSDL file $path"; 04802 $this->debug($errstr); 04803 $this->setError($errstr); 04804 return false; 04805 } 04806 } 04807 $this->debug('Parse WSDL'); 04808 // end new code added 04809 // Create an XML parser. 04810 $this->parser = xml_parser_create(); 04811 // Set the options for parsing the XML data. 04812 // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 04813 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 04814 // Set the object for the parser. 04815 xml_set_object($this->parser, $this); 04816 // Set the element handlers for the parser. 04817 xml_set_element_handler($this->parser, 'start_element', 'end_element'); 04818 xml_set_character_data_handler($this->parser, 'character_data'); 04819 // Parse the XML file. 04820 if (!xml_parse($this->parser, $wsdl_string, true)) { 04821 // Display an error message. 04822 $errstr = sprintf( 04823 'XML error parsing WSDL from %s on line %d: %s', 04824 $wsdl, 04825 xml_get_current_line_number($this->parser), 04826 xml_error_string(xml_get_error_code($this->parser)) 04827 ); 04828 $this->debug($errstr); 04829 $this->debug("XML payload:\n" . $wsdl_string); 04830 $this->setError($errstr); 04831 return false; 04832 } 04833 // free the parser 04834 xml_parser_free($this->parser); 04835 $this->debug('Parsing WSDL done'); 04836 // catch wsdl parse errors 04837 if($this->getError()){ 04838 return false; 04839 } 04840 return true; 04841 } 04842 04851 function start_element($parser, $name, $attrs) 04852 { 04853 if ($this->status == 'schema') { 04854 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 04855 $this->appendDebug($this->currentSchema->getDebug()); 04856 $this->currentSchema->clearDebug(); 04857 } elseif (ereg('schema$', $name)) { 04858 $this->debug('Parsing WSDL schema'); 04859 // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); 04860 $this->status = 'schema'; 04861 $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); 04862 $this->currentSchema->schemaStartElement($parser, $name, $attrs); 04863 $this->appendDebug($this->currentSchema->getDebug()); 04864 $this->currentSchema->clearDebug(); 04865 } else { 04866 // position in the total number of elements, starting from 0 04867 $pos = $this->position++; 04868 $depth = $this->depth++; 04869 // set self as current value for this depth 04870 $this->depth_array[$depth] = $pos; 04871 $this->message[$pos] = array('cdata' => ''); 04872 // process attributes 04873 if (count($attrs) > 0) { 04874 // register namespace declarations 04875 foreach($attrs as $k => $v) { 04876 if (ereg("^xmlns", $k)) { 04877 if ($ns_prefix = substr(strrchr($k, ':'), 1)) { 04878 $this->namespaces[$ns_prefix] = $v; 04879 } else { 04880 $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; 04881 } 04882 if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { 04883 $this->XMLSchemaVersion = $v; 04884 $this->namespaces['xsi'] = $v . '-instance'; 04885 } 04886 } 04887 } 04888 // expand each attribute prefix to its namespace 04889 foreach($attrs as $k => $v) { 04890 $k = strpos($k, ':') ? $this->expandQname($k) : $k; 04891 if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { 04892 $v = strpos($v, ':') ? $this->expandQname($v) : $v; 04893 } 04894 $eAttrs[$k] = $v; 04895 } 04896 $attrs = $eAttrs; 04897 } else { 04898 $attrs = array(); 04899 } 04900 // get element prefix, namespace and name 04901 if (ereg(':', $name)) { 04902 // get ns prefix 04903 $prefix = substr($name, 0, strpos($name, ':')); 04904 // get ns 04905 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; 04906 // get unqualified name 04907 $name = substr(strstr($name, ':'), 1); 04908 } 04909 // process attributes, expanding any prefixes to namespaces 04910 // find status, register data 04911 switch ($this->status) { 04912 case 'message': 04913 if ($name == 'part') { 04914 if (isset($attrs['type'])) { 04915 $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); 04916 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; 04917 } 04918 if (isset($attrs['element'])) { 04919 $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); 04920 $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; 04921 } 04922 } 04923 break; 04924 case 'portType': 04925 switch ($name) { 04926 case 'operation': 04927 $this->currentPortOperation = $attrs['name']; 04928 $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); 04929 if (isset($attrs['parameterOrder'])) { 04930 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; 04931 } 04932 break; 04933 case 'documentation': 04934 $this->documentation = true; 04935 break; 04936 // merge input/output data 04937 default: 04938 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; 04939 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; 04940 break; 04941 } 04942 break; 04943 case 'binding': 04944 switch ($name) { 04945 case 'binding': 04946 // get ns prefix 04947 if (isset($attrs['style'])) { 04948 $this->bindings[$this->currentBinding]['prefix'] = $prefix; 04949 } 04950 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); 04951 break; 04952 case 'header': 04953 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; 04954 break; 04955 case 'operation': 04956 if (isset($attrs['soapAction'])) { 04957 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; 04958 } 04959 if (isset($attrs['style'])) { 04960 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; 04961 } 04962 if (isset($attrs['name'])) { 04963 $this->currentOperation = $attrs['name']; 04964 $this->debug("current binding operation: $this->currentOperation"); 04965 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; 04966 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; 04967 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; 04968 } 04969 break; 04970 case 'input': 04971 $this->opStatus = 'input'; 04972 break; 04973 case 'output': 04974 $this->opStatus = 'output'; 04975 break; 04976 case 'body': 04977 if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { 04978 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); 04979 } else { 04980 $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; 04981 } 04982 break; 04983 } 04984 break; 04985 case 'service': 04986 switch ($name) { 04987 case 'port': 04988 $this->currentPort = $attrs['name']; 04989 $this->debug('current port: ' . $this->currentPort); 04990 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); 04991 04992 break; 04993 case 'address': 04994 $this->ports[$this->currentPort]['location'] = $attrs['location']; 04995 $this->ports[$this->currentPort]['bindingType'] = $namespace; 04996 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; 04997 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; 04998 break; 04999 } 05000 break; 05001 } 05002 // set status 05003 switch ($name) { 05004 case 'import': 05005 if (isset($attrs['location'])) { 05006 $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); 05007 $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); 05008 } else { 05009 $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); 05010 if (! $this->getPrefixFromNamespace($attrs['namespace'])) { 05011 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; 05012 } 05013 $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); 05014 } 05015 break; 05016 //wait for schema 05017 //case 'types': 05018 // $this->status = 'schema'; 05019 // break; 05020 case 'message': 05021 $this->status = 'message'; 05022 $this->messages[$attrs['name']] = array(); 05023 $this->currentMessage = $attrs['name']; 05024 break; 05025 case 'portType': 05026 $this->status = 'portType'; 05027 $this->portTypes[$attrs['name']] = array(); 05028 $this->currentPortType = $attrs['name']; 05029 break; 05030 case "binding": 05031 if (isset($attrs['name'])) { 05032 // get binding name 05033 if (strpos($attrs['name'], ':')) { 05034 $this->currentBinding = $this->getLocalPart($attrs['name']); 05035 } else { 05036 $this->currentBinding = $attrs['name']; 05037 } 05038 $this->status = 'binding'; 05039 $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); 05040 $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); 05041 } 05042 break; 05043 case 'service': 05044 $this->serviceName = $attrs['name']; 05045 $this->status = 'service'; 05046 $this->debug('current service: ' . $this->serviceName); 05047 break; 05048 case 'definitions': 05049 foreach ($attrs as $name => $value) { 05050 $this->wsdl_info[$name] = $value; 05051 } 05052 break; 05053 } 05054 } 05055 } 05056 05064 function end_element($parser, $name){ 05065 // unset schema status 05066 if (/*ereg('types$', $name) ||*/ ereg('schema$', $name)) { 05067 $this->status = ""; 05068 $this->appendDebug($this->currentSchema->getDebug()); 05069 $this->currentSchema->clearDebug(); 05070 $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; 05071 $this->debug('Parsing WSDL schema done'); 05072 } 05073 if ($this->status == 'schema') { 05074 $this->currentSchema->schemaEndElement($parser, $name); 05075 } else { 05076 // bring depth down a notch 05077 $this->depth--; 05078 } 05079 // end documentation 05080 if ($this->documentation) { 05081 //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. 05082 //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; 05083 $this->documentation = false; 05084 } 05085 } 05086 05094 function character_data($parser, $data) 05095 { 05096 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; 05097 if (isset($this->message[$pos]['cdata'])) { 05098 $this->message[$pos]['cdata'] .= $data; 05099 } 05100 if ($this->documentation) { 05101 $this->documentation .= $data; 05102 } 05103 } 05104 05114 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 05115 $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 05116 $this->appendDebug($this->varDump($certRequest)); 05117 $this->username = $username; 05118 $this->password = $password; 05119 $this->authtype = $authtype; 05120 $this->certRequest = $certRequest; 05121 } 05122 05123 function getBindingData($binding) 05124 { 05125 if (is_array($this->bindings[$binding])) { 05126 return $this->bindings[$binding]; 05127 } 05128 } 05129 05138 function getOperations($portName = '', $bindingType = 'soap') { 05139 $ops = array(); 05140 if ($bindingType == 'soap') { 05141 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 05142 } elseif ($bindingType == 'soap12') { 05143 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 05144 } else { 05145 $this->debug("getOperations bindingType $bindingType may not be supported"); 05146 } 05147 $this->debug("getOperations for port '$portName' bindingType $bindingType"); 05148 // loop thru ports 05149 foreach($this->ports as $port => $portData) { 05150 $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); 05151 if ($portName == '' || $port == $portName) { 05152 // binding type of port matches parameter 05153 if ($portData['bindingType'] == $bindingType) { 05154 $this->debug("getOperations found port $port bindingType $bindingType"); 05155 //$this->debug("port data: " . $this->varDump($portData)); 05156 //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); 05157 // merge bindings 05158 if (isset($this->bindings[ $portData['binding'] ]['operations'])) { 05159 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); 05160 } 05161 } 05162 } 05163 } 05164 if (count($ops) == 0) { 05165 $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); 05166 } 05167 return $ops; 05168 } 05169 05178 function getOperationData($operation, $bindingType = 'soap') 05179 { 05180 if ($bindingType == 'soap') { 05181 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 05182 } elseif ($bindingType == 'soap12') { 05183 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 05184 } 05185 // loop thru ports 05186 foreach($this->ports as $port => $portData) { 05187 // binding type of port matches parameter 05188 if ($portData['bindingType'] == $bindingType) { 05189 // get binding 05190 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 05191 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { 05192 // note that we could/should also check the namespace here 05193 if ($operation == $bOperation) { 05194 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; 05195 return $opData; 05196 } 05197 } 05198 } 05199 } 05200 } 05201 05210 function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { 05211 if ($bindingType == 'soap') { 05212 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; 05213 } elseif ($bindingType == 'soap12') { 05214 $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; 05215 } 05216 // loop thru ports 05217 foreach($this->ports as $port => $portData) { 05218 // binding type of port matches parameter 05219 if ($portData['bindingType'] == $bindingType) { 05220 // loop through operations for the binding 05221 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { 05222 if ($opData['soapAction'] == $soapAction) { 05223 return $opData; 05224 } 05225 } 05226 } 05227 } 05228 } 05229 05248 function getTypeDef($type, $ns) { 05249 $this->debug("in getTypeDef: type=$type, ns=$ns"); 05250 if ((! $ns) && isset($this->namespaces['tns'])) { 05251 $ns = $this->namespaces['tns']; 05252 $this->debug("in getTypeDef: type namespace forced to $ns"); 05253 } 05254 if (!isset($this->schemas[$ns])) { 05255 foreach ($this->schemas as $ns0 => $schema0) { 05256 if (strcasecmp($ns, $ns0) == 0) { 05257 $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); 05258 $ns = $ns0; 05259 break; 05260 } 05261 } 05262 } 05263 if (isset($this->schemas[$ns])) { 05264 $this->debug("in getTypeDef: have schema for namespace $ns"); 05265 for ($i = 0; $i < count($this->schemas[$ns]); $i++) { 05266 $xs = &$this->schemas[$ns][$i]; 05267 $t = $xs->getTypeDef($type); 05268 $this->appendDebug($xs->getDebug()); 05269 $xs->clearDebug(); 05270 if ($t) { 05271 $this->debug("in getTypeDef: found type $type"); 05272 if (!isset($t['phpType'])) { 05273 // get info for type to tack onto the element 05274 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); 05275 $ns = substr($t['type'], 0, strrpos($t['type'], ':')); 05276 $etype = $this->getTypeDef($uqType, $ns); 05277 if ($etype) { 05278 $this->debug("found type for [element] $type:"); 05279 $this->debug($this->varDump($etype)); 05280 if (isset($etype['phpType'])) { 05281 $t['phpType'] = $etype['phpType']; 05282 } 05283 if (isset($etype['elements'])) { 05284 $t['elements'] = $etype['elements']; 05285 } 05286 if (isset($etype['attrs'])) { 05287 $t['attrs'] = $etype['attrs']; 05288 } 05289 } else { 05290 $this->debug("did not find type for [element] $type"); 05291 } 05292 } 05293 return $t; 05294 } 05295 } 05296 $this->debug("in getTypeDef: did not find type $type"); 05297 } else { 05298 $this->debug("in getTypeDef: do not have schema for namespace $ns"); 05299 } 05300 return false; 05301 } 05302 05308 function webDescription(){ 05309 global $HTTP_SERVER_VARS; 05310 05311 if (isset($_SERVER)) { 05312 $PHP_SELF = $_SERVER['PHP_SELF']; 05313 } elseif (isset($HTTP_SERVER_VARS)) { 05314 $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; 05315 } else { 05316 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); 05317 } 05318 05319 $b = ' 05320 <html><head><title>NuSOAP: '.$this->serviceName.'</title> 05321 <style type="text/css"> 05322 body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } 05323 p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } 05324 pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} 05325 ul { margin-top: 10px; margin-left: 20px; } 05326 li { list-style-type: none; margin-top: 10px; color: #000000; } 05327 .content{ 05328 margin-left: 0px; padding-bottom: 2em; } 05329 .nav { 05330 padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; 05331 margin-top: 10px; margin-left: 0px; color: #000000; 05332 background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } 05333 .title { 05334 font-family: arial; font-size: 26px; color: #ffffff; 05335 background-color: #999999; width: 100%; 05336 margin-left: 0px; margin-right: 0px; 05337 padding-top: 10px; padding-bottom: 10px;} 05338 .hidden { 05339 position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; 05340 font-family: arial; overflow: hidden; width: 600; 05341 padding: 20px; font-size: 10px; background-color: #999999; 05342 layer-background-color:#FFFFFF; } 05343 a,a:active { color: charcoal; font-weight: bold; } 05344 a:visited { color: #666666; font-weight: bold; } 05345 a:hover { color: cc3300; font-weight: bold; } 05346 </style> 05347 <script language="JavaScript" type="text/javascript"> 05348 <!-- 05349 // POP-UP CAPTIONS... 05350 function lib_bwcheck(){ //Browsercheck (needed) 05351 this.ver=navigator.appVersion 05352 this.agent=navigator.userAgent 05353 this.dom=document.getElementById?1:0 05354 this.opera5=this.agent.indexOf("Opera 5")>-1 05355 this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0; 05356 this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0; 05357 this.ie4=(document.all && !this.dom && !this.opera5)?1:0; 05358 this.ie=this.ie4||this.ie5||this.ie6 05359 this.mac=this.agent.indexOf("Mac")>-1 05360 this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; 05361 this.ns4=(document.layers && !this.dom)?1:0; 05362 this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) 05363 return this 05364 } 05365 var bw = new lib_bwcheck() 05366 //Makes crossbrowser object. 05367 function makeObj(obj){ 05368 this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; 05369 if(!this.evnt) return false 05370 this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; 05371 this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; 05372 this.writeIt=b_writeIt; 05373 return this 05374 } 05375 // A unit of measure that will be added when setting the position of a layer. 05376 //var px = bw.ns4||window.opera?"":"px"; 05377 function b_writeIt(text){ 05378 if (bw.ns4){this.wref.write(text);this.wref.close()} 05379 else this.wref.innerHTML = text 05380 } 05381 //Shows the messages 05382 var oDesc; 05383 function popup(divid){ 05384 if(oDesc = new makeObj(divid)){ 05385 oDesc.css.visibility = "visible" 05386 } 05387 } 05388 function popout(){ // Hides message 05389 if(oDesc) oDesc.css.visibility = "hidden" 05390 } 05391 //--> 05392 </script> 05393 </head> 05394 <body> 05395 <div class=content> 05396 <br><br> 05397 <div class=title>'.$this->serviceName.'</div> 05398 <div class=nav> 05399 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service. 05400 Click on an operation name to view it's details.</p> 05401 <ul>'; 05402 foreach($this->getOperations() as $op => $data){ 05403 $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>"; 05404 // create hidden div 05405 $b .= "<div id='$op' class='hidden'> 05406 <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; 05407 foreach($data as $donnie => $marie){ // loop through opdata 05408 if($donnie == 'input' || $donnie == 'output'){ // show input/output data 05409 $b .= "<font color='white'>".ucfirst($donnie).':</font><br>'; 05410 foreach($marie as $captain => $tenille){ // loop through data 05411 if($captain == 'parts'){ // loop thru parts 05412 $b .= " $captain:<br>"; 05413 //if(is_array($tenille)){ 05414 foreach($tenille as $joanie => $chachi){ 05415 $b .= " $joanie: $chachi<br>"; 05416 } 05417 //} 05418 } else { 05419 $b .= " $captain: $tenille<br>"; 05420 } 05421 } 05422 } else { 05423 $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; 05424 } 05425 } 05426 $b .= '</div>'; 05427 } 05428 $b .= ' 05429 <ul> 05430 </div> 05431 </div></body></html>'; 05432 return $b; 05433 } 05434 05442 function serialize($debug = 0) 05443 { 05444 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>'; 05445 $xml .= "\n<definitions"; 05446 foreach($this->namespaces as $k => $v) { 05447 $xml .= " xmlns:$k=\"$v\""; 05448 } 05449 // 10.9.02 - add poulter fix for wsdl and tns declarations 05450 if (isset($this->namespaces['wsdl'])) { 05451 $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; 05452 } 05453 if (isset($this->namespaces['tns'])) { 05454 $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; 05455 } 05456 $xml .= '>'; 05457 // imports 05458 if (sizeof($this->import) > 0) { 05459 foreach($this->import as $ns => $list) { 05460 foreach ($list as $ii) { 05461 if ($ii['location'] != '') { 05462 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />'; 05463 } else { 05464 $xml .= '<import namespace="' . $ns . '" />'; 05465 } 05466 } 05467 } 05468 } 05469 // types 05470 if (count($this->schemas)>=1) { 05471 $xml .= "\n<types>\n"; 05472 foreach ($this->schemas as $ns => $list) { 05473 foreach ($list as $xs) { 05474 $xml .= $xs->serializeSchema(); 05475 } 05476 } 05477 $xml .= '</types>'; 05478 } 05479 // messages 05480 if (count($this->messages) >= 1) { 05481 foreach($this->messages as $msgName => $msgParts) { 05482 $xml .= "\n<message name=\"" . $msgName . '">'; 05483 if(is_array($msgParts)){ 05484 foreach($msgParts as $partName => $partType) { 05485 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>'; 05486 if (strpos($partType, ':')) { 05487 $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); 05488 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { 05489 // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>'; 05490 $typePrefix = 'xsd'; 05491 } else { 05492 foreach($this->typemap as $ns => $types) { 05493 if (isset($types[$partType])) { 05494 $typePrefix = $this->getPrefixFromNamespace($ns); 05495 } 05496 } 05497 if (!isset($typePrefix)) { 05498 die("$partType has no namespace!"); 05499 } 05500 } 05501 $ns = $this->getNamespaceFromPrefix($typePrefix); 05502 $localPart = $this->getLocalPart($partType); 05503 $typeDef = $this->getTypeDef($localPart, $ns); 05504 if ($typeDef['typeClass'] == 'element') { 05505 $elementortype = 'element'; 05506 if (substr($localPart, -1) == '^') { 05507 $localPart = substr($localPart, 0, -1); 05508 } 05509 } else { 05510 $elementortype = 'type'; 05511 } 05512 $xml .= "\n" . ' <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />'; 05513 } 05514 } 05515 $xml .= '</message>'; 05516 } 05517 } 05518 // bindings & porttypes 05519 if (count($this->bindings) >= 1) { 05520 $binding_xml = ''; 05521 $portType_xml = ''; 05522 foreach($this->bindings as $bindingName => $attrs) { 05523 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">'; 05524 $binding_xml .= "\n" . ' <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>'; 05525 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">'; 05526 foreach($attrs['operations'] as $opName => $opParts) { 05527 $binding_xml .= "\n" . ' <operation name="' . $opName . '">'; 05528 $binding_xml .= "\n" . ' <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>'; 05529 if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { 05530 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; 05531 } else { 05532 $enc_style = ''; 05533 } 05534 $binding_xml .= "\n" . ' <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>'; 05535 if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { 05536 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; 05537 } else { 05538 $enc_style = ''; 05539 } 05540 $binding_xml .= "\n" . ' <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>'; 05541 $binding_xml .= "\n" . ' </operation>'; 05542 $portType_xml .= "\n" . ' <operation name="' . $opParts['name'] . '"'; 05543 if (isset($opParts['parameterOrder'])) { 05544 $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"'; 05545 } 05546 $portType_xml .= '>'; 05547 if(isset($opParts['documentation']) && $opParts['documentation'] != '') { 05548 $portType_xml .= "\n" . ' <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>'; 05549 } 05550 $portType_xml .= "\n" . ' <input message="tns:' . $opParts['input']['message'] . '"/>'; 05551 $portType_xml .= "\n" . ' <output message="tns:' . $opParts['output']['message'] . '"/>'; 05552 $portType_xml .= "\n" . ' </operation>'; 05553 } 05554 $portType_xml .= "\n" . '</portType>'; 05555 $binding_xml .= "\n" . '</binding>'; 05556 } 05557 $xml .= $portType_xml . $binding_xml; 05558 } 05559 // services 05560 $xml .= "\n<service name=\"" . $this->serviceName . '">'; 05561 if (count($this->ports) >= 1) { 05562 foreach($this->ports as $pName => $attrs) { 05563 $xml .= "\n" . ' <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">'; 05564 $xml .= "\n" . ' <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>'; 05565 $xml .= "\n" . ' </port>'; 05566 } 05567 } 05568 $xml .= "\n" . '</service>'; 05569 return $xml . "\n</definitions>"; 05570 } 05571 05581 function parametersMatchWrapped($type, &$parameters) { 05582 $this->debug("in parametersMatchWrapped type=$type, parameters="); 05583 $this->appendDebug($this->varDump($parameters)); 05584 05585 // split type into namespace:unqualified-type 05586 if (strpos($type, ':')) { 05587 $uqType = substr($type, strrpos($type, ':') + 1); 05588 $ns = substr($type, 0, strrpos($type, ':')); 05589 $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); 05590 if ($this->getNamespaceFromPrefix($ns)) { 05591 $ns = $this->getNamespaceFromPrefix($ns); 05592 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); 05593 } 05594 } else { 05595 // TODO: should the type be compared to types in XSD, and the namespace 05596 // set to XSD if the type matches? 05597 $this->debug("in parametersMatchWrapped: No namespace for type $type"); 05598 $ns = ''; 05599 $uqType = $type; 05600 } 05601 05602 // get the type information 05603 if (!$typeDef = $this->getTypeDef($uqType, $ns)) { 05604 $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); 05605 return false; 05606 } 05607 $this->debug("in parametersMatchWrapped: found typeDef="); 05608 $this->appendDebug($this->varDump($typeDef)); 05609 if (substr($uqType, -1) == '^') { 05610 $uqType = substr($uqType, 0, -1); 05611 } 05612 $phpType = $typeDef['phpType']; 05613 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); 05614 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); 05615 05616 // we expect a complexType or element of complexType 05617 if ($phpType != 'struct') { 05618 $this->debug("in parametersMatchWrapped: not a struct"); 05619 return false; 05620 } 05621 05622 // see whether the parameter names match the elements 05623 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 05624 $elements = 0; 05625 $matches = 0; 05626 foreach ($typeDef['elements'] as $name => $attrs) { 05627 if (isset($parameters[$name])) { 05628 $this->debug("in parametersMatchWrapped: have parameter named $name"); 05629 $matches++; 05630 } else { 05631 $this->debug("in parametersMatchWrapped: do not have parameter named $name"); 05632 } 05633 $elements++; 05634 } 05635 05636 $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); 05637 if ($matches == 0) { 05638 return false; 05639 } 05640 return true; 05641 } 05642 05643 // since there are no elements for the type, if the user passed no 05644 // parameters, the parameters match wrapped. 05645 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); 05646 return count($parameters) == 0; 05647 } 05648 05664 function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { 05665 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); 05666 $this->appendDebug('parameters=' . $this->varDump($parameters)); 05667 05668 if ($direction != 'input' && $direction != 'output') { 05669 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 05670 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 05671 return false; 05672 } 05673 if (!$opData = $this->getOperationData($operation, $bindingType)) { 05674 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 05675 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); 05676 return false; 05677 } 05678 $this->debug('in serializeRPCParameters: opData:'); 05679 $this->appendDebug($this->varDump($opData)); 05680 05681 // Get encoding style for output and set to current 05682 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 05683 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 05684 $encodingStyle = $opData['output']['encodingStyle']; 05685 $enc_style = $encodingStyle; 05686 } 05687 05688 // set input params 05689 $xml = ''; 05690 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 05691 $parts = &$opData[$direction]['parts']; 05692 $part_count = sizeof($parts); 05693 $style = $opData['style']; 05694 $use = $opData[$direction]['use']; 05695 $this->debug("have $part_count part(s) to serialize using $style/$use"); 05696 if (is_array($parameters)) { 05697 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 05698 $parameter_count = count($parameters); 05699 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); 05700 // check for Microsoft-style wrapped parameters 05701 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { 05702 $this->debug('check whether the caller has wrapped the parameters'); 05703 if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { 05704 // TODO: consider checking here for double-wrapping, when 05705 // service function wraps, then NuSOAP wraps again 05706 $this->debug("change simple array to associative with 'parameters' element"); 05707 $parameters['parameters'] = $parameters[0]; 05708 unset($parameters[0]); 05709 } 05710 if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { 05711 $this->debug('check whether caller\'s parameters match the wrapped ones'); 05712 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { 05713 $this->debug('wrap the parameters for the caller'); 05714 $parameters = array('parameters' => $parameters); 05715 $parameter_count = 1; 05716 } 05717 } 05718 } 05719 foreach ($parts as $name => $type) { 05720 $this->debug("serializing part $name of type $type"); 05721 // Track encoding style 05722 if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 05723 $encodingStyle = $opData[$direction]['encodingStyle']; 05724 $enc_style = $encodingStyle; 05725 } else { 05726 $enc_style = false; 05727 } 05728 // NOTE: add error handling here 05729 // if serializeType returns false, then catch global error and fault 05730 if ($parametersArrayType == 'arraySimple') { 05731 $p = array_shift($parameters); 05732 $this->debug('calling serializeType w/indexed param'); 05733 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 05734 } elseif (isset($parameters[$name])) { 05735 $this->debug('calling serializeType w/named param'); 05736 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 05737 } else { 05738 // TODO: only send nillable 05739 $this->debug('calling serializeType w/null param'); 05740 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 05741 } 05742 } 05743 } else { 05744 $this->debug('no parameters passed.'); 05745 } 05746 } 05747 $this->debug("serializeRPCParameters returning: $xml"); 05748 return $xml; 05749 } 05750 05765 function serializeParameters($operation, $direction, $parameters) 05766 { 05767 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); 05768 $this->appendDebug('parameters=' . $this->varDump($parameters)); 05769 05770 if ($direction != 'input' && $direction != 'output') { 05771 $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); 05772 $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); 05773 return false; 05774 } 05775 if (!$opData = $this->getOperationData($operation)) { 05776 $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); 05777 $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); 05778 return false; 05779 } 05780 $this->debug('opData:'); 05781 $this->appendDebug($this->varDump($opData)); 05782 05783 // Get encoding style for output and set to current 05784 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 05785 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { 05786 $encodingStyle = $opData['output']['encodingStyle']; 05787 $enc_style = $encodingStyle; 05788 } 05789 05790 // set input params 05791 $xml = ''; 05792 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { 05793 05794 $use = $opData[$direction]['use']; 05795 $this->debug("use=$use"); 05796 $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); 05797 if (is_array($parameters)) { 05798 $parametersArrayType = $this->isArraySimpleOrStruct($parameters); 05799 $this->debug('have ' . $parametersArrayType . ' parameters'); 05800 foreach($opData[$direction]['parts'] as $name => $type) { 05801 $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); 05802 // Track encoding style 05803 if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { 05804 $encodingStyle = $opData[$direction]['encodingStyle']; 05805 $enc_style = $encodingStyle; 05806 } else { 05807 $enc_style = false; 05808 } 05809 // NOTE: add error handling here 05810 // if serializeType returns false, then catch global error and fault 05811 if ($parametersArrayType == 'arraySimple') { 05812 $p = array_shift($parameters); 05813 $this->debug('calling serializeType w/indexed param'); 05814 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); 05815 } elseif (isset($parameters[$name])) { 05816 $this->debug('calling serializeType w/named param'); 05817 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); 05818 } else { 05819 // TODO: only send nillable 05820 $this->debug('calling serializeType w/null param'); 05821 $xml .= $this->serializeType($name, $type, null, $use, $enc_style); 05822 } 05823 } 05824 } else { 05825 $this->debug('no parameters passed.'); 05826 } 05827 } 05828 $this->debug("serializeParameters returning: $xml"); 05829 return $xml; 05830 } 05831 05844 function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) 05845 { 05846 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); 05847 $this->appendDebug("value=" . $this->varDump($value)); 05848 if($use == 'encoded' && $encodingStyle) { 05849 $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; 05850 } 05851 05852 // if a soapval has been supplied, let its type override the WSDL 05853 if (is_object($value) && get_class($value) == 'soapval') { 05854 if ($value->type_ns) { 05855 $type = $value->type_ns . ':' . $value->type; 05856 $forceType = true; 05857 $this->debug("in serializeType: soapval overrides type to $type"); 05858 } elseif ($value->type) { 05859 $type = $value->type; 05860 $forceType = true; 05861 $this->debug("in serializeType: soapval overrides type to $type"); 05862 } else { 05863 $forceType = false; 05864 $this->debug("in serializeType: soapval does not override type"); 05865 } 05866 $attrs = $value->attributes; 05867 $value = $value->value; 05868 $this->debug("in serializeType: soapval overrides value to $value"); 05869 if ($attrs) { 05870 if (!is_array($value)) { 05871 $value['!'] = $value; 05872 } 05873 foreach ($attrs as $n => $v) { 05874 $value['!' . $n] = $v; 05875 } 05876 $this->debug("in serializeType: soapval provides attributes"); 05877 } 05878 } else { 05879 $forceType = false; 05880 } 05881 05882 $xml = ''; 05883 if (strpos($type, ':')) { 05884 $uqType = substr($type, strrpos($type, ':') + 1); 05885 $ns = substr($type, 0, strrpos($type, ':')); 05886 $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); 05887 if ($this->getNamespaceFromPrefix($ns)) { 05888 $ns = $this->getNamespaceFromPrefix($ns); 05889 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); 05890 } 05891 05892 if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ 05893 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); 05894 if ($unqualified && $use == 'literal') { 05895 $elementNS = " xmlns=\"\""; 05896 } else { 05897 $elementNS = ''; 05898 } 05899 if (is_null($value)) { 05900 if ($use == 'literal') { 05901 // TODO: depends on minOccurs 05902 $xml = "<$name$elementNS/>"; 05903 } else { 05904 // TODO: depends on nillable, which should be checked before calling this method 05905 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 05906 } 05907 $this->debug("in serializeType: returning: $xml"); 05908 return $xml; 05909 } 05910 if ($uqType == 'Array') { 05911 // JBoss/Axis does this sometimes 05912 return $this->serialize_val($value, $name, false, false, false, false, $use); 05913 } 05914 if ($uqType == 'boolean') { 05915 if ((is_string($value) && $value == 'false') || (! $value)) { 05916 $value = 'false'; 05917 } else { 05918 $value = 'true'; 05919 } 05920 } 05921 if ($uqType == 'string' && gettype($value) == 'string') { 05922 $value = $this->expandEntities($value); 05923 } 05924 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { 05925 $value = sprintf("%.0lf", $value); 05926 } 05927 // it's a scalar 05928 // TODO: what about null/nil values? 05929 // check type isn't a custom type extending xmlschema namespace 05930 if (!$this->getTypeDef($uqType, $ns)) { 05931 if ($use == 'literal') { 05932 if ($forceType) { 05933 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 05934 } else { 05935 $xml = "<$name$elementNS>$value</$name>"; 05936 } 05937 } else { 05938 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 05939 } 05940 $this->debug("in serializeType: returning: $xml"); 05941 return $xml; 05942 } 05943 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); 05944 } else if ($ns == 'http://xml.apache.org/xml-soap') { 05945 $this->debug('in serializeType: appears to be Apache SOAP type'); 05946 if ($uqType == 'Map') { 05947 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 05948 if (! $tt_prefix) { 05949 $this->debug('in serializeType: Add namespace for Apache SOAP type'); 05950 $tt_prefix = 'ns' . rand(1000, 9999); 05951 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; 05952 // force this to be added to usedNamespaces 05953 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); 05954 } 05955 $contents = ''; 05956 foreach($value as $k => $v) { 05957 $this->debug("serializing map element: key $k, value $v"); 05958 $contents .= '<item>'; 05959 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); 05960 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); 05961 $contents .= '</item>'; 05962 } 05963 if ($use == 'literal') { 05964 if ($forceType) { 05965 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>"; 05966 } else { 05967 $xml = "<$name>$contents</$name>"; 05968 } 05969 } else { 05970 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>"; 05971 } 05972 $this->debug("in serializeType: returning: $xml"); 05973 return $xml; 05974 } 05975 $this->debug('in serializeType: Apache SOAP type, but only support Map'); 05976 } 05977 } else { 05978 // TODO: should the type be compared to types in XSD, and the namespace 05979 // set to XSD if the type matches? 05980 $this->debug("in serializeType: No namespace for type $type"); 05981 $ns = ''; 05982 $uqType = $type; 05983 } 05984 if(!$typeDef = $this->getTypeDef($uqType, $ns)){ 05985 $this->setError("$type ($uqType) is not a supported type."); 05986 $this->debug("in serializeType: $type ($uqType) is not a supported type."); 05987 return false; 05988 } else { 05989 $this->debug("in serializeType: found typeDef"); 05990 $this->appendDebug('typeDef=' . $this->varDump($typeDef)); 05991 if (substr($uqType, -1) == '^') { 05992 $uqType = substr($uqType, 0, -1); 05993 } 05994 } 05995 if (!isset($typeDef['phpType'])) { 05996 $this->setError("$type ($uqType) has no phpType."); 05997 $this->debug("in serializeType: $type ($uqType) has no phpType."); 05998 return false; 05999 } 06000 $phpType = $typeDef['phpType']; 06001 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); 06002 // if php type == struct, map value to the <all> element names 06003 if ($phpType == 'struct') { 06004 if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { 06005 $elementName = $uqType; 06006 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 06007 $elementNS = " xmlns=\"$ns\""; 06008 } else { 06009 $elementNS = " xmlns=\"\""; 06010 } 06011 } else { 06012 $elementName = $name; 06013 if ($unqualified) { 06014 $elementNS = " xmlns=\"\""; 06015 } else { 06016 $elementNS = ''; 06017 } 06018 } 06019 if (is_null($value)) { 06020 if ($use == 'literal') { 06021 // TODO: depends on minOccurs 06022 $xml = "<$elementName$elementNS/>"; 06023 } else { 06024 $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; 06025 } 06026 $this->debug("in serializeType: returning: $xml"); 06027 return $xml; 06028 } 06029 if (is_object($value)) { 06030 $value = get_object_vars($value); 06031 } 06032 if (is_array($value)) { 06033 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); 06034 if ($use == 'literal') { 06035 if ($forceType) { 06036 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; 06037 } else { 06038 $xml = "<$elementName$elementNS$elementAttrs>"; 06039 } 06040 } else { 06041 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; 06042 } 06043 06044 $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); 06045 $xml .= "</$elementName>"; 06046 } else { 06047 $this->debug("in serializeType: phpType is struct, but value is not an array"); 06048 $this->setError("phpType is struct, but value is not an array: see debug output for details"); 06049 $xml = ''; 06050 } 06051 } elseif ($phpType == 'array') { 06052 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 06053 $elementNS = " xmlns=\"$ns\""; 06054 } else { 06055 if ($unqualified) { 06056 $elementNS = " xmlns=\"\""; 06057 } else { 06058 $elementNS = ''; 06059 } 06060 } 06061 if (is_null($value)) { 06062 if ($use == 'literal') { 06063 // TODO: depends on minOccurs 06064 $xml = "<$name$elementNS/>"; 06065 } else { 06066 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . 06067 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 06068 ":Array\" " . 06069 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . 06070 ':arrayType="' . 06071 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . 06072 ':' . 06073 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; 06074 } 06075 $this->debug("in serializeType: returning: $xml"); 06076 return $xml; 06077 } 06078 if (isset($typeDef['multidimensional'])) { 06079 $nv = array(); 06080 foreach($value as $v) { 06081 $cols = ',' . sizeof($v); 06082 $nv = array_merge($nv, $v); 06083 } 06084 $value = $nv; 06085 } else { 06086 $cols = ''; 06087 } 06088 if (is_array($value) && sizeof($value) >= 1) { 06089 $rows = sizeof($value); 06090 $contents = ''; 06091 foreach($value as $k => $v) { 06092 $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); 06093 //if (strpos($typeDef['arrayType'], ':') ) { 06094 if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { 06095 $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); 06096 } else { 06097 $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); 06098 } 06099 } 06100 } else { 06101 $rows = 0; 06102 $contents = null; 06103 } 06104 // TODO: for now, an empty value will be serialized as a zero element 06105 // array. Revisit this when coding the handling of null/nil values. 06106 if ($use == 'literal') { 06107 $xml = "<$name$elementNS>" 06108 .$contents 06109 ."</$name>"; 06110 } else { 06111 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. 06112 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') 06113 .':arrayType="' 06114 .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) 06115 .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" 06116 .$contents 06117 ."</$name>"; 06118 } 06119 } elseif ($phpType == 'scalar') { 06120 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { 06121 $elementNS = " xmlns=\"$ns\""; 06122 } else { 06123 if ($unqualified) { 06124 $elementNS = " xmlns=\"\""; 06125 } else { 06126 $elementNS = ''; 06127 } 06128 } 06129 if ($use == 'literal') { 06130 if ($forceType) { 06131 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>"; 06132 } else { 06133 $xml = "<$name$elementNS>$value</$name>"; 06134 } 06135 } else { 06136 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>"; 06137 } 06138 } 06139 $this->debug("in serializeType: returning: $xml"); 06140 return $xml; 06141 } 06142 06153 function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { 06154 $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); 06155 $xml = ''; 06156 if (isset($typeDef['extensionBase'])) { 06157 $nsx = $this->getPrefix($typeDef['extensionBase']); 06158 $uqTypex = $this->getLocalPart($typeDef['extensionBase']); 06159 if ($this->getNamespaceFromPrefix($nsx)) { 06160 $nsx = $this->getNamespaceFromPrefix($nsx); 06161 } 06162 if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { 06163 $this->debug("serialize attributes for extension base $nsx:$uqTypex"); 06164 $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); 06165 } else { 06166 $this->debug("extension base $nsx:$uqTypex is not a supported type"); 06167 } 06168 } 06169 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { 06170 $this->debug("serialize attributes for XML Schema type $ns:$uqType"); 06171 if (is_array($value)) { 06172 $xvalue = $value; 06173 } elseif (is_object($value)) { 06174 $xvalue = get_object_vars($value); 06175 } else { 06176 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 06177 $xvalue = array(); 06178 } 06179 foreach ($typeDef['attrs'] as $aName => $attrs) { 06180 if (isset($xvalue['!' . $aName])) { 06181 $xname = '!' . $aName; 06182 $this->debug("value provided for attribute $aName with key $xname"); 06183 } elseif (isset($xvalue[$aName])) { 06184 $xname = $aName; 06185 $this->debug("value provided for attribute $aName with key $xname"); 06186 } elseif (isset($attrs['default'])) { 06187 $xname = '!' . $aName; 06188 $xvalue[$xname] = $attrs['default']; 06189 $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); 06190 } else { 06191 $xname = ''; 06192 $this->debug("no value provided for attribute $aName"); 06193 } 06194 if ($xname) { 06195 $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; 06196 } 06197 } 06198 } else { 06199 $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); 06200 } 06201 return $xml; 06202 } 06203 06216 function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { 06217 $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); 06218 $xml = ''; 06219 if (isset($typeDef['extensionBase'])) { 06220 $nsx = $this->getPrefix($typeDef['extensionBase']); 06221 $uqTypex = $this->getLocalPart($typeDef['extensionBase']); 06222 if ($this->getNamespaceFromPrefix($nsx)) { 06223 $nsx = $this->getNamespaceFromPrefix($nsx); 06224 } 06225 if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { 06226 $this->debug("serialize elements for extension base $nsx:$uqTypex"); 06227 $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); 06228 } else { 06229 $this->debug("extension base $nsx:$uqTypex is not a supported type"); 06230 } 06231 } 06232 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { 06233 $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); 06234 if (is_array($value)) { 06235 $xvalue = $value; 06236 } elseif (is_object($value)) { 06237 $xvalue = get_object_vars($value); 06238 } else { 06239 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); 06240 $xvalue = array(); 06241 } 06242 // toggle whether all elements are present - ideally should validate against schema 06243 if (count($typeDef['elements']) != count($xvalue)){ 06244 $optionals = true; 06245 } 06246 foreach ($typeDef['elements'] as $eName => $attrs) { 06247 if (!isset($xvalue[$eName])) { 06248 if (isset($attrs['default'])) { 06249 $xvalue[$eName] = $attrs['default']; 06250 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); 06251 } 06252 } 06253 // if user took advantage of a minOccurs=0, then only serialize named parameters 06254 if (isset($optionals) 06255 && (!isset($xvalue[$eName])) 06256 && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') 06257 ){ 06258 if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { 06259 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); 06260 } 06261 // do nothing 06262 $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); 06263 } else { 06264 // get value 06265 if (isset($xvalue[$eName])) { 06266 $v = $xvalue[$eName]; 06267 } else { 06268 $v = null; 06269 } 06270 if (isset($attrs['form'])) { 06271 $unqualified = ($attrs['form'] == 'unqualified'); 06272 } else { 06273 $unqualified = false; 06274 } 06275 if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { 06276 $vv = $v; 06277 foreach ($vv as $k => $v) { 06278 if (isset($attrs['type']) || isset($attrs['ref'])) { 06279 // serialize schema-defined type 06280 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 06281 } else { 06282 // serialize generic type (can this ever really happen?) 06283 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 06284 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 06285 } 06286 } 06287 } else { 06288 if (isset($attrs['type']) || isset($attrs['ref'])) { 06289 // serialize schema-defined type 06290 $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); 06291 } else { 06292 // serialize generic type (can this ever really happen?) 06293 $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); 06294 $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); 06295 } 06296 } 06297 } 06298 } 06299 } else { 06300 $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); 06301 } 06302 return $xml; 06303 } 06304 06319 function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { 06320 if (count($elements) > 0) { 06321 $eElements = array(); 06322 foreach($elements as $n => $e){ 06323 // expand each element 06324 $ee = array(); 06325 foreach ($e as $k => $v) { 06326 $k = strpos($k,':') ? $this->expandQname($k) : $k; 06327 $v = strpos($v,':') ? $this->expandQname($v) : $v; 06328 $ee[$k] = $v; 06329 } 06330 $eElements[$n] = $ee; 06331 } 06332 $elements = $eElements; 06333 } 06334 06335 if (count($attrs) > 0) { 06336 foreach($attrs as $n => $a){ 06337 // expand each attribute 06338 foreach ($a as $k => $v) { 06339 $k = strpos($k,':') ? $this->expandQname($k) : $k; 06340 $v = strpos($v,':') ? $this->expandQname($v) : $v; 06341 $aa[$k] = $v; 06342 } 06343 $eAttrs[$n] = $aa; 06344 } 06345 $attrs = $eAttrs; 06346 } 06347 06348 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 06349 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; 06350 06351 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 06352 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); 06353 } 06354 06366 function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { 06367 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; 06368 06369 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 06370 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); 06371 } 06372 06380 function addElement($attrs) { 06381 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; 06382 $this->schemas[$typens][0]->addElement($attrs); 06383 } 06384 06399 function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ 06400 if ($use == 'encoded' && $encodingStyle == '') { 06401 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 06402 } 06403 06404 if ($style == 'document') { 06405 $elements = array(); 06406 foreach ($in as $n => $t) { 06407 $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); 06408 } 06409 $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); 06410 $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); 06411 $in = array('parameters' => 'tns:' . $name . '^'); 06412 06413 $elements = array(); 06414 foreach ($out as $n => $t) { 06415 $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); 06416 } 06417 $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); 06418 $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); 06419 $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); 06420 } 06421 06422 // get binding 06423 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = 06424 array( 06425 'name' => $name, 06426 'binding' => $this->serviceName . 'Binding', 06427 'endpoint' => $this->endpoint, 06428 'soapAction' => $soapaction, 06429 'style' => $style, 06430 'input' => array( 06431 'use' => $use, 06432 'namespace' => $namespace, 06433 'encodingStyle' => $encodingStyle, 06434 'message' => $name . 'Request', 06435 'parts' => $in), 06436 'output' => array( 06437 'use' => $use, 06438 'namespace' => $namespace, 06439 'encodingStyle' => $encodingStyle, 06440 'message' => $name . 'Response', 06441 'parts' => $out), 06442 'namespace' => $namespace, 06443 'transport' => 'http://schemas.xmlsoap.org/soap/http', 06444 'documentation' => $documentation); 06445 // add portTypes 06446 // add messages 06447 if($in) 06448 { 06449 foreach($in as $pName => $pType) 06450 { 06451 if(strpos($pType,':')) { 06452 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 06453 } 06454 $this->messages[$name.'Request'][$pName] = $pType; 06455 } 06456 } else { 06457 $this->messages[$name.'Request']= '0'; 06458 } 06459 if($out) 06460 { 06461 foreach($out as $pName => $pType) 06462 { 06463 if(strpos($pType,':')) { 06464 $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); 06465 } 06466 $this->messages[$name.'Response'][$pName] = $pType; 06467 } 06468 } else { 06469 $this->messages[$name.'Response']= '0'; 06470 } 06471 return true; 06472 } 06473 } 06474 ?><?php 06475 06476 06477 06487 class nusoap_parser extends nusoap_base { 06488 06489 var $xml = ''; 06490 var $xml_encoding = ''; 06491 var $method = ''; 06492 var $root_struct = ''; 06493 var $root_struct_name = ''; 06494 var $root_struct_namespace = ''; 06495 var $root_header = ''; 06496 var $document = ''; // incoming SOAP body (text) 06497 // determines where in the message we are (envelope,header,body,method) 06498 var $status = ''; 06499 var $position = 0; 06500 var $depth = 0; 06501 var $default_namespace = ''; 06502 var $namespaces = array(); 06503 var $message = array(); 06504 var $parent = ''; 06505 var $fault = false; 06506 var $fault_code = ''; 06507 var $fault_str = ''; 06508 var $fault_detail = ''; 06509 var $depth_array = array(); 06510 var $debug_flag = true; 06511 var $soapresponse = NULL; // parsed SOAP Body 06512 var $soapheader = NULL; // parsed SOAP Header 06513 var $responseHeaders = ''; // incoming SOAP headers (text) 06514 var $body_position = 0; 06515 // for multiref parsing: 06516 // array of id => pos 06517 var $ids = array(); 06518 // array of id => hrefs => pos 06519 var $multirefs = array(); 06520 // toggle for auto-decoding element content 06521 var $decode_utf8 = true; 06522 06532 function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ 06533 parent::nusoap_base(); 06534 $this->xml = $xml; 06535 $this->xml_encoding = $encoding; 06536 $this->method = $method; 06537 $this->decode_utf8 = $decode_utf8; 06538 06539 // Check whether content has been read. 06540 if(!empty($xml)){ 06541 // Check XML encoding 06542 $pos_xml = strpos($xml, '<?xml'); 06543 if ($pos_xml !== FALSE) { 06544 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); 06545 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { 06546 $xml_encoding = $res[1]; 06547 if (strtoupper($xml_encoding) != $encoding) { 06548 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; 06549 $this->debug($err); 06550 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { 06551 $this->setError($err); 06552 return; 06553 } 06554 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed 06555 } else { 06556 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); 06557 } 06558 } else { 06559 $this->debug('No encoding specified in XML declaration'); 06560 } 06561 } else { 06562 $this->debug('No XML declaration'); 06563 } 06564 $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); 06565 // Create an XML parser - why not xml_parser_create_ns? 06566 $this->parser = xml_parser_create($this->xml_encoding); 06567 // Set the options for parsing the XML data. 06568 //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); 06569 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); 06570 xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); 06571 // Set the object for the parser. 06572 xml_set_object($this->parser, $this); 06573 // Set the element handlers for the parser. 06574 xml_set_element_handler($this->parser, 'start_element','end_element'); 06575 xml_set_character_data_handler($this->parser,'character_data'); 06576 06577 // Parse the XML file. 06578 if(!xml_parse($this->parser,$xml,true)){ 06579 // Display an error message. 06580 $err = sprintf('XML error parsing SOAP payload on line %d: %s', 06581 xml_get_current_line_number($this->parser), 06582 xml_error_string(xml_get_error_code($this->parser))); 06583 $this->debug($err); 06584 $this->debug("XML payload:\n" . $xml); 06585 $this->setError($err); 06586 } else { 06587 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); 06588 // get final value 06589 $this->soapresponse = $this->message[$this->root_struct]['result']; 06590 // get header value 06591 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ 06592 $this->soapheader = $this->message[$this->root_header]['result']; 06593 } 06594 // resolve hrefs/ids 06595 if(sizeof($this->multirefs) > 0){ 06596 foreach($this->multirefs as $id => $hrefs){ 06597 $this->debug('resolving multirefs for id: '.$id); 06598 $idVal = $this->buildVal($this->ids[$id]); 06599 if (is_array($idVal) && isset($idVal['!id'])) { 06600 unset($idVal['!id']); 06601 } 06602 foreach($hrefs as $refPos => $ref){ 06603 $this->debug('resolving href at pos '.$refPos); 06604 $this->multirefs[$id][$refPos] = $idVal; 06605 } 06606 } 06607 } 06608 } 06609 xml_parser_free($this->parser); 06610 } else { 06611 $this->debug('xml was empty, didn\'t parse!'); 06612 $this->setError('xml was empty, didn\'t parse!'); 06613 } 06614 } 06615 06624 function start_element($parser, $name, $attrs) { 06625 // position in a total number of elements, starting from 0 06626 // update class level pos 06627 $pos = $this->position++; 06628 // and set mine 06629 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); 06630 // depth = how many levels removed from root? 06631 // set mine as current global depth and increment global depth value 06632 $this->message[$pos]['depth'] = $this->depth++; 06633 06634 // else add self as child to whoever the current parent is 06635 if($pos != 0){ 06636 $this->message[$this->parent]['children'] .= '|'.$pos; 06637 } 06638 // set my parent 06639 $this->message[$pos]['parent'] = $this->parent; 06640 // set self as current parent 06641 $this->parent = $pos; 06642 // set self as current value for this depth 06643 $this->depth_array[$this->depth] = $pos; 06644 // get element prefix 06645 if(strpos($name,':')){ 06646 // get ns prefix 06647 $prefix = substr($name,0,strpos($name,':')); 06648 // get unqualified name 06649 $name = substr(strstr($name,':'),1); 06650 } 06651 // set status 06652 if($name == 'Envelope'){ 06653 $this->status = 'envelope'; 06654 } elseif($name == 'Header' && $this->status = 'envelope'){ 06655 $this->root_header = $pos; 06656 $this->status = 'header'; 06657 } elseif($name == 'Body' && $this->status = 'envelope'){ 06658 $this->status = 'body'; 06659 $this->body_position = $pos; 06660 // set method 06661 } elseif($this->status == 'body' && $pos == ($this->body_position+1)){ 06662 $this->status = 'method'; 06663 $this->root_struct_name = $name; 06664 $this->root_struct = $pos; 06665 $this->message[$pos]['type'] = 'struct'; 06666 $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); 06667 } 06668 // set my status 06669 $this->message[$pos]['status'] = $this->status; 06670 // set name 06671 $this->message[$pos]['name'] = htmlspecialchars($name); 06672 // set attrs 06673 $this->message[$pos]['attrs'] = $attrs; 06674 06675 // loop through atts, logging ns and type declarations 06676 $attstr = ''; 06677 foreach($attrs as $key => $value){ 06678 $key_prefix = $this->getPrefix($key); 06679 $key_localpart = $this->getLocalPart($key); 06680 // if ns declarations, add to class level array of valid namespaces 06681 if($key_prefix == 'xmlns'){ 06682 if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ 06683 $this->XMLSchemaVersion = $value; 06684 $this->namespaces['xsd'] = $this->XMLSchemaVersion; 06685 $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; 06686 } 06687 $this->namespaces[$key_localpart] = $value; 06688 // set method namespace 06689 if($name == $this->root_struct_name){ 06690 $this->methodNamespace = $value; 06691 } 06692 // if it's a type declaration, set type 06693 } elseif($key_localpart == 'type'){ 06694 if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { 06695 // do nothing: already processed arrayType 06696 } else { 06697 $value_prefix = $this->getPrefix($value); 06698 $value_localpart = $this->getLocalPart($value); 06699 $this->message[$pos]['type'] = $value_localpart; 06700 $this->message[$pos]['typePrefix'] = $value_prefix; 06701 if(isset($this->namespaces[$value_prefix])){ 06702 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; 06703 } else if(isset($attrs['xmlns:'.$value_prefix])) { 06704 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; 06705 } 06706 // should do something here with the namespace of specified type? 06707 } 06708 } elseif($key_localpart == 'arrayType'){ 06709 $this->message[$pos]['type'] = 'array'; 06710 /* do arrayType ereg here 06711 [1] arrayTypeValue ::= atype asize 06712 [2] atype ::= QName rank* 06713 [3] rank ::= '[' (',')* ']' 06714 [4] asize ::= '[' length~ ']' 06715 [5] length ::= nextDimension* Digit+ 06716 [6] nextDimension ::= Digit+ ',' 06717 */ 06718 $expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; 06719 if(ereg($expr,$value,$regs)){ 06720 $this->message[$pos]['typePrefix'] = $regs[1]; 06721 $this->message[$pos]['arrayTypePrefix'] = $regs[1]; 06722 if (isset($this->namespaces[$regs[1]])) { 06723 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; 06724 } else if (isset($attrs['xmlns:'.$regs[1]])) { 06725 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; 06726 } 06727 $this->message[$pos]['arrayType'] = $regs[2]; 06728 $this->message[$pos]['arraySize'] = $regs[3]; 06729 $this->message[$pos]['arrayCols'] = $regs[4]; 06730 } 06731 // specifies nil value (or not) 06732 } elseif ($key_localpart == 'nil'){ 06733 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); 06734 // some other attribute 06735 } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { 06736 $this->message[$pos]['xattrs']['!' . $key] = $value; 06737 } 06738 06739 if ($key == 'xmlns') { 06740 $this->default_namespace = $value; 06741 } 06742 // log id 06743 if($key == 'id'){ 06744 $this->ids[$value] = $pos; 06745 } 06746 // root 06747 if($key_localpart == 'root' && $value == 1){ 06748 $this->status = 'method'; 06749 $this->root_struct_name = $name; 06750 $this->root_struct = $pos; 06751 $this->debug("found root struct $this->root_struct_name, pos $pos"); 06752 } 06753 // for doclit 06754 $attstr .= " $key=\"$value\""; 06755 } 06756 // get namespace - must be done after namespace atts are processed 06757 if(isset($prefix)){ 06758 $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; 06759 $this->default_namespace = $this->namespaces[$prefix]; 06760 } else { 06761 $this->message[$pos]['namespace'] = $this->default_namespace; 06762 } 06763 if($this->status == 'header'){ 06764 if ($this->root_header != $pos) { 06765 $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 06766 } 06767 } elseif($this->root_struct_name != ''){ 06768 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; 06769 } 06770 } 06771 06779 function end_element($parser, $name) { 06780 // position of current element is equal to the last value left in depth_array for my depth 06781 $pos = $this->depth_array[$this->depth--]; 06782 06783 // get element prefix 06784 if(strpos($name,':')){ 06785 // get ns prefix 06786 $prefix = substr($name,0,strpos($name,':')); 06787 // get unqualified name 06788 $name = substr(strstr($name,':'),1); 06789 } 06790 06791 // build to native type 06792 if(isset($this->body_position) && $pos > $this->body_position){ 06793 // deal w/ multirefs 06794 if(isset($this->message[$pos]['attrs']['href'])){ 06795 // get id 06796 $id = substr($this->message[$pos]['attrs']['href'],1); 06797 // add placeholder to href array 06798 $this->multirefs[$id][$pos] = 'placeholder'; 06799 // add set a reference to it as the result value 06800 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; 06801 // build complexType values 06802 } elseif($this->message[$pos]['children'] != ''){ 06803 // if result has already been generated (struct/array) 06804 if(!isset($this->message[$pos]['result'])){ 06805 $this->message[$pos]['result'] = $this->buildVal($pos); 06806 } 06807 // build complexType values of attributes and possibly simpleContent 06808 } elseif (isset($this->message[$pos]['xattrs'])) { 06809 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 06810 $this->message[$pos]['xattrs']['!'] = null; 06811 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 06812 if (isset($this->message[$pos]['type'])) { 06813 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 06814 } else { 06815 $parent = $this->message[$pos]['parent']; 06816 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 06817 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 06818 } else { 06819 $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; 06820 } 06821 } 06822 } 06823 $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; 06824 // set value of simpleType (or nil complexType) 06825 } else { 06826 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); 06827 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { 06828 $this->message[$pos]['xattrs']['!'] = null; 06829 } elseif (isset($this->message[$pos]['type'])) { 06830 $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'] : ''); 06831 } else { 06832 $parent = $this->message[$pos]['parent']; 06833 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 06834 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 06835 } else { 06836 $this->message[$pos]['result'] = $this->message[$pos]['cdata']; 06837 } 06838 } 06839 06840 /* add value to parent's result, if parent is struct/array 06841 $parent = $this->message[$pos]['parent']; 06842 if($this->message[$parent]['type'] != 'map'){ 06843 if(strtolower($this->message[$parent]['type']) == 'array'){ 06844 $this->message[$parent]['result'][] = $this->message[$pos]['result']; 06845 } else { 06846 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; 06847 } 06848 } 06849 */ 06850 } 06851 } 06852 06853 // for doclit 06854 if($this->status == 'header'){ 06855 if ($this->root_header != $pos) { 06856 $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 06857 } 06858 } elseif($pos >= $this->root_struct){ 06859 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; 06860 } 06861 // switch status 06862 if($pos == $this->root_struct){ 06863 $this->status = 'body'; 06864 $this->root_struct_namespace = $this->message[$pos]['namespace']; 06865 } elseif($name == 'Body'){ 06866 $this->status = 'envelope'; 06867 } elseif($name == 'Header'){ 06868 $this->status = 'envelope'; 06869 } elseif($name == 'Envelope'){ 06870 // 06871 } 06872 // set parent back to my parent 06873 $this->parent = $this->message[$pos]['parent']; 06874 } 06875 06883 function character_data($parser, $data){ 06884 $pos = $this->depth_array[$this->depth]; 06885 if ($this->xml_encoding=='UTF-8'){ 06886 // TODO: add an option to disable this for folks who want 06887 // raw UTF-8 that, e.g., might not map to iso-8859-1 06888 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); 06889 if($this->decode_utf8){ 06890 $data = utf8_decode($data); 06891 } 06892 } 06893 $this->message[$pos]['cdata'] .= $data; 06894 // for doclit 06895 if($this->status == 'header'){ 06896 $this->responseHeaders .= $data; 06897 } else { 06898 $this->document .= $data; 06899 } 06900 } 06901 06909 function get_response(){ 06910 return $this->soapresponse; 06911 } 06912 06919 function get_soapbody(){ 06920 return $this->soapresponse; 06921 } 06922 06929 function get_soapheader(){ 06930 return $this->soapheader; 06931 } 06932 06939 function getHeaders(){ 06940 return $this->responseHeaders; 06941 } 06942 06952 function decodeSimple($value, $type, $typens) { 06953 // TODO: use the namespace! 06954 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { 06955 return (string) $value; 06956 } 06957 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { 06958 return (int) $value; 06959 } 06960 if ($type == 'float' || $type == 'double' || $type == 'decimal') { 06961 return (double) $value; 06962 } 06963 if ($type == 'boolean') { 06964 if (strtolower($value) == 'false' || strtolower($value) == 'f') { 06965 return false; 06966 } 06967 return (boolean) $value; 06968 } 06969 if ($type == 'base64' || $type == 'base64Binary') { 06970 $this->debug('Decode base64 value'); 06971 return base64_decode($value); 06972 } 06973 // obscure numeric types 06974 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' 06975 || $type == 'nonNegativeInteger' || $type == 'positiveInteger' 06976 || $type == 'unsignedInt' 06977 || $type == 'unsignedShort' || $type == 'unsignedByte') { 06978 return (int) $value; 06979 } 06980 // bogus: parser treats array with no elements as a simple type 06981 if ($type == 'array') { 06982 return array(); 06983 } 06984 // everything else 06985 return (string) $value; 06986 } 06987 06996 function buildVal($pos){ 06997 if(!isset($this->message[$pos]['type'])){ 06998 $this->message[$pos]['type'] = ''; 06999 } 07000 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); 07001 // if there are children... 07002 if($this->message[$pos]['children'] != ''){ 07003 $this->debug('in buildVal, there are children'); 07004 $children = explode('|',$this->message[$pos]['children']); 07005 array_shift($children); // knock off empty 07006 // md array 07007 if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ 07008 $r=0; // rowcount 07009 $c=0; // colcount 07010 foreach($children as $child_pos){ 07011 $this->debug("in buildVal, got an MD array element: $r, $c"); 07012 $params[$r][] = $this->message[$child_pos]['result']; 07013 $c++; 07014 if($c == $this->message[$pos]['arrayCols']){ 07015 $c = 0; 07016 $r++; 07017 } 07018 } 07019 // array 07020 } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ 07021 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); 07022 foreach($children as $child_pos){ 07023 $params[] = &$this->message[$child_pos]['result']; 07024 } 07025 // apache Map type: java hashtable 07026 } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ 07027 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); 07028 foreach($children as $child_pos){ 07029 $kv = explode("|",$this->message[$child_pos]['children']); 07030 $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; 07031 } 07032 // generic compound type 07033 //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { 07034 } else { 07035 // Apache Vector type: treat as an array 07036 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); 07037 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { 07038 $notstruct = 1; 07039 } else { 07040 $notstruct = 0; 07041 } 07042 // 07043 foreach($children as $child_pos){ 07044 if($notstruct){ 07045 $params[] = &$this->message[$child_pos]['result']; 07046 } else { 07047 if (isset($params[$this->message[$child_pos]['name']])) { 07048 // de-serialize repeated element name into an array 07049 if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { 07050 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); 07051 } 07052 $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; 07053 } else { 07054 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; 07055 } 07056 } 07057 } 07058 } 07059 if (isset($this->message[$pos]['xattrs'])) { 07060 $this->debug('in buildVal, handling attributes'); 07061 foreach ($this->message[$pos]['xattrs'] as $n => $v) { 07062 $params[$n] = $v; 07063 } 07064 } 07065 // handle simpleContent 07066 if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { 07067 $this->debug('in buildVal, handling simpleContent'); 07068 if (isset($this->message[$pos]['type'])) { 07069 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 07070 } else { 07071 $parent = $this->message[$pos]['parent']; 07072 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 07073 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 07074 } else { 07075 $params['!'] = $this->message[$pos]['cdata']; 07076 } 07077 } 07078 } 07079 $ret = is_array($params) ? $params : array(); 07080 $this->debug('in buildVal, return:'); 07081 $this->appendDebug($this->varDump($ret)); 07082 return $ret; 07083 } else { 07084 $this->debug('in buildVal, no children, building scalar'); 07085 $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; 07086 if (isset($this->message[$pos]['type'])) { 07087 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); 07088 $this->debug("in buildVal, return: $ret"); 07089 return $ret; 07090 } 07091 $parent = $this->message[$pos]['parent']; 07092 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { 07093 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); 07094 $this->debug("in buildVal, return: $ret"); 07095 return $ret; 07096 } 07097 $ret = $this->message[$pos]['cdata']; 07098 $this->debug("in buildVal, return: $ret"); 07099 return $ret; 07100 } 07101 } 07102 } 07103 07107 class soap_parser extends nusoap_parser { 07108 } 07109 07110 ?><?php 07111 07112 07113 07134 class nusoap_client extends nusoap_base { 07135 07136 var $username = ''; // Username for HTTP authentication 07137 var $password = ''; // Password for HTTP authentication 07138 var $authtype = ''; // Type of HTTP authentication 07139 var $certRequest = array(); // Certificate for HTTP SSL authentication 07140 var $requestHeaders = false; // SOAP headers in request (text) 07141 var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) 07142 var $responseHeader = NULL; // SOAP Header from response (parsed) 07143 var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) 07144 var $endpoint; 07145 var $forceEndpoint = ''; // overrides WSDL endpoint 07146 var $proxyhost = ''; 07147 var $proxyport = ''; 07148 var $proxyusername = ''; 07149 var $proxypassword = ''; 07150 var $portName = ''; // port name to use in WSDL 07151 var $xml_encoding = ''; // character set encoding of incoming (response) messages 07152 var $http_encoding = false; 07153 var $timeout = 0; // HTTP connection timeout 07154 var $response_timeout = 30; // HTTP response timeout 07155 var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error 07156 var $persistentConnection = false; 07157 var $defaultRpcParams = false; // This is no longer used 07158 var $request = ''; // HTTP request 07159 var $response = ''; // HTTP response 07160 var $responseData = ''; // SOAP payload of response 07161 var $cookies = array(); // Cookies from response or for request 07162 var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() 07163 var $operations = array(); // WSDL operations, empty for WSDL initialization error 07164 var $curl_options = array(); // User-specified cURL options 07165 var $bindingType = ''; // WSDL operation binding type 07166 var $use_curl = false; // whether to always try to use cURL 07167 07168 /* 07169 * fault related variables 07170 */ 07175 var $fault; 07180 var $faultcode; 07185 var $faultstring; 07190 var $faultdetail; 07191 07206 function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ 07207 parent::nusoap_base(); 07208 $this->endpoint = $endpoint; 07209 $this->proxyhost = $proxyhost; 07210 $this->proxyport = $proxyport; 07211 $this->proxyusername = $proxyusername; 07212 $this->proxypassword = $proxypassword; 07213 $this->timeout = $timeout; 07214 $this->response_timeout = $response_timeout; 07215 $this->portName = $portName; 07216 07217 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); 07218 $this->appendDebug('endpoint=' . $this->varDump($endpoint)); 07219 07220 // make values 07221 if($wsdl){ 07222 if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { 07223 $this->wsdl = $endpoint; 07224 $this->endpoint = $this->wsdl->wsdl; 07225 $this->wsdlFile = $this->endpoint; 07226 $this->debug('existing wsdl instance created from ' . $this->endpoint); 07227 $this->checkWSDL(); 07228 } else { 07229 $this->wsdlFile = $this->endpoint; 07230 $this->wsdl = null; 07231 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); 07232 } 07233 $this->endpointType = 'wsdl'; 07234 } else { 07235 $this->debug("instantiate SOAP with endpoint at $endpoint"); 07236 $this->endpointType = 'soap'; 07237 } 07238 } 07239 07265 function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ 07266 $this->operation = $operation; 07267 $this->fault = false; 07268 $this->setError(''); 07269 $this->request = ''; 07270 $this->response = ''; 07271 $this->responseData = ''; 07272 $this->faultstring = ''; 07273 $this->faultcode = ''; 07274 $this->opData = array(); 07275 07276 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); 07277 $this->appendDebug('params=' . $this->varDump($params)); 07278 $this->appendDebug('headers=' . $this->varDump($headers)); 07279 if ($headers) { 07280 $this->requestHeaders = $headers; 07281 } 07282 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 07283 $this->loadWSDL(); 07284 if ($this->getError()) 07285 return false; 07286 } 07287 // serialize parameters 07288 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ 07289 // use WSDL for operation 07290 $this->opData = $opData; 07291 $this->debug("found operation"); 07292 $this->appendDebug('opData=' . $this->varDump($opData)); 07293 if (isset($opData['soapAction'])) { 07294 $soapAction = $opData['soapAction']; 07295 } 07296 if (! $this->forceEndpoint) { 07297 $this->endpoint = $opData['endpoint']; 07298 } else { 07299 $this->endpoint = $this->forceEndpoint; 07300 } 07301 $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; 07302 $style = $opData['style']; 07303 $use = $opData['input']['use']; 07304 // add ns to ns array 07305 if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ 07306 $nsPrefix = 'ns' . rand(1000, 9999); 07307 $this->wsdl->namespaces[$nsPrefix] = $namespace; 07308 } 07309 $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); 07310 // serialize payload 07311 if (is_string($params)) { 07312 $this->debug("serializing param string for WSDL operation $operation"); 07313 $payload = $params; 07314 } elseif (is_array($params)) { 07315 $this->debug("serializing param array for WSDL operation $operation"); 07316 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); 07317 } else { 07318 $this->debug('params must be array or string'); 07319 $this->setError('params must be array or string'); 07320 return false; 07321 } 07322 $usedNamespaces = $this->wsdl->usedNamespaces; 07323 if (isset($opData['input']['encodingStyle'])) { 07324 $encodingStyle = $opData['input']['encodingStyle']; 07325 } else { 07326 $encodingStyle = ''; 07327 } 07328 $this->appendDebug($this->wsdl->getDebug()); 07329 $this->wsdl->clearDebug(); 07330 if ($errstr = $this->wsdl->getError()) { 07331 $this->debug('got wsdl error: '.$errstr); 07332 $this->setError('wsdl error: '.$errstr); 07333 return false; 07334 } 07335 } elseif($this->endpointType == 'wsdl') { 07336 // operation not in WSDL 07337 $this->appendDebug($this->wsdl->getDebug()); 07338 $this->wsdl->clearDebug(); 07339 $this->setError( 'operation '.$operation.' not present.'); 07340 $this->debug("operation '$operation' not present."); 07341 return false; 07342 } else { 07343 // no WSDL 07344 //$this->namespaces['ns1'] = $namespace; 07345 $nsPrefix = 'ns' . rand(1000, 9999); 07346 // serialize 07347 $payload = ''; 07348 if (is_string($params)) { 07349 $this->debug("serializing param string for operation $operation"); 07350 $payload = $params; 07351 } elseif (is_array($params)) { 07352 $this->debug("serializing param array for operation $operation"); 07353 foreach($params as $k => $v){ 07354 $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); 07355 } 07356 } else { 07357 $this->debug('params must be array or string'); 07358 $this->setError('params must be array or string'); 07359 return false; 07360 } 07361 $usedNamespaces = array(); 07362 if ($use == 'encoded') { 07363 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; 07364 } else { 07365 $encodingStyle = ''; 07366 } 07367 } 07368 // wrap RPC calls with method element 07369 if ($style == 'rpc') { 07370 if ($use == 'literal') { 07371 $this->debug("wrapping RPC request with literal method element"); 07372 if ($namespace) { 07373 // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace 07374 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 07375 $payload . 07376 "</$nsPrefix:$operation>"; 07377 } else { 07378 $payload = "<$operation>" . $payload . "</$operation>"; 07379 } 07380 } else { 07381 $this->debug("wrapping RPC request with encoded method element"); 07382 if ($namespace) { 07383 $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . 07384 $payload . 07385 "</$nsPrefix:$operation>"; 07386 } else { 07387 $payload = "<$operation>" . 07388 $payload . 07389 "</$operation>"; 07390 } 07391 } 07392 } 07393 // serialize envelope 07394 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); 07395 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); 07396 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); 07397 // send 07398 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); 07399 if($errstr = $this->getError()){ 07400 $this->debug('Error: '.$errstr); 07401 return false; 07402 } else { 07403 $this->return = $return; 07404 $this->debug('sent message successfully and got a(n) '.gettype($return)); 07405 $this->appendDebug('return=' . $this->varDump($return)); 07406 07407 // fault? 07408 if(is_array($return) && isset($return['faultcode'])){ 07409 $this->debug('got fault'); 07410 $this->setError($return['faultcode'].': '.$return['faultstring']); 07411 $this->fault = true; 07412 foreach($return as $k => $v){ 07413 $this->$k = $v; 07414 $this->debug("$k = $v<br>"); 07415 } 07416 return $return; 07417 } elseif ($style == 'document') { 07418 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), 07419 // we are only going to return the first part here...sorry about that 07420 return $return; 07421 } else { 07422 // array of return values 07423 if(is_array($return)){ 07424 // multiple 'out' parameters, which we return wrapped up 07425 // in the array 07426 if(sizeof($return) > 1){ 07427 return $return; 07428 } 07429 // single 'out' parameter (normally the return value) 07430 $return = array_shift($return); 07431 $this->debug('return shifted value: '); 07432 $this->appendDebug($this->varDump($return)); 07433 return $return; 07434 // nothing returned (ie, echoVoid) 07435 } else { 07436 return ""; 07437 } 07438 } 07439 } 07440 } 07441 07447 function checkWSDL() { 07448 $this->appendDebug($this->wsdl->getDebug()); 07449 $this->wsdl->clearDebug(); 07450 $this->debug('checkWSDL'); 07451 // catch errors 07452 if ($errstr = $this->wsdl->getError()) { 07453 $this->appendDebug($this->wsdl->getDebug()); 07454 $this->wsdl->clearDebug(); 07455 $this->debug('got wsdl error: '.$errstr); 07456 $this->setError('wsdl error: '.$errstr); 07457 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { 07458 $this->appendDebug($this->wsdl->getDebug()); 07459 $this->wsdl->clearDebug(); 07460 $this->bindingType = 'soap'; 07461 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 07462 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { 07463 $this->appendDebug($this->wsdl->getDebug()); 07464 $this->wsdl->clearDebug(); 07465 $this->bindingType = 'soap12'; 07466 $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); 07467 $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); 07468 } else { 07469 $this->appendDebug($this->wsdl->getDebug()); 07470 $this->wsdl->clearDebug(); 07471 $this->debug('getOperations returned false'); 07472 $this->setError('no operations defined in the WSDL document!'); 07473 } 07474 } 07475 07481 function loadWSDL() { 07482 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); 07483 $this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); 07484 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); 07485 $this->wsdl->fetchWSDL($this->wsdlFile); 07486 $this->checkWSDL(); 07487 } 07488 07496 function getOperationData($operation){ 07497 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 07498 $this->loadWSDL(); 07499 if ($this->getError()) 07500 return false; 07501 } 07502 if(isset($this->operations[$operation])){ 07503 return $this->operations[$operation]; 07504 } 07505 $this->debug("No data for operation: $operation"); 07506 } 07507 07522 function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { 07523 $this->checkCookies(); 07524 // detect transport 07525 switch(true){ 07526 // http(s) 07527 case ereg('^http',$this->endpoint): 07528 $this->debug('transporting via HTTP'); 07529 if($this->persistentConnection == true && is_object($this->persistentConnection)){ 07530 $http =& $this->persistentConnection; 07531 } else { 07532 $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); 07533 if ($this->persistentConnection) { 07534 $http->usePersistentConnection(); 07535 } 07536 } 07537 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); 07538 $http->setSOAPAction($soapaction); 07539 if($this->proxyhost && $this->proxyport){ 07540 $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); 07541 } 07542 if($this->authtype != '') { 07543 $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); 07544 } 07545 if($this->http_encoding != ''){ 07546 $http->setEncoding($this->http_encoding); 07547 } 07548 $this->debug('sending message, length='.strlen($msg)); 07549 if(ereg('^http:',$this->endpoint)){ 07550 //if(strpos($this->endpoint,'http:')){ 07551 $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); 07552 } elseif(ereg('^https',$this->endpoint)){ 07553 //} elseif(strpos($this->endpoint,'https:')){ 07554 //if(phpversion() == '4.3.0-dev'){ 07555 //$response = $http->send($msg,$timeout,$response_timeout); 07556 //$this->request = $http->outgoing_payload; 07557 //$this->response = $http->incoming_payload; 07558 //} else 07559 $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); 07560 } else { 07561 $this->setError('no http/s in endpoint url'); 07562 } 07563 $this->request = $http->outgoing_payload; 07564 $this->response = $http->incoming_payload; 07565 $this->appendDebug($http->getDebug()); 07566 $this->UpdateCookies($http->incoming_cookies); 07567 07568 // save transport object if using persistent connections 07569 if ($this->persistentConnection) { 07570 $http->clearDebug(); 07571 if (!is_object($this->persistentConnection)) { 07572 $this->persistentConnection = $http; 07573 } 07574 } 07575 07576 if($err = $http->getError()){ 07577 $this->setError('HTTP Error: '.$err); 07578 return false; 07579 } elseif($this->getError()){ 07580 return false; 07581 } else { 07582 $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); 07583 return $this->parseResponse($http->incoming_headers, $this->responseData); 07584 } 07585 break; 07586 default: 07587 $this->setError('no transport found, or selected transport is not yet supported!'); 07588 return false; 07589 break; 07590 } 07591 } 07592 07601 function parseResponse($headers, $data) { 07602 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); 07603 $this->appendDebug($this->varDump($headers)); 07604 if (!isset($headers['content-type'])) { 07605 $this->setError('Response not of type text/xml (no content-type header)'); 07606 return false; 07607 } 07608 if (!strstr($headers['content-type'], 'text/xml')) { 07609 $this->setError('Response not of type text/xml: ' . $headers['content-type']); 07610 return false; 07611 } 07612 if (strpos($headers['content-type'], '=')) { 07613 $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); 07614 $this->debug('Got response encoding: ' . $enc); 07615 if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ 07616 $this->xml_encoding = strtoupper($enc); 07617 } else { 07618 $this->xml_encoding = 'US-ASCII'; 07619 } 07620 } else { 07621 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 07622 $this->xml_encoding = 'ISO-8859-1'; 07623 } 07624 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); 07625 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); 07626 // add parser debug data to our debug 07627 $this->appendDebug($parser->getDebug()); 07628 // if parse errors 07629 if($errstr = $parser->getError()){ 07630 $this->setError( $errstr); 07631 // destroy the parser object 07632 unset($parser); 07633 return false; 07634 } else { 07635 // get SOAP headers 07636 $this->responseHeaders = $parser->getHeaders(); 07637 // get SOAP headers 07638 $this->responseHeader = $parser->get_soapheader(); 07639 // get decoded message 07640 $return = $parser->get_soapbody(); 07641 // add document for doclit support 07642 $this->document = $parser->document; 07643 // destroy the parser object 07644 unset($parser); 07645 // return decode message 07646 return $return; 07647 } 07648 } 07649 07657 function setCurlOption($option, $value) { 07658 $this->debug("setCurlOption option=$option, value="); 07659 $this->appendDebug($this->varDump($value)); 07660 $this->curl_options[$option] = $value; 07661 } 07662 07669 function setEndpoint($endpoint) { 07670 $this->debug("setEndpoint(\"$endpoint\")"); 07671 $this->forceEndpoint = $endpoint; 07672 } 07673 07680 function setHeaders($headers){ 07681 $this->debug("setHeaders headers="); 07682 $this->appendDebug($this->varDump($headers)); 07683 $this->requestHeaders = $headers; 07684 } 07685 07692 function getHeaders(){ 07693 return $this->responseHeaders; 07694 } 07695 07702 function getHeader(){ 07703 return $this->responseHeader; 07704 } 07705 07715 function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { 07716 $this->proxyhost = $proxyhost; 07717 $this->proxyport = $proxyport; 07718 $this->proxyusername = $proxyusername; 07719 $this->proxypassword = $proxypassword; 07720 } 07721 07731 function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { 07732 $this->debug("setCredentials username=$username authtype=$authtype certRequest="); 07733 $this->appendDebug($this->varDump($certRequest)); 07734 $this->username = $username; 07735 $this->password = $password; 07736 $this->authtype = $authtype; 07737 $this->certRequest = $certRequest; 07738 } 07739 07746 function setHTTPEncoding($enc='gzip, deflate'){ 07747 $this->debug("setHTTPEncoding(\"$enc\")"); 07748 $this->http_encoding = $enc; 07749 } 07750 07757 function setUseCURL($use) { 07758 $this->debug("setUseCURL($use)"); 07759 $this->use_curl = $use; 07760 } 07761 07767 function useHTTPPersistentConnection(){ 07768 $this->debug("useHTTPPersistentConnection"); 07769 $this->persistentConnection = true; 07770 } 07771 07783 function getDefaultRpcParams() { 07784 return $this->defaultRpcParams; 07785 } 07786 07798 function setDefaultRpcParams($rpcParams) { 07799 $this->defaultRpcParams = $rpcParams; 07800 } 07801 07809 function getProxy() { 07810 $r = rand(); 07811 $evalStr = $this->_getProxyClassCode($r); 07812 //$this->debug("proxy class: $evalStr"); 07813 if ($this->getError()) { 07814 $this->debug("Error from _getProxyClassCode, so return NULL"); 07815 return null; 07816 } 07817 // eval the class 07818 eval($evalStr); 07819 // instantiate proxy object 07820 eval("\$proxy = new nusoap_proxy_$r('');"); 07821 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice 07822 $proxy->endpointType = 'wsdl'; 07823 $proxy->wsdlFile = $this->wsdlFile; 07824 $proxy->wsdl = $this->wsdl; 07825 $proxy->operations = $this->operations; 07826 $proxy->defaultRpcParams = $this->defaultRpcParams; 07827 // transfer other state 07828 $proxy->soap_defencoding = $this->soap_defencoding; 07829 $proxy->username = $this->username; 07830 $proxy->password = $this->password; 07831 $proxy->authtype = $this->authtype; 07832 $proxy->certRequest = $this->certRequest; 07833 $proxy->requestHeaders = $this->requestHeaders; 07834 $proxy->endpoint = $this->endpoint; 07835 $proxy->forceEndpoint = $this->forceEndpoint; 07836 $proxy->proxyhost = $this->proxyhost; 07837 $proxy->proxyport = $this->proxyport; 07838 $proxy->proxyusername = $this->proxyusername; 07839 $proxy->proxypassword = $this->proxypassword; 07840 $proxy->http_encoding = $this->http_encoding; 07841 $proxy->timeout = $this->timeout; 07842 $proxy->response_timeout = $this->response_timeout; 07843 $proxy->persistentConnection = &$this->persistentConnection; 07844 $proxy->decode_utf8 = $this->decode_utf8; 07845 $proxy->curl_options = $this->curl_options; 07846 $proxy->bindingType = $this->bindingType; 07847 $proxy->use_curl = $this->use_curl; 07848 return $proxy; 07849 } 07850 07857 function _getProxyClassCode($r) { 07858 $this->debug("in getProxy endpointType=$this->endpointType"); 07859 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); 07860 if ($this->endpointType != 'wsdl') { 07861 $evalStr = 'A proxy can only be created for a WSDL client'; 07862 $this->setError($evalStr); 07863 $evalStr = "echo \"$evalStr\";"; 07864 return $evalStr; 07865 } 07866 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { 07867 $this->loadWSDL(); 07868 if ($this->getError()) { 07869 return "echo \"" . $this->getError() . "\";"; 07870 } 07871 } 07872 $evalStr = ''; 07873 foreach ($this->operations as $operation => $opData) { 07874 if ($operation != '') { 07875 // create param string and param comment string 07876 if (sizeof($opData['input']['parts']) > 0) { 07877 $paramStr = ''; 07878 $paramArrayStr = ''; 07879 $paramCommentStr = ''; 07880 foreach ($opData['input']['parts'] as $name => $type) { 07881 $paramStr .= "\$$name, "; 07882 $paramArrayStr .= "'$name' => \$$name, "; 07883 $paramCommentStr .= "$type \$$name, "; 07884 } 07885 $paramStr = substr($paramStr, 0, strlen($paramStr)-2); 07886 $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); 07887 $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); 07888 } else { 07889 $paramStr = ''; 07890 $paramArrayStr = ''; 07891 $paramCommentStr = 'void'; 07892 } 07893 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; 07894 $evalStr .= "// $paramCommentStr 07895 function " . str_replace('.', '__', $operation) . "($paramStr) { 07896 \$params = array($paramArrayStr); 07897 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); 07898 } 07899 "; 07900 unset($paramStr); 07901 unset($paramCommentStr); 07902 } 07903 } 07904 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { 07905 '.$evalStr.' 07906 }'; 07907 return $evalStr; 07908 } 07909 07916 function getProxyClassCode() { 07917 $r = rand(); 07918 return $this->_getProxyClassCode($r); 07919 } 07920 07928 function getHTTPBody($soapmsg) { 07929 return $soapmsg; 07930 } 07931 07940 function getHTTPContentType() { 07941 return 'text/xml'; 07942 } 07943 07953 function getHTTPContentTypeCharset() { 07954 return $this->soap_defencoding; 07955 } 07956 07957 /* 07958 * whether or not parser should decode utf8 element content 07959 * 07960 * @return always returns true 07961 * @access public 07962 */ 07963 function decodeUTF8($bool){ 07964 $this->decode_utf8 = $bool; 07965 return true; 07966 } 07967 07976 function setCookie($name, $value) { 07977 if (strlen($name) == 0) { 07978 return false; 07979 } 07980 $this->cookies[] = array('name' => $name, 'value' => $value); 07981 return true; 07982 } 07983 07990 function getCookies() { 07991 return $this->cookies; 07992 } 07993 08000 function checkCookies() { 08001 if (sizeof($this->cookies) == 0) { 08002 return true; 08003 } 08004 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); 08005 $curr_cookies = $this->cookies; 08006 $this->cookies = array(); 08007 foreach ($curr_cookies as $cookie) { 08008 if (! is_array($cookie)) { 08009 $this->debug('Remove cookie that is not an array'); 08010 continue; 08011 } 08012 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { 08013 if (strtotime($cookie['expires']) > time()) { 08014 $this->cookies[] = $cookie; 08015 } else { 08016 $this->debug('Remove expired cookie ' . $cookie['name']); 08017 } 08018 } else { 08019 $this->cookies[] = $cookie; 08020 } 08021 } 08022 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); 08023 return true; 08024 } 08025 08033 function UpdateCookies($cookies) { 08034 if (sizeof($this->cookies) == 0) { 08035 // no existing cookies: take whatever is new 08036 if (sizeof($cookies) > 0) { 08037 $this->debug('Setting new cookie(s)'); 08038 $this->cookies = $cookies; 08039 } 08040 return true; 08041 } 08042 if (sizeof($cookies) == 0) { 08043 // no new cookies: keep what we've got 08044 return true; 08045 } 08046 // merge 08047 foreach ($cookies as $newCookie) { 08048 if (!is_array($newCookie)) { 08049 continue; 08050 } 08051 if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { 08052 continue; 08053 } 08054 $newName = $newCookie['name']; 08055 08056 $found = false; 08057 for ($i = 0; $i < count($this->cookies); $i++) { 08058 $cookie = $this->cookies[$i]; 08059 if (!is_array($cookie)) { 08060 continue; 08061 } 08062 if (!isset($cookie['name'])) { 08063 continue; 08064 } 08065 if ($newName != $cookie['name']) { 08066 continue; 08067 } 08068 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; 08069 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; 08070 if ($newDomain != $domain) { 08071 continue; 08072 } 08073 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; 08074 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; 08075 if ($newPath != $path) { 08076 continue; 08077 } 08078 $this->cookies[$i] = $newCookie; 08079 $found = true; 08080 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); 08081 break; 08082 } 08083 if (! $found) { 08084 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); 08085 $this->cookies[] = $newCookie; 08086 } 08087 } 08088 return true; 08089 } 08090 } 08091 08092 if (!extension_loaded('soap')) { 08096 class soapclient extends nusoap_client { 08097 } 08098 } 08099 ?>
Copyright © 2003 - 2009 MyOOS [Shopsystem]. All rights reserved. MyOOS [Shopsystem] is Free Software released under the GNU/GPL License. Webmaster: info@r23.de (Impressum) |
|