[svn r15948] Test inclusion for web services development - will be used as one possible method (SOAP)
parent
6fdd3d13bd
commit
ec55ca2782
@ -0,0 +1,90 @@ |
||||
<?php |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* Contains information for a SOAP fault. |
||||
* Mainly used for returning faults from deployed functions |
||||
* in a server instance. |
||||
* @author Dietrich Ayala <dietrich@ganx4.com> |
||||
* @version $Id: class.soap_fault.php,v 1.14 2007/04/11 15:49:47 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_fault extends nusoap_base { |
||||
/** |
||||
* The fault code (client|server) |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $faultcode; |
||||
/** |
||||
* The fault actor |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $faultactor; |
||||
/** |
||||
* The fault string, a description of the fault |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $faultstring; |
||||
/** |
||||
* The fault detail, typically a string or array of string |
||||
* @var mixed |
||||
* @access private |
||||
*/ |
||||
var $faultdetail; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) |
||||
* @param string $faultactor only used when msg routed between multiple actors |
||||
* @param string $faultstring human readable error message |
||||
* @param mixed $faultdetail detail, typically a string or array of string |
||||
*/ |
||||
function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ |
||||
parent::nusoap_base(); |
||||
$this->faultcode = $faultcode; |
||||
$this->faultactor = $faultactor; |
||||
$this->faultstring = $faultstring; |
||||
$this->faultdetail = $faultdetail; |
||||
} |
||||
|
||||
/** |
||||
* serialize a fault |
||||
* |
||||
* @return string The serialization of the fault instance. |
||||
* @access public |
||||
*/ |
||||
function serialize(){ |
||||
$ns_string = ''; |
||||
foreach($this->namespaces as $k => $v){ |
||||
$ns_string .= "\n xmlns:$k=\"$v\""; |
||||
} |
||||
$return_msg = |
||||
'<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
|
||||
'<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n". |
||||
'<SOAP-ENV:Body>'. |
||||
'<SOAP-ENV:Fault>'. |
||||
$this->serialize_val($this->faultcode, 'faultcode'). |
||||
$this->serialize_val($this->faultactor, 'faultactor'). |
||||
$this->serialize_val($this->faultstring, 'faultstring'). |
||||
$this->serialize_val($this->faultdetail, 'detail'). |
||||
'</SOAP-ENV:Fault>'. |
||||
'</SOAP-ENV:Body>'. |
||||
'</SOAP-ENV:Envelope>'; |
||||
return $return_msg; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Backward compatibility |
||||
*/ |
||||
class soap_fault extends nusoap_fault { |
||||
} |
||||
|
||||
|
||||
?> |
@ -0,0 +1,639 @@ |
||||
<?php |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* |
||||
* nusoap_parser class parses SOAP XML messages into native PHP values |
||||
* |
||||
* @author Dietrich Ayala <dietrich@ganx4.com> |
||||
* @author Scott Nichol <snichol@users.sourceforge.net> |
||||
* @version $Id: class.soap_parser.php,v 1.40 2007/04/17 16:34:03 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_parser extends nusoap_base { |
||||
|
||||
var $xml = ''; |
||||
var $xml_encoding = ''; |
||||
var $method = ''; |
||||
var $root_struct = ''; |
||||
var $root_struct_name = ''; |
||||
var $root_struct_namespace = ''; |
||||
var $root_header = ''; |
||||
var $document = ''; // incoming SOAP body (text) |
||||
// determines where in the message we are (envelope,header,body,method) |
||||
var $status = ''; |
||||
var $position = 0; |
||||
var $depth = 0; |
||||
var $default_namespace = ''; |
||||
var $namespaces = array(); |
||||
var $message = array(); |
||||
var $parent = ''; |
||||
var $fault = false; |
||||
var $fault_code = ''; |
||||
var $fault_str = ''; |
||||
var $fault_detail = ''; |
||||
var $depth_array = array(); |
||||
var $debug_flag = true; |
||||
var $soapresponse = NULL; // parsed SOAP Body |
||||
var $soapheader = NULL; // parsed SOAP Header |
||||
var $responseHeaders = ''; // incoming SOAP headers (text) |
||||
var $body_position = 0; |
||||
// for multiref parsing: |
||||
// array of id => pos |
||||
var $ids = array(); |
||||
// array of id => hrefs => pos |
||||
var $multirefs = array(); |
||||
// toggle for auto-decoding element content |
||||
var $decode_utf8 = true; |
||||
|
||||
/** |
||||
* constructor that actually does the parsing |
||||
* |
||||
* @param string $xml SOAP message |
||||
* @param string $encoding character encoding scheme of message |
||||
* @param string $method method for which XML is parsed (unused?) |
||||
* @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 |
||||
* @access public |
||||
*/ |
||||
function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ |
||||
parent::nusoap_base(); |
||||
$this->xml = $xml; |
||||
$this->xml_encoding = $encoding; |
||||
$this->method = $method; |
||||
$this->decode_utf8 = $decode_utf8; |
||||
|
||||
// Check whether content has been read. |
||||
if(!empty($xml)){ |
||||
// Check XML encoding |
||||
$pos_xml = strpos($xml, '<?xml'); |
||||
if ($pos_xml !== FALSE) { |
||||
$xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1); |
||||
if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { |
||||
$xml_encoding = $res[1]; |
||||
if (strtoupper($xml_encoding) != $encoding) { |
||||
$err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; |
||||
$this->debug($err); |
||||
if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { |
||||
$this->setError($err); |
||||
return; |
||||
} |
||||
// when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed |
||||
} else { |
||||
$this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); |
||||
} |
||||
} else { |
||||
$this->debug('No encoding specified in XML declaration'); |
||||
} |
||||
} else { |
||||
$this->debug('No XML declaration'); |
||||
} |
||||
$this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); |
||||
// Create an XML parser - why not xml_parser_create_ns? |
||||
$this->parser = xml_parser_create($this->xml_encoding); |
||||
// Set the options for parsing the XML data. |
||||
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); |
||||
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
||||
xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); |
||||
// Set the object for the parser. |
||||
xml_set_object($this->parser, $this); |
||||
// Set the element handlers for the parser. |
||||
xml_set_element_handler($this->parser, 'start_element','end_element'); |
||||
xml_set_character_data_handler($this->parser,'character_data'); |
||||
|
||||
// Parse the XML file. |
||||
if(!xml_parse($this->parser,$xml,true)){ |
||||
// Display an error message. |
||||
$err = sprintf('XML error parsing SOAP payload on line %d: %s', |
||||
xml_get_current_line_number($this->parser), |
||||
xml_error_string(xml_get_error_code($this->parser))); |
||||
$this->debug($err); |
||||
$this->debug("XML payload:\n" . $xml); |
||||
$this->setError($err); |
||||
} else { |
||||
$this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); |
||||
// get final value |
||||
$this->soapresponse = $this->message[$this->root_struct]['result']; |
||||
// get header value |
||||
if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ |
||||
$this->soapheader = $this->message[$this->root_header]['result']; |
||||
} |
||||
// resolve hrefs/ids |
||||
if(sizeof($this->multirefs) > 0){ |
||||
foreach($this->multirefs as $id => $hrefs){ |
||||
$this->debug('resolving multirefs for id: '.$id); |
||||
$idVal = $this->buildVal($this->ids[$id]); |
||||
if (is_array($idVal) && isset($idVal['!id'])) { |
||||
unset($idVal['!id']); |
||||
} |
||||
foreach($hrefs as $refPos => $ref){ |
||||
$this->debug('resolving href at pos '.$refPos); |
||||
$this->multirefs[$id][$refPos] = $idVal; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
xml_parser_free($this->parser); |
||||
} else { |
||||
$this->debug('xml was empty, didn\'t parse!'); |
||||
$this->setError('xml was empty, didn\'t parse!'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* start-element handler |
||||
* |
||||
* @param resource $parser XML parser object |
||||
* @param string $name element name |
||||
* @param array $attrs associative array of attributes |
||||
* @access private |
||||
*/ |
||||
function start_element($parser, $name, $attrs) { |
||||
// position in a total number of elements, starting from 0 |
||||
// update class level pos |
||||
$pos = $this->position++; |
||||
// and set mine |
||||
$this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); |
||||
// depth = how many levels removed from root? |
||||
// set mine as current global depth and increment global depth value |
||||
$this->message[$pos]['depth'] = $this->depth++; |
||||
|
||||
// else add self as child to whoever the current parent is |
||||
if($pos != 0){ |
||||
$this->message[$this->parent]['children'] .= '|'.$pos; |
||||
} |
||||
// set my parent |
||||
$this->message[$pos]['parent'] = $this->parent; |
||||
// set self as current parent |
||||
$this->parent = $pos; |
||||
// set self as current value for this depth |
||||
$this->depth_array[$this->depth] = $pos; |
||||
// get element prefix |
||||
if(strpos($name,':')){ |
||||
// get ns prefix |
||||
$prefix = substr($name,0,strpos($name,':')); |
||||
// get unqualified name |
||||
$name = substr(strstr($name,':'),1); |
||||
} |
||||
// set status |
||||
if($name == 'Envelope'){ |
||||
$this->status = 'envelope'; |
||||
} elseif($name == 'Header' && $this->status = 'envelope'){ |
||||
$this->root_header = $pos; |
||||
$this->status = 'header'; |
||||
} elseif($name == 'Body' && $this->status = 'envelope'){ |
||||
$this->status = 'body'; |
||||
$this->body_position = $pos; |
||||
// set method |
||||
} elseif($this->status == 'body' && $pos == ($this->body_position+1)){ |
||||
$this->status = 'method'; |
||||
$this->root_struct_name = $name; |
||||
$this->root_struct = $pos; |
||||
$this->message[$pos]['type'] = 'struct'; |
||||
$this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); |
||||
} |
||||
// set my status |
||||
$this->message[$pos]['status'] = $this->status; |
||||
// set name |
||||
$this->message[$pos]['name'] = htmlspecialchars($name); |
||||
// set attrs |
||||
$this->message[$pos]['attrs'] = $attrs; |
||||
|
||||
// loop through atts, logging ns and type declarations |
||||
$attstr = ''; |
||||
foreach($attrs as $key => $value){ |
||||
$key_prefix = $this->getPrefix($key); |
||||
$key_localpart = $this->getLocalPart($key); |
||||
// if ns declarations, add to class level array of valid namespaces |
||||
if($key_prefix == 'xmlns'){ |
||||
if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ |
||||
$this->XMLSchemaVersion = $value; |
||||
$this->namespaces['xsd'] = $this->XMLSchemaVersion; |
||||
$this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; |
||||
} |
||||
$this->namespaces[$key_localpart] = $value; |
||||
// set method namespace |
||||
if($name == $this->root_struct_name){ |
||||
$this->methodNamespace = $value; |
||||
} |
||||
// if it's a type declaration, set type |
||||
} elseif($key_localpart == 'type'){ |
||||
if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { |
||||
// do nothing: already processed arrayType |
||||
} else { |
||||
$value_prefix = $this->getPrefix($value); |
||||
$value_localpart = $this->getLocalPart($value); |
||||
$this->message[$pos]['type'] = $value_localpart; |
||||
$this->message[$pos]['typePrefix'] = $value_prefix; |
||||
if(isset($this->namespaces[$value_prefix])){ |
||||
$this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; |
||||
} else if(isset($attrs['xmlns:'.$value_prefix])) { |
||||
$this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; |
||||
} |
||||
// should do something here with the namespace of specified type? |
||||
} |
||||
} elseif($key_localpart == 'arrayType'){ |
||||
$this->message[$pos]['type'] = 'array'; |
||||
/* do arrayType ereg here |
||||
[1] arrayTypeValue ::= atype asize |
||||
[2] atype ::= QName rank* |
||||
[3] rank ::= '[' (',')* ']' |
||||
[4] asize ::= '[' length~ ']' |
||||
[5] length ::= nextDimension* Digit+ |
||||
[6] nextDimension ::= Digit+ ',' |
||||
*/ |
||||
$expr = '([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]'; |
||||
if(ereg($expr,$value,$regs)){ |
||||
$this->message[$pos]['typePrefix'] = $regs[1]; |
||||
$this->message[$pos]['arrayTypePrefix'] = $regs[1]; |
||||
if (isset($this->namespaces[$regs[1]])) { |
||||
$this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; |
||||
} else if (isset($attrs['xmlns:'.$regs[1]])) { |
||||
$this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; |
||||
} |
||||
$this->message[$pos]['arrayType'] = $regs[2]; |
||||
$this->message[$pos]['arraySize'] = $regs[3]; |
||||
$this->message[$pos]['arrayCols'] = $regs[4]; |
||||
} |
||||
// specifies nil value (or not) |
||||
} elseif ($key_localpart == 'nil'){ |
||||
$this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); |
||||
// some other attribute |
||||
} elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { |
||||
$this->message[$pos]['xattrs']['!' . $key] = $value; |
||||
} |
||||
|
||||
if ($key == 'xmlns') { |
||||
$this->default_namespace = $value; |
||||
} |
||||
// log id |
||||
if($key == 'id'){ |
||||
$this->ids[$value] = $pos; |
||||
} |
||||
// root |
||||
if($key_localpart == 'root' && $value == 1){ |
||||
$this->status = 'method'; |
||||
$this->root_struct_name = $name; |
||||
$this->root_struct = $pos; |
||||
$this->debug("found root struct $this->root_struct_name, pos $pos"); |
||||
} |
||||
// for doclit |
||||
$attstr .= " $key=\"$value\""; |
||||
} |
||||
// get namespace - must be done after namespace atts are processed |
||||
if(isset($prefix)){ |
||||
$this->message[$pos]['namespace'] = $this->namespaces[$prefix]; |
||||
$this->default_namespace = $this->namespaces[$prefix]; |
||||
} else { |
||||
$this->message[$pos]['namespace'] = $this->default_namespace; |
||||
} |
||||
if($this->status == 'header'){ |
||||
if ($this->root_header != $pos) { |
||||
$this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; |
||||
} |
||||
} elseif($this->root_struct_name != ''){ |
||||
$this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* end-element handler |
||||
* |
||||
* @param resource $parser XML parser object |
||||
* @param string $name element name |
||||
* @access private |
||||
*/ |
||||
function end_element($parser, $name) { |
||||
// position of current element is equal to the last value left in depth_array for my depth |
||||
$pos = $this->depth_array[$this->depth--]; |
||||
|
||||
// get element prefix |
||||
if(strpos($name,':')){ |
||||
// get ns prefix |
||||
$prefix = substr($name,0,strpos($name,':')); |
||||
// get unqualified name |
||||
$name = substr(strstr($name,':'),1); |
||||
} |
||||
|
||||
// build to native type |
||||
if(isset($this->body_position) && $pos > $this->body_position){ |
||||
// deal w/ multirefs |
||||
if(isset($this->message[$pos]['attrs']['href'])){ |
||||
// get id |
||||
$id = substr($this->message[$pos]['attrs']['href'],1); |
||||
// add placeholder to href array |
||||
$this->multirefs[$id][$pos] = 'placeholder'; |
||||
// add set a reference to it as the result value |
||||
$this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; |
||||
// build complexType values |
||||
} elseif($this->message[$pos]['children'] != ''){ |
||||
// if result has already been generated (struct/array) |
||||
if(!isset($this->message[$pos]['result'])){ |
||||
$this->message[$pos]['result'] = $this->buildVal($pos); |
||||
} |
||||
// build complexType values of attributes and possibly simpleContent |
||||
} elseif (isset($this->message[$pos]['xattrs'])) { |
||||
if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { |
||||
$this->message[$pos]['xattrs']['!'] = null; |
||||
} elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { |
||||
if (isset($this->message[$pos]['type'])) { |
||||
$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'] : ''); |
||||
} else { |
||||
$parent = $this->message[$pos]['parent']; |
||||
if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { |
||||
$this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); |
||||
} else { |
||||
$this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; |
||||
} |
||||
} |
||||
} |
||||
$this->message[$pos]['result'] = $this->message[$pos]['xattrs']; |
||||
// set value of simpleType (or nil complexType) |
||||
} else { |
||||
//$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); |
||||
if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { |
||||
$this->message[$pos]['xattrs']['!'] = null; |
||||
} elseif (isset($this->message[$pos]['type'])) { |
||||
$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'] : ''); |
||||
} else { |
||||
$parent = $this->message[$pos]['parent']; |
||||
if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { |
||||
$this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); |
||||
} else { |
||||
$this->message[$pos]['result'] = $this->message[$pos]['cdata']; |
||||
} |
||||
} |
||||
|
||||
/* add value to parent's result, if parent is struct/array |
||||
$parent = $this->message[$pos]['parent']; |
||||
if($this->message[$parent]['type'] != 'map'){ |
||||
if(strtolower($this->message[$parent]['type']) == 'array'){ |
||||
$this->message[$parent]['result'][] = $this->message[$pos]['result']; |
||||
} else { |
||||
$this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; |
||||
} |
||||
} |
||||
*/ |
||||
} |
||||
} |
||||
|
||||
// for doclit |
||||
if($this->status == 'header'){ |
||||
if ($this->root_header != $pos) { |
||||
$this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; |
||||
} |
||||
} elseif($pos >= $this->root_struct){ |
||||
$this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>"; |
||||
} |
||||
// switch status |
||||
if($pos == $this->root_struct){ |
||||
$this->status = 'body'; |
||||
$this->root_struct_namespace = $this->message[$pos]['namespace']; |
||||
} elseif($name == 'Body'){ |
||||
$this->status = 'envelope'; |
||||
} elseif($name == 'Header'){ |
||||
$this->status = 'envelope'; |
||||
} elseif($name == 'Envelope'){ |
||||
// |
||||
} |
||||
// set parent back to my parent |
||||
$this->parent = $this->message[$pos]['parent']; |
||||
} |
||||
|
||||
/** |
||||
* element content handler |
||||
* |
||||
* @param resource $parser XML parser object |
||||
* @param string $data element content |
||||
* @access private |
||||
*/ |
||||
function character_data($parser, $data){ |
||||
$pos = $this->depth_array[$this->depth]; |
||||
if ($this->xml_encoding=='UTF-8'){ |
||||
// TODO: add an option to disable this for folks who want |
||||
// raw UTF-8 that, e.g., might not map to iso-8859-1 |
||||
// TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); |
||||
if($this->decode_utf8){ |
||||
$data = utf8_decode($data); |
||||
} |
||||
} |
||||
$this->message[$pos]['cdata'] .= $data; |
||||
// for doclit |
||||
if($this->status == 'header'){ |
||||
$this->responseHeaders .= $data; |
||||
} else { |
||||
$this->document .= $data; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* get the parsed message (SOAP Body) |
||||
* |
||||
* @return mixed |
||||
* @access public |
||||
* @deprecated use get_soapbody instead |
||||
*/ |
||||
function get_response(){ |
||||
return $this->soapresponse; |
||||
} |
||||
|
||||
/** |
||||
* get the parsed SOAP Body (NULL if there was none) |
||||
* |
||||
* @return mixed |
||||
* @access public |
||||
*/ |
||||
function get_soapbody(){ |
||||
return $this->soapresponse; |
||||
} |
||||
|
||||
/** |
||||
* get the parsed SOAP Header (NULL if there was none) |
||||
* |
||||
* @return mixed |
||||
* @access public |
||||
*/ |
||||
function get_soapheader(){ |
||||
return $this->soapheader; |
||||
} |
||||
|
||||
/** |
||||
* get the unparsed SOAP Header |
||||
* |
||||
* @return string XML or empty if no Header |
||||
* @access public |
||||
*/ |
||||
function getHeaders(){ |
||||
return $this->responseHeaders; |
||||
} |
||||
|
||||
/** |
||||
* decodes simple types into PHP variables |
||||
* |
||||
* @param string $value value to decode |
||||
* @param string $type XML type to decode |
||||
* @param string $typens XML type namespace to decode |
||||
* @return mixed PHP value |
||||
* @access private |
||||
*/ |
||||
function decodeSimple($value, $type, $typens) { |
||||
// TODO: use the namespace! |
||||
if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { |
||||
return (string) $value; |
||||
} |
||||
if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { |
||||
return (int) $value; |
||||
} |
||||
if ($type == 'float' || $type == 'double' || $type == 'decimal') { |
||||
return (double) $value; |
||||
} |
||||
if ($type == 'boolean') { |
||||
if (strtolower($value) == 'false' || strtolower($value) == 'f') { |
||||
return false; |
||||
} |
||||
return (boolean) $value; |
||||
} |
||||
if ($type == 'base64' || $type == 'base64Binary') { |
||||
$this->debug('Decode base64 value'); |
||||
return base64_decode($value); |
||||
} |
||||
// obscure numeric types |
||||
if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' |
||||
|| $type == 'nonNegativeInteger' || $type == 'positiveInteger' |
||||
|| $type == 'unsignedInt' |
||||
|| $type == 'unsignedShort' || $type == 'unsignedByte') { |
||||
return (int) $value; |
||||
} |
||||
// bogus: parser treats array with no elements as a simple type |
||||
if ($type == 'array') { |
||||
return array(); |
||||
} |
||||
// everything else |
||||
return (string) $value; |
||||
} |
||||
|
||||
/** |
||||
* builds response structures for compound values (arrays/structs) |
||||
* and scalars |
||||
* |
||||
* @param integer $pos position in node tree |
||||
* @return mixed PHP value |
||||
* @access private |
||||
*/ |
||||
function buildVal($pos){ |
||||
if(!isset($this->message[$pos]['type'])){ |
||||
$this->message[$pos]['type'] = ''; |
||||
} |
||||
$this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); |
||||
// if there are children... |
||||
if($this->message[$pos]['children'] != ''){ |
||||
$this->debug('in buildVal, there are children'); |
||||
$children = explode('|',$this->message[$pos]['children']); |
||||
array_shift($children); // knock off empty |
||||
// md array |
||||
if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ |
||||
$r=0; // rowcount |
||||
$c=0; // colcount |
||||
foreach($children as $child_pos){ |
||||
$this->debug("in buildVal, got an MD array element: $r, $c"); |
||||
$params[$r][] = $this->message[$child_pos]['result']; |
||||
$c++; |
||||
if($c == $this->message[$pos]['arrayCols']){ |
||||
$c = 0; |
||||
$r++; |
||||
} |
||||
} |
||||
// array |
||||
} elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ |
||||
$this->debug('in buildVal, adding array '.$this->message[$pos]['name']); |
||||
foreach($children as $child_pos){ |
||||
$params[] = &$this->message[$child_pos]['result']; |
||||
} |
||||
// apache Map type: java hashtable |
||||
} elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ |
||||
$this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); |
||||
foreach($children as $child_pos){ |
||||
$kv = explode("|",$this->message[$child_pos]['children']); |
||||
$params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; |
||||
} |
||||
// generic compound type |
||||
//} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { |
||||
} else { |
||||
// Apache Vector type: treat as an array |
||||
$this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); |
||||
if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { |
||||
$notstruct = 1; |
||||
} else { |
||||
$notstruct = 0; |
||||
} |
||||
// |
||||
foreach($children as $child_pos){ |
||||
if($notstruct){ |
||||
$params[] = &$this->message[$child_pos]['result']; |
||||
} else { |
||||
if (isset($params[$this->message[$child_pos]['name']])) { |
||||
// de-serialize repeated element name into an array |
||||
if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { |
||||
$params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); |
||||
} |
||||
$params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; |
||||
} else { |
||||
$params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (isset($this->message[$pos]['xattrs'])) { |
||||
$this->debug('in buildVal, handling attributes'); |
||||
foreach ($this->message[$pos]['xattrs'] as $n => $v) { |
||||
$params[$n] = $v; |
||||
} |
||||
} |
||||
// handle simpleContent |
||||
if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { |
||||
$this->debug('in buildVal, handling simpleContent'); |
||||
if (isset($this->message[$pos]['type'])) { |
||||
$params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); |
||||
} else { |
||||
$parent = $this->message[$pos]['parent']; |
||||
if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { |
||||
$params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); |
||||
} else { |
||||
$params['!'] = $this->message[$pos]['cdata']; |
||||
} |
||||
} |
||||
} |
||||
$ret = is_array($params) ? $params : array(); |
||||
$this->debug('in buildVal, return:'); |
||||
$this->appendDebug($this->varDump($ret)); |
||||
return $ret; |
||||
} else { |
||||
$this->debug('in buildVal, no children, building scalar'); |
||||
$cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; |
||||
if (isset($this->message[$pos]['type'])) { |
||||
$ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); |
||||
$this->debug("in buildVal, return: $ret"); |
||||
return $ret; |
||||
} |
||||
$parent = $this->message[$pos]['parent']; |
||||
if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { |
||||
$ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); |
||||
$this->debug("in buildVal, return: $ret"); |
||||
return $ret; |
||||
} |
||||
$ret = $this->message[$pos]['cdata']; |
||||
$this->debug("in buildVal, return: $ret"); |
||||
return $ret; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Backward compatibility |
||||
*/ |
||||
class soap_parser extends nusoap_parser { |
||||
} |
||||
|
||||
|
||||
?> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,107 @@ |
||||
<?php |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* For creating serializable abstractions of native PHP types. This class |
||||
* allows element name/namespace, XSD type, and XML attributes to be |
||||
* associated with a value. This is extremely useful when WSDL is not |
||||
* used, but is also useful when WSDL is used with polymorphic types, including |
||||
* xsd:anyType and user-defined types. |
||||
* |
||||
* @author Dietrich Ayala <dietrich@ganx4.com> |
||||
* @version $Id: class.soap_val.php,v 1.11 2007/04/06 13:56:32 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class soapval extends nusoap_base { |
||||
/** |
||||
* The XML element name |
||||
* |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $name; |
||||
/** |
||||
* The XML type name (string or false) |
||||
* |
||||
* @var mixed |
||||
* @access private |
||||
*/ |
||||
var $type; |
||||
/** |
||||
* The PHP value |
||||
* |
||||
* @var mixed |
||||
* @access private |
||||
*/ |
||||
var $value; |
||||
/** |
||||
* The XML element namespace (string or false) |
||||
* |
||||
* @var mixed |
||||
* @access private |
||||
*/ |
||||
var $element_ns; |
||||
/** |
||||
* The XML type namespace (string or false) |
||||
* |
||||
* @var mixed |
||||
* @access private |
||||
*/ |
||||
var $type_ns; |
||||
/** |
||||
* The XML element attributes (array or false) |
||||
* |
||||
* @var mixed |
||||
* @access private |
||||
*/ |
||||
var $attributes; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param string $name optional name |
||||
* @param mixed $type optional type name |
||||
* @param mixed $value optional value |
||||
* @param mixed $element_ns optional namespace of value |
||||
* @param mixed $type_ns optional namespace of type |
||||
* @param mixed $attributes associative array of attributes to add to element serialization |
||||
* @access public |
||||
*/ |
||||
function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { |
||||
parent::nusoap_base(); |
||||
$this->name = $name; |
||||
$this->type = $type; |
||||
$this->value = $value; |
||||
$this->element_ns = $element_ns; |
||||
$this->type_ns = $type_ns; |
||||
$this->attributes = $attributes; |
||||
} |
||||
|
||||
/** |
||||
* return serialized value |
||||
* |
||||
* @param string $use The WSDL use value (encoded|literal) |
||||
* @return string XML data |
||||
* @access public |
||||
*/ |
||||
function serialize($use='encoded') { |
||||
return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); |
||||
} |
||||
|
||||
/** |
||||
* decodes a soapval object into a PHP native type |
||||
* |
||||
* @return mixed |
||||
* @access public |
||||
*/ |
||||
function decode(){ |
||||
return $this->value; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
?> |
@ -0,0 +1,977 @@ |
||||
<?php |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* |
||||
* [nu]soapclient higher level class for easy usage. |
||||
* |
||||
* usage: |
||||
* |
||||
* // instantiate client with server info |
||||
* $soapclient = new nusoap_client( string path [ ,mixed wsdl] ); |
||||
* |
||||
* // call method, get results |
||||
* echo $soapclient->call( string methodname [ ,array parameters] ); |
||||
* |
||||
* // bye bye client |
||||
* unset($soapclient); |
||||
* |
||||
* @author Dietrich Ayala <dietrich@ganx4.com> |
||||
* @author Scott Nichol <snichol@users.sourceforge.net> |
||||
* @version $Id: class.soapclient.php,v 1.64 2007/10/22 01:15:17 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_client extends nusoap_base { |
||||
|
||||
var $username = ''; // Username for HTTP authentication |
||||
var $password = ''; // Password for HTTP authentication |
||||
var $authtype = ''; // Type of HTTP authentication |
||||
var $certRequest = array(); // Certificate for HTTP SSL authentication |
||||
var $requestHeaders = false; // SOAP headers in request (text) |
||||
var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) |
||||
var $responseHeader = NULL; // SOAP Header from response (parsed) |
||||
var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) |
||||
var $endpoint; |
||||
var $forceEndpoint = ''; // overrides WSDL endpoint |
||||
var $proxyhost = ''; |
||||
var $proxyport = ''; |
||||
var $proxyusername = ''; |
||||
var $proxypassword = ''; |
||||
var $xml_encoding = ''; // character set encoding of incoming (response) messages |
||||
var $http_encoding = false; |
||||
var $timeout = 0; // HTTP connection timeout |
||||
var $response_timeout = 30; // HTTP response timeout |
||||
var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error |
||||
var $persistentConnection = false; |
||||
var $defaultRpcParams = false; // This is no longer used |
||||
var $request = ''; // HTTP request |
||||
var $response = ''; // HTTP response |
||||
var $responseData = ''; // SOAP payload of response |
||||
var $cookies = array(); // Cookies from response or for request |
||||
var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() |
||||
var $operations = array(); // WSDL operations, empty for WSDL initialization error |
||||
var $curl_options = array(); // User-specified cURL options |
||||
var $bindingType = ''; // WSDL operation binding type |
||||
var $use_curl = false; // whether to always try to use cURL |
||||
|
||||
/* |
||||
* fault related variables |
||||
*/ |
||||
/** |
||||
* @var fault |
||||
* @access public |
||||
*/ |
||||
var $fault; |
||||
/** |
||||
* @var faultcode |
||||
* @access public |
||||
*/ |
||||
var $faultcode; |
||||
/** |
||||
* @var faultstring |
||||
* @access public |
||||
*/ |
||||
var $faultstring; |
||||
/** |
||||
* @var faultdetail |
||||
* @access public |
||||
*/ |
||||
var $faultdetail; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) |
||||
* @param bool $wsdl optional, set to true if using WSDL |
||||
* @param int $portName optional portName in WSDL document |
||||
* @param string $proxyhost |
||||
* @param string $proxyport |
||||
* @param string $proxyusername |
||||
* @param string $proxypassword |
||||
* @param integer $timeout set the connection timeout |
||||
* @param integer $response_timeout set the response timeout |
||||
* @access public |
||||
*/ |
||||
function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30){ |
||||
parent::nusoap_base(); |
||||
$this->endpoint = $endpoint; |
||||
$this->proxyhost = $proxyhost; |
||||
$this->proxyport = $proxyport; |
||||
$this->proxyusername = $proxyusername; |
||||
$this->proxypassword = $proxypassword; |
||||
$this->timeout = $timeout; |
||||
$this->response_timeout = $response_timeout; |
||||
|
||||
$this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); |
||||
$this->appendDebug('endpoint=' . $this->varDump($endpoint)); |
||||
|
||||
// make values |
||||
if($wsdl){ |
||||
if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { |
||||
$this->wsdl = $endpoint; |
||||
$this->endpoint = $this->wsdl->wsdl; |
||||
$this->wsdlFile = $this->endpoint; |
||||
$this->debug('existing wsdl instance created from ' . $this->endpoint); |
||||
$this->checkWSDL(); |
||||
} else { |
||||
$this->wsdlFile = $this->endpoint; |
||||
$this->wsdl = null; |
||||
$this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); |
||||
} |
||||
$this->endpointType = 'wsdl'; |
||||
} else { |
||||
$this->debug("instantiate SOAP with endpoint at $endpoint"); |
||||
$this->endpointType = 'soap'; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* calls method, returns PHP native type |
||||
* |
||||
* @param string $operation SOAP server URL or path |
||||
* @param mixed $params An array, associative or simple, of the parameters |
||||
* for the method call, or a string that is the XML |
||||
* for the call. For rpc style, this call will |
||||
* wrap the XML in a tag named after the method, as |
||||
* well as the SOAP Envelope and Body. For document |
||||
* style, this will only wrap with the Envelope and Body. |
||||
* IMPORTANT: when using an array with document style, |
||||
* in which case there |
||||
* is really one parameter, the root of the fragment |
||||
* used in the call, which encloses what programmers |
||||
* normally think of parameters. A parameter array |
||||
* *must* include the wrapper. |
||||
* @param string $namespace optional method namespace (WSDL can override) |
||||
* @param string $soapAction optional SOAPAction value (WSDL can override) |
||||
* @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array |
||||
* @param boolean $rpcParams optional (no longer used) |
||||
* @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) |
||||
* @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) |
||||
* @return mixed response from SOAP call |
||||
* @access public |
||||
*/ |
||||
function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ |
||||
$this->operation = $operation; |
||||
$this->fault = false; |
||||
$this->setError(''); |
||||
$this->request = ''; |
||||
$this->response = ''; |
||||
$this->responseData = ''; |
||||
$this->faultstring = ''; |
||||
$this->faultcode = ''; |
||||
$this->opData = array(); |
||||
|
||||
$this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); |
||||
$this->appendDebug('params=' . $this->varDump($params)); |
||||
$this->appendDebug('headers=' . $this->varDump($headers)); |
||||
if ($headers) { |
||||
$this->requestHeaders = $headers; |
||||
} |
||||
if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { |
||||
$this->loadWSDL(); |
||||
if ($this->getError()) |
||||
return false; |
||||
} |
||||
// serialize parameters |
||||
if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ |
||||
// use WSDL for operation |
||||
$this->opData = $opData; |
||||
$this->debug("found operation"); |
||||
$this->appendDebug('opData=' . $this->varDump($opData)); |
||||
if (isset($opData['soapAction'])) { |
||||
$soapAction = $opData['soapAction']; |
||||
} |
||||
if (! $this->forceEndpoint) { |
||||
$this->endpoint = $opData['endpoint']; |
||||
} else { |
||||
$this->endpoint = $this->forceEndpoint; |
||||
} |
||||
$namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; |
||||
$style = $opData['style']; |
||||
$use = $opData['input']['use']; |
||||
// add ns to ns array |
||||
if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ |
||||
$nsPrefix = 'ns' . rand(1000, 9999); |
||||
$this->wsdl->namespaces[$nsPrefix] = $namespace; |
||||
} |
||||
$nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); |
||||
// serialize payload |
||||
if (is_string($params)) { |
||||
$this->debug("serializing param string for WSDL operation $operation"); |
||||
$payload = $params; |
||||
} elseif (is_array($params)) { |
||||
$this->debug("serializing param array for WSDL operation $operation"); |
||||
$payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); |
||||
} else { |
||||
$this->debug('params must be array or string'); |
||||
$this->setError('params must be array or string'); |
||||
return false; |
||||
} |
||||
$usedNamespaces = $this->wsdl->usedNamespaces; |
||||
if (isset($opData['input']['encodingStyle'])) { |
||||
$encodingStyle = $opData['input']['encodingStyle']; |
||||
} else { |
||||
$encodingStyle = ''; |
||||
} |
||||
$this->appendDebug($this->wsdl->getDebug()); |
||||
$this->wsdl->clearDebug(); |
||||
if ($errstr = $this->wsdl->getError()) { |
||||
$this->debug('got wsdl error: '.$errstr); |
||||
$this->setError('wsdl error: '.$errstr); |
||||
return false; |
||||
} |
||||
} elseif($this->endpointType == 'wsdl') { |
||||
// operation not in WSDL |
||||
$this->appendDebug($this->wsdl->getDebug()); |
||||
$this->wsdl->clearDebug(); |
||||
$this->setError( 'operation '.$operation.' not present.'); |
||||
$this->debug("operation '$operation' not present."); |
||||
return false; |
||||
} else { |
||||
// no WSDL |
||||
//$this->namespaces['ns1'] = $namespace; |
||||
$nsPrefix = 'ns' . rand(1000, 9999); |
||||
// serialize |
||||
$payload = ''; |
||||
if (is_string($params)) { |
||||
$this->debug("serializing param string for operation $operation"); |
||||
$payload = $params; |
||||
} elseif (is_array($params)) { |
||||
$this->debug("serializing param array for operation $operation"); |
||||
foreach($params as $k => $v){ |
||||
$payload .= $this->serialize_val($v,$k,false,false,false,false,$use); |
||||
} |
||||
} else { |
||||
$this->debug('params must be array or string'); |
||||
$this->setError('params must be array or string'); |
||||
return false; |
||||
} |
||||
$usedNamespaces = array(); |
||||
if ($use == 'encoded') { |
||||
$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; |
||||
} else { |
||||
$encodingStyle = ''; |
||||
} |
||||
} |
||||
// wrap RPC calls with method element |
||||
if ($style == 'rpc') { |
||||
if ($use == 'literal') { |
||||
$this->debug("wrapping RPC request with literal method element"); |
||||
if ($namespace) { |
||||
// 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 |
||||
$payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . |
||||
$payload . |
||||
"</$nsPrefix:$operation>"; |
||||
} else { |
||||
$payload = "<$operation>" . $payload . "</$operation>"; |
||||
} |
||||
} else { |
||||
$this->debug("wrapping RPC request with encoded method element"); |
||||
if ($namespace) { |
||||
$payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . |
||||
$payload . |
||||
"</$nsPrefix:$operation>"; |
||||
} else { |
||||
$payload = "<$operation>" . |
||||
$payload . |
||||
"</$operation>"; |
||||
} |
||||
} |
||||
} |
||||
// serialize envelope |
||||
$soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); |
||||
$this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); |
||||
$this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); |
||||
// send |
||||
$return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); |
||||
if($errstr = $this->getError()){ |
||||
$this->debug('Error: '.$errstr); |
||||
return false; |
||||
} else { |
||||
$this->return = $return; |
||||
$this->debug('sent message successfully and got a(n) '.gettype($return)); |
||||
$this->appendDebug('return=' . $this->varDump($return)); |
||||
|
||||
// fault? |
||||
if(is_array($return) && isset($return['faultcode'])){ |
||||
$this->debug('got fault'); |
||||
$this->setError($return['faultcode'].': '.$return['faultstring']); |
||||
$this->fault = true; |
||||
foreach($return as $k => $v){ |
||||
$this->$k = $v; |
||||
$this->debug("$k = $v<br>"); |
||||
} |
||||
return $return; |
||||
} elseif ($style == 'document') { |
||||
// NOTE: if the response is defined to have multiple parts (i.e. unwrapped), |
||||
// we are only going to return the first part here...sorry about that |
||||
return $return; |
||||
} else { |
||||
// array of return values |
||||
if(is_array($return)){ |
||||
// multiple 'out' parameters, which we return wrapped up |
||||
// in the array |
||||
if(sizeof($return) > 1){ |
||||
return $return; |
||||
} |
||||
// single 'out' parameter (normally the return value) |
||||
$return = array_shift($return); |
||||
$this->debug('return shifted value: '); |
||||
$this->appendDebug($this->varDump($return)); |
||||
return $return; |
||||
// nothing returned (ie, echoVoid) |
||||
} else { |
||||
return ""; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* check WSDL passed as an instance or pulled from an endpoint |
||||
* |
||||
* @access private |
||||
*/ |
||||
function checkWSDL() { |
||||
$this->appendDebug($this->wsdl->getDebug()); |
||||
$this->wsdl->clearDebug(); |
||||
$this->debug('checkWSDL'); |
||||
// catch errors |
||||
if ($errstr = $this->wsdl->getError()) { |
||||
$this->debug('got wsdl error: '.$errstr); |
||||
$this->setError('wsdl error: '.$errstr); |
||||
} elseif ($this->operations = $this->wsdl->getOperations('soap')) { |
||||
$this->bindingType = 'soap'; |
||||
$this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); |
||||
} elseif ($this->operations = $this->wsdl->getOperations('soap12')) { |
||||
$this->bindingType = 'soap12'; |
||||
$this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); |
||||
$this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); |
||||
} else { |
||||
$this->debug('getOperations returned false'); |
||||
$this->setError('no operations defined in the WSDL document!'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* instantiate wsdl object and parse wsdl file |
||||
* |
||||
* @access public |
||||
*/ |
||||
function loadWSDL() { |
||||
$this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); |
||||
$this->wsdl =& new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); |
||||
$this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); |
||||
$this->wsdl->fetchWSDL($this->wsdlFile); |
||||
$this->checkWSDL(); |
||||
} |
||||
|
||||
/** |
||||
* get available data pertaining to an operation |
||||
* |
||||
* @param string $operation operation name |
||||
* @return array array of data pertaining to the operation |
||||
* @access public |
||||
*/ |
||||
function getOperationData($operation){ |
||||
if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { |
||||
$this->loadWSDL(); |
||||
if ($this->getError()) |
||||
return false; |
||||
} |
||||
if(isset($this->operations[$operation])){ |
||||
return $this->operations[$operation]; |
||||
} |
||||
$this->debug("No data for operation: $operation"); |
||||
} |
||||
|
||||
/** |
||||
* send the SOAP message |
||||
* |
||||
* Note: if the operation has multiple return values |
||||
* the return value of this method will be an array |
||||
* of those values. |
||||
* |
||||
* @param string $msg a SOAPx4 soapmsg object |
||||
* @param string $soapaction SOAPAction value |
||||
* @param integer $timeout set connection timeout in seconds |
||||
* @param integer $response_timeout set response timeout in seconds |
||||
* @return mixed native PHP types. |
||||
* @access private |
||||
*/ |
||||
function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { |
||||
$this->checkCookies(); |
||||
// detect transport |
||||
switch(true){ |
||||
// http(s) |
||||
case ereg('^http',$this->endpoint): |
||||
$this->debug('transporting via HTTP'); |
||||
if($this->persistentConnection == true && is_object($this->persistentConnection)){ |
||||
$http =& $this->persistentConnection; |
||||
} else { |
||||
$http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); |
||||
if ($this->persistentConnection) { |
||||
$http->usePersistentConnection(); |
||||
} |
||||
} |
||||
$http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); |
||||
$http->setSOAPAction($soapaction); |
||||
if($this->proxyhost && $this->proxyport){ |
||||
$http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); |
||||
} |
||||
if($this->authtype != '') { |
||||
$http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); |
||||
} |
||||
if($this->http_encoding != ''){ |
||||
$http->setEncoding($this->http_encoding); |
||||
} |
||||
$this->debug('sending message, length='.strlen($msg)); |
||||
if(ereg('^http:',$this->endpoint)){ |
||||
//if(strpos($this->endpoint,'http:')){ |
||||
$this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); |
||||
} elseif(ereg('^https',$this->endpoint)){ |
||||
//} elseif(strpos($this->endpoint,'https:')){ |
||||
//if(phpversion() == '4.3.0-dev'){ |
||||
//$response = $http->send($msg,$timeout,$response_timeout); |
||||
//$this->request = $http->outgoing_payload; |
||||
//$this->response = $http->incoming_payload; |
||||
//} else |
||||
$this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); |
||||
} else { |
||||
$this->setError('no http/s in endpoint url'); |
||||
} |
||||
$this->request = $http->outgoing_payload; |
||||
$this->response = $http->incoming_payload; |
||||
$this->appendDebug($http->getDebug()); |
||||
$this->UpdateCookies($http->incoming_cookies); |
||||
|
||||
// save transport object if using persistent connections |
||||
if ($this->persistentConnection) { |
||||
$http->clearDebug(); |
||||
if (!is_object($this->persistentConnection)) { |
||||
$this->persistentConnection = $http; |
||||
} |
||||
} |
||||
|
||||
if($err = $http->getError()){ |
||||
$this->setError('HTTP Error: '.$err); |
||||
return false; |
||||
} elseif($this->getError()){ |
||||
return false; |
||||
} else { |
||||
$this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); |
||||
return $this->parseResponse($http->incoming_headers, $this->responseData); |
||||
} |
||||
break; |
||||
default: |
||||
$this->setError('no transport found, or selected transport is not yet supported!'); |
||||
return false; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* processes SOAP message returned from server |
||||
* |
||||
* @param array $headers The HTTP headers |
||||
* @param string $data unprocessed response data from server |
||||
* @return mixed value of the message, decoded into a PHP type |
||||
* @access private |
||||
*/ |
||||
function parseResponse($headers, $data) { |
||||
$this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); |
||||
$this->appendDebug($this->varDump($headers)); |
||||
if (!strstr($headers['content-type'], 'text/xml')) { |
||||
$this->setError('Response not of type text/xml: ' . $headers['content-type']); |
||||
return false; |
||||
} |
||||
if (strpos($headers['content-type'], '=')) { |
||||
$enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); |
||||
$this->debug('Got response encoding: ' . $enc); |
||||
if(eregi('^(ISO-8859-1|US-ASCII|UTF-8)$',$enc)){ |
||||
$this->xml_encoding = strtoupper($enc); |
||||
} else { |
||||
$this->xml_encoding = 'US-ASCII'; |
||||
} |
||||
} else { |
||||
// should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 |
||||
$this->xml_encoding = 'ISO-8859-1'; |
||||
} |
||||
$this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); |
||||
$parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); |
||||
// add parser debug data to our debug |
||||
$this->appendDebug($parser->getDebug()); |
||||
// if parse errors |
||||
if($errstr = $parser->getError()){ |
||||
$this->setError( $errstr); |
||||
// destroy the parser object |
||||
unset($parser); |
||||
return false; |
||||
} else { |
||||
// get SOAP headers |
||||
$this->responseHeaders = $parser->getHeaders(); |
||||
// get SOAP headers |
||||
$this->responseHeader = $parser->get_soapheader(); |
||||
// get decoded message |
||||
$return = $parser->get_soapbody(); |
||||
// add document for doclit support |
||||
$this->document = $parser->document; |
||||
// destroy the parser object |
||||
unset($parser); |
||||
// return decode message |
||||
return $return; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* sets user-specified cURL options |
||||
* |
||||
* @param mixed $option The cURL option (always integer?) |
||||
* @param mixed $value The cURL option value |
||||
* @access public |
||||
*/ |
||||
function setCurlOption($option, $value) { |
||||
$this->debug("setCurlOption option=$option, value="); |
||||
$this->appendDebug($this->varDump($value)); |
||||
$this->curl_options[$option] = $value; |
||||
} |
||||
|
||||
/** |
||||
* sets the SOAP endpoint, which can override WSDL |
||||
* |
||||
* @param string $endpoint The endpoint URL to use, or empty string or false to prevent override |
||||
* @access public |
||||
*/ |
||||
function setEndpoint($endpoint) { |
||||
$this->debug("setEndpoint(\"$endpoint\")"); |
||||
$this->forceEndpoint = $endpoint; |
||||
} |
||||
|
||||
/** |
||||
* set the SOAP headers |
||||
* |
||||
* @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers |
||||
* @access public |
||||
*/ |
||||
function setHeaders($headers){ |
||||
$this->debug("setHeaders headers="); |
||||
$this->appendDebug($this->varDump($headers)); |
||||
$this->requestHeaders = $headers; |
||||
} |
||||
|
||||
/** |
||||
* get the SOAP response headers (namespace resolution incomplete) |
||||
* |
||||
* @return string |
||||
* @access public |
||||
*/ |
||||
function getHeaders(){ |
||||
return $this->responseHeaders; |
||||
} |
||||
|
||||
/** |
||||
* get the SOAP response Header (parsed) |
||||
* |
||||
* @return mixed |
||||
* @access public |
||||
*/ |
||||
function getHeader(){ |
||||
return $this->responseHeader; |
||||
} |
||||
|
||||
/** |
||||
* set proxy info here |
||||
* |
||||
* @param string $proxyhost |
||||
* @param string $proxyport |
||||
* @param string $proxyusername |
||||
* @param string $proxypassword |
||||
* @access public |
||||
*/ |
||||
function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { |
||||
$this->proxyhost = $proxyhost; |
||||
$this->proxyport = $proxyport; |
||||
$this->proxyusername = $proxyusername; |
||||
$this->proxypassword = $proxypassword; |
||||
} |
||||
|
||||
/** |
||||
* if authenticating, set user credentials here |
||||
* |
||||
* @param string $username |
||||
* @param string $password |
||||
* @param string $authtype (basic|digest|certificate|ntlm) |
||||
* @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) |
||||
* @access public |
||||
*/ |
||||
function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { |
||||
$this->debug("setCredentials username=$username authtype=$authtype certRequest="); |
||||
$this->appendDebug($this->varDump($certRequest)); |
||||
$this->username = $username; |
||||
$this->password = $password; |
||||
$this->authtype = $authtype; |
||||
$this->certRequest = $certRequest; |
||||
} |
||||
|
||||
/** |
||||
* use HTTP encoding |
||||
* |
||||
* @param string $enc HTTP encoding |
||||
* @access public |
||||
*/ |
||||
function setHTTPEncoding($enc='gzip, deflate'){ |
||||
$this->debug("setHTTPEncoding(\"$enc\")"); |
||||
$this->http_encoding = $enc; |
||||
} |
||||
|
||||
/** |
||||
* Set whether to try to use cURL connections if possible |
||||
* |
||||
* @param boolean $use Whether to try to use cURL |
||||
* @access public |
||||
*/ |
||||
function setUseCURL($use) { |
||||
$this->debug("setUseCURL($use)"); |
||||
$this->use_curl = $use; |
||||
} |
||||
|
||||
/** |
||||
* use HTTP persistent connections if possible |
||||
* |
||||
* @access public |
||||
*/ |
||||
function useHTTPPersistentConnection(){ |
||||
$this->debug("useHTTPPersistentConnection"); |
||||
$this->persistentConnection = true; |
||||
} |
||||
|
||||
/** |
||||
* gets the default RPC parameter setting. |
||||
* If true, default is that call params are like RPC even for document style. |
||||
* Each call() can override this value. |
||||
* |
||||
* This is no longer used. |
||||
* |
||||
* @return boolean |
||||
* @access public |
||||
* @deprecated |
||||
*/ |
||||
function getDefaultRpcParams() { |
||||
return $this->defaultRpcParams; |
||||
} |
||||
|
||||
/** |
||||
* sets the default RPC parameter setting. |
||||
* If true, default is that call params are like RPC even for document style |
||||
* Each call() can override this value. |
||||
* |
||||
* This is no longer used. |
||||
* |
||||
* @param boolean $rpcParams |
||||
* @access public |
||||
* @deprecated |
||||
*/ |
||||
function setDefaultRpcParams($rpcParams) { |
||||
$this->defaultRpcParams = $rpcParams; |
||||
} |
||||
|
||||
/** |
||||
* dynamically creates an instance of a proxy class, |
||||
* allowing user to directly call methods from wsdl |
||||
* |
||||
* @return object soap_proxy object |
||||
* @access public |
||||
*/ |
||||
function getProxy() { |
||||
$r = rand(); |
||||
$evalStr = $this->_getProxyClassCode($r); |
||||
//$this->debug("proxy class: $evalStr"); |
||||
if ($this->getError()) { |
||||
$this->debug("Error from _getProxyClassCode, so return NULL"); |
||||
return null; |
||||
} |
||||
// eval the class |
||||
eval($evalStr); |
||||
// instantiate proxy object |
||||
eval("\$proxy = new nusoap_proxy_$r('');"); |
||||
// transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice |
||||
$proxy->endpointType = 'wsdl'; |
||||
$proxy->wsdlFile = $this->wsdlFile; |
||||
$proxy->wsdl = $this->wsdl; |
||||
$proxy->operations = $this->operations; |
||||
$proxy->defaultRpcParams = $this->defaultRpcParams; |
||||
// transfer other state |
||||
$proxy->soap_defencoding = $this->soap_defencoding; |
||||
$proxy->username = $this->username; |
||||
$proxy->password = $this->password; |
||||
$proxy->authtype = $this->authtype; |
||||
$proxy->certRequest = $this->certRequest; |
||||
$proxy->requestHeaders = $this->requestHeaders; |
||||
$proxy->endpoint = $this->endpoint; |
||||
$proxy->forceEndpoint = $this->forceEndpoint; |
||||
$proxy->proxyhost = $this->proxyhost; |
||||
$proxy->proxyport = $this->proxyport; |
||||
$proxy->proxyusername = $this->proxyusername; |
||||
$proxy->proxypassword = $this->proxypassword; |
||||
$proxy->http_encoding = $this->http_encoding; |
||||
$proxy->timeout = $this->timeout; |
||||
$proxy->response_timeout = $this->response_timeout; |
||||
$proxy->persistentConnection = &$this->persistentConnection; |
||||
$proxy->decode_utf8 = $this->decode_utf8; |
||||
$proxy->curl_options = $this->curl_options; |
||||
$proxy->bindingType = $this->bindingType; |
||||
$proxy->use_curl = $this->use_curl; |
||||
return $proxy; |
||||
} |
||||
|
||||
/** |
||||
* dynamically creates proxy class code |
||||
* |
||||
* @return string PHP/NuSOAP code for the proxy class |
||||
* @access private |
||||
*/ |
||||
function _getProxyClassCode($r) { |
||||
$this->debug("in getProxy endpointType=$this->endpointType"); |
||||
$this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); |
||||
if ($this->endpointType != 'wsdl') { |
||||
$evalStr = 'A proxy can only be created for a WSDL client'; |
||||
$this->setError($evalStr); |
||||
$evalStr = "echo \"$evalStr\";"; |
||||
return $evalStr; |
||||
} |
||||
if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { |
||||
$this->loadWSDL(); |
||||
if ($this->getError()) { |
||||
return "echo \"" . $this->getError() . "\";"; |
||||
} |
||||
} |
||||
$evalStr = ''; |
||||
foreach ($this->operations as $operation => $opData) { |
||||
if ($operation != '') { |
||||
// create param string and param comment string |
||||
if (sizeof($opData['input']['parts']) > 0) { |
||||
$paramStr = ''; |
||||
$paramArrayStr = ''; |
||||
$paramCommentStr = ''; |
||||
foreach ($opData['input']['parts'] as $name => $type) { |
||||
$paramStr .= "\$$name, "; |
||||
$paramArrayStr .= "'$name' => \$$name, "; |
||||
$paramCommentStr .= "$type \$$name, "; |
||||
} |
||||
$paramStr = substr($paramStr, 0, strlen($paramStr)-2); |
||||
$paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); |
||||
$paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); |
||||
} else { |
||||
$paramStr = ''; |
||||
$paramArrayStr = ''; |
||||
$paramCommentStr = 'void'; |
||||
} |
||||
$opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; |
||||
$evalStr .= "// $paramCommentStr |
||||
function " . str_replace('.', '__', $operation) . "($paramStr) { |
||||
\$params = array($paramArrayStr); |
||||
return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); |
||||
} |
||||
"; |
||||
unset($paramStr); |
||||
unset($paramCommentStr); |
||||
} |
||||
} |
||||
$evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { |
||||
'.$evalStr.' |
||||
}'; |
||||
return $evalStr; |
||||
} |
||||
|
||||
/** |
||||
* dynamically creates proxy class code |
||||
* |
||||
* @return string PHP/NuSOAP code for the proxy class |
||||
* @access public |
||||
*/ |
||||
function getProxyClassCode() { |
||||
$r = rand(); |
||||
return $this->_getProxyClassCode($r); |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP body for the current request. |
||||
* |
||||
* @param string $soapmsg The SOAP payload |
||||
* @return string The HTTP body, which includes the SOAP payload |
||||
* @access private |
||||
*/ |
||||
function getHTTPBody($soapmsg) { |
||||
return $soapmsg; |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP content type for the current request. |
||||
* |
||||
* Note: getHTTPBody must be called before this. |
||||
* |
||||
* @return string the HTTP content type for the current request. |
||||
* @access private |
||||
*/ |
||||
function getHTTPContentType() { |
||||
return 'text/xml'; |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP content type charset for the current request. |
||||
* returns false for non-text content types. |
||||
* |
||||
* Note: getHTTPBody must be called before this. |
||||
* |
||||
* @return string the HTTP content type charset for the current request. |
||||
* @access private |
||||
*/ |
||||
function getHTTPContentTypeCharset() { |
||||
return $this->soap_defencoding; |
||||
} |
||||
|
||||
/* |
||||
* whether or not parser should decode utf8 element content |
||||
* |
||||
* @return always returns true |
||||
* @access public |
||||
*/ |
||||
function decodeUTF8($bool){ |
||||
$this->decode_utf8 = $bool; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* adds a new Cookie into $this->cookies array |
||||
* |
||||
* @param string $name Cookie Name |
||||
* @param string $value Cookie Value |
||||
* @return boolean if cookie-set was successful returns true, else false |
||||
* @access public |
||||
*/ |
||||
function setCookie($name, $value) { |
||||
if (strlen($name) == 0) { |
||||
return false; |
||||
} |
||||
$this->cookies[] = array('name' => $name, 'value' => $value); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* gets all Cookies |
||||
* |
||||
* @return array with all internal cookies |
||||
* @access public |
||||
*/ |
||||
function getCookies() { |
||||
return $this->cookies; |
||||
} |
||||
|
||||
/** |
||||
* checks all Cookies and delete those which are expired |
||||
* |
||||
* @return boolean always return true |
||||
* @access private |
||||
*/ |
||||
function checkCookies() { |
||||
if (sizeof($this->cookies) == 0) { |
||||
return true; |
||||
} |
||||
$this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); |
||||
$curr_cookies = $this->cookies; |
||||
$this->cookies = array(); |
||||
foreach ($curr_cookies as $cookie) { |
||||
if (! is_array($cookie)) { |
||||
$this->debug('Remove cookie that is not an array'); |
||||
continue; |
||||
} |
||||
if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { |
||||
if (strtotime($cookie['expires']) > time()) { |
||||
$this->cookies[] = $cookie; |
||||
} else { |
||||
$this->debug('Remove expired cookie ' . $cookie['name']); |
||||
} |
||||
} else { |
||||
$this->cookies[] = $cookie; |
||||
} |
||||
} |
||||
$this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* updates the current cookies with a new set |
||||
* |
||||
* @param array $cookies new cookies with which to update current ones |
||||
* @return boolean always return true |
||||
* @access private |
||||
*/ |
||||
function UpdateCookies($cookies) { |
||||
if (sizeof($this->cookies) == 0) { |
||||
// no existing cookies: take whatever is new |
||||
if (sizeof($cookies) > 0) { |
||||
$this->debug('Setting new cookie(s)'); |
||||
$this->cookies = $cookies; |
||||
} |
||||
return true; |
||||
} |
||||
if (sizeof($cookies) == 0) { |
||||
// no new cookies: keep what we've got |
||||
return true; |
||||
} |
||||
// merge |
||||
foreach ($cookies as $newCookie) { |
||||
if (!is_array($newCookie)) { |
||||
continue; |
||||
} |
||||
if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { |
||||
continue; |
||||
} |
||||
$newName = $newCookie['name']; |
||||
|
||||
$found = false; |
||||
for ($i = 0; $i < count($this->cookies); $i++) { |
||||
$cookie = $this->cookies[$i]; |
||||
if (!is_array($cookie)) { |
||||
continue; |
||||
} |
||||
if (!isset($cookie['name'])) { |
||||
continue; |
||||
} |
||||
if ($newName != $cookie['name']) { |
||||
continue; |
||||
} |
||||
$newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; |
||||
$domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; |
||||
if ($newDomain != $domain) { |
||||
continue; |
||||
} |
||||
$newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; |
||||
$path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; |
||||
if ($newPath != $path) { |
||||
continue; |
||||
} |
||||
$this->cookies[$i] = $newCookie; |
||||
$found = true; |
||||
$this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); |
||||
break; |
||||
} |
||||
if (! $found) { |
||||
$this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); |
||||
$this->cookies[] = $newCookie; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
if (!extension_loaded('soap')) { |
||||
/** |
||||
* For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. |
||||
*/ |
||||
class soapclient extends nusoap_client { |
||||
} |
||||
} |
||||
?> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,209 @@ |
||||
<?php |
||||
/* |
||||
The NuSOAP project home is: |
||||
http://sourceforge.net/projects/nusoap/ |
||||
|
||||
The primary support for NuSOAP is the mailing list: |
||||
nusoap-general@lists.sourceforge.net |
||||
*/ |
||||
|
||||
/** |
||||
* caches instances of the wsdl class |
||||
* |
||||
* @author Scott Nichol <snichol@users.sourceforge.net> |
||||
* @author Ingo Fischer <ingo@apollon.de> |
||||
* @version $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_wsdlcache { |
||||
/** |
||||
* @var resource |
||||
* @access private |
||||
*/ |
||||
var $fplock; |
||||
/** |
||||
* @var integer |
||||
* @access private |
||||
*/ |
||||
var $cache_lifetime; |
||||
/** |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $cache_dir; |
||||
/** |
||||
* @var string |
||||
* @access public |
||||
*/ |
||||
var $debug_str = ''; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param string $cache_dir directory for cache-files |
||||
* @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited |
||||
* @access public |
||||
*/ |
||||
function nusoap_wsdlcache($cache_dir='.', $cache_lifetime=0) { |
||||
$this->fplock = array(); |
||||
$this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; |
||||
$this->cache_lifetime = $cache_lifetime; |
||||
} |
||||
|
||||
/** |
||||
* creates the filename used to cache a wsdl instance |
||||
* |
||||
* @param string $wsdl The URL of the wsdl instance |
||||
* @return string The filename used to cache the instance |
||||
* @access private |
||||
*/ |
||||
function createFilename($wsdl) { |
||||
return $this->cache_dir.'/wsdlcache-' . md5($wsdl); |
||||
} |
||||
|
||||
/** |
||||
* adds debug data to the class level debug string |
||||
* |
||||
* @param string $string debug data |
||||
* @access private |
||||
*/ |
||||
function debug($string){ |
||||
$this->debug_str .= get_class($this).": $string\n"; |
||||
} |
||||
|
||||
/** |
||||
* gets a wsdl instance from the cache |
||||
* |
||||
* @param string $wsdl The URL of the wsdl instance |
||||
* @return object wsdl The cached wsdl instance, null if the instance is not in the cache |
||||
* @access public |
||||
*/ |
||||
function get($wsdl) { |
||||
$filename = $this->createFilename($wsdl); |
||||
if ($this->obtainMutex($filename, "r")) { |
||||
// check for expired WSDL that must be removed from the cache |
||||
if ($this->cache_lifetime > 0) { |
||||
if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { |
||||
unlink($filename); |
||||
$this->debug("Expired $wsdl ($filename) from cache"); |
||||
$this->releaseMutex($filename); |
||||
return null; |
||||
} |
||||
} |
||||
// see what there is to return |
||||
if (!file_exists($filename)) { |
||||
$this->debug("$wsdl ($filename) not in cache (1)"); |
||||
$this->releaseMutex($filename); |
||||
return null; |
||||
} |
||||
$fp = @fopen($filename, "r"); |
||||
if ($fp) { |
||||
$s = implode("", @file($filename)); |
||||
fclose($fp); |
||||
$this->debug("Got $wsdl ($filename) from cache"); |
||||
} else { |
||||
$s = null; |
||||
$this->debug("$wsdl ($filename) not in cache (2)"); |
||||
} |
||||
$this->releaseMutex($filename); |
||||
return (!is_null($s)) ? unserialize($s) : null; |
||||
} else { |
||||
$this->debug("Unable to obtain mutex for $filename in get"); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* obtains the local mutex |
||||
* |
||||
* @param string $filename The Filename of the Cache to lock |
||||
* @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode |
||||
* @return boolean Lock successfully obtained ?! |
||||
* @access private |
||||
*/ |
||||
function obtainMutex($filename, $mode) { |
||||
if (isset($this->fplock[md5($filename)])) { |
||||
$this->debug("Lock for $filename already exists"); |
||||
return false; |
||||
} |
||||
$this->fplock[md5($filename)] = fopen($filename.".lock", "w"); |
||||
if ($mode == "r") { |
||||
return flock($this->fplock[md5($filename)], LOCK_SH); |
||||
} else { |
||||
return flock($this->fplock[md5($filename)], LOCK_EX); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* adds a wsdl instance to the cache |
||||
* |
||||
* @param object wsdl $wsdl_instance The wsdl instance to add |
||||
* @return boolean WSDL successfully cached |
||||
* @access public |
||||
*/ |
||||
function put($wsdl_instance) { |
||||
$filename = $this->createFilename($wsdl_instance->wsdl); |
||||
$s = serialize($wsdl_instance); |
||||
if ($this->obtainMutex($filename, "w")) { |
||||
$fp = fopen($filename, "w"); |
||||
if (! $fp) { |
||||
$this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache"); |
||||
$this->releaseMutex($filename); |
||||
return false; |
||||
} |
||||
fputs($fp, $s); |
||||
fclose($fp); |
||||
$this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); |
||||
$this->releaseMutex($filename); |
||||
return true; |
||||
} else { |
||||
$this->debug("Unable to obtain mutex for $filename in put"); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* releases the local mutex |
||||
* |
||||
* @param string $filename The Filename of the Cache to lock |
||||
* @return boolean Lock successfully released |
||||
* @access private |
||||
*/ |
||||
function releaseMutex($filename) { |
||||
$ret = flock($this->fplock[md5($filename)], LOCK_UN); |
||||
fclose($this->fplock[md5($filename)]); |
||||
unset($this->fplock[md5($filename)]); |
||||
if (! $ret) { |
||||
$this->debug("Not able to release lock for $filename"); |
||||
} |
||||
return $ret; |
||||
} |
||||
|
||||
/** |
||||
* removes a wsdl instance from the cache |
||||
* |
||||
* @param string $wsdl The URL of the wsdl instance |
||||
* @return boolean Whether there was an instance to remove |
||||
* @access public |
||||
*/ |
||||
function remove($wsdl) { |
||||
$filename = $this->createFilename($wsdl); |
||||
if (!file_exists($filename)) { |
||||
$this->debug("$wsdl ($filename) not in cache to be removed"); |
||||
return false; |
||||
} |
||||
// ignore errors obtaining mutex |
||||
$this->obtainMutex($filename, "w"); |
||||
$ret = unlink($filename); |
||||
$this->debug("Removed ($ret) $wsdl ($filename) from cache"); |
||||
$this->releaseMutex($filename); |
||||
return $ret; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* For backward compatibility |
||||
*/ |
||||
class wsdlcache extends nusoap_wsdlcache { |
||||
} |
||||
?> |
@ -0,0 +1,938 @@ |
||||
<?php |
||||
|
||||
|
||||
|
||||
|
||||
/** |
||||
* parses an XML Schema, allows access to it's data, other utility methods. |
||||
* imperfect, no validation... yet, but quite functional. |
||||
* |
||||
* @author Dietrich Ayala <dietrich@ganx4.com> |
||||
* @author Scott Nichol <snichol@users.sourceforge.net> |
||||
* @version $Id: class.xmlschema.php,v 1.49 2007/11/06 14:17:53 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_xmlschema extends nusoap_base { |
||||
|
||||
// files |
||||
var $schema = ''; |
||||
var $xml = ''; |
||||
// namespaces |
||||
var $enclosingNamespaces; |
||||
// schema info |
||||
var $schemaInfo = array(); |
||||
var $schemaTargetNamespace = ''; |
||||
// types, elements, attributes defined by the schema |
||||
var $attributes = array(); |
||||
var $complexTypes = array(); |
||||
var $complexTypeStack = array(); |
||||
var $currentComplexType = null; |
||||
var $elements = array(); |
||||
var $elementStack = array(); |
||||
var $currentElement = null; |
||||
var $simpleTypes = array(); |
||||
var $simpleTypeStack = array(); |
||||
var $currentSimpleType = null; |
||||
// imports |
||||
var $imports = array(); |
||||
// parser vars |
||||
var $parser; |
||||
var $position = 0; |
||||
var $depth = 0; |
||||
var $depth_array = array(); |
||||
var $message = array(); |
||||
var $defaultNamespace = array(); |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param string $schema schema document URI |
||||
* @param string $xml xml document URI |
||||
* @param string $namespaces namespaces defined in enclosing XML |
||||
* @access public |
||||
*/ |
||||
function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ |
||||
parent::nusoap_base(); |
||||
$this->debug('nusoap_xmlschema class instantiated, inside constructor'); |
||||
// files |
||||
$this->schema = $schema; |
||||
$this->xml = $xml; |
||||
|
||||
// namespaces |
||||
$this->enclosingNamespaces = $namespaces; |
||||
$this->namespaces = array_merge($this->namespaces, $namespaces); |
||||
|
||||
// parse schema file |
||||
if($schema != ''){ |
||||
$this->debug('initial schema file: '.$schema); |
||||
$this->parseFile($schema, 'schema'); |
||||
} |
||||
|
||||
// parse xml file |
||||
if($xml != ''){ |
||||
$this->debug('initial xml file: '.$xml); |
||||
$this->parseFile($xml, 'xml'); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* parse an XML file |
||||
* |
||||
* @param string $xml path/URL to XML file |
||||
* @param string $type (schema | xml) |
||||
* @return boolean |
||||
* @access public |
||||
*/ |
||||
function parseFile($xml,$type){ |
||||
// parse xml file |
||||
if($xml != ""){ |
||||
$xmlStr = @join("",@file($xml)); |
||||
if($xmlStr == ""){ |
||||
$msg = 'Error reading XML from '.$xml; |
||||
$this->setError($msg); |
||||
$this->debug($msg); |
||||
return false; |
||||
} else { |
||||
$this->debug("parsing $xml"); |
||||
$this->parseString($xmlStr,$type); |
||||
$this->debug("done parsing $xml"); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* parse an XML string |
||||
* |
||||
* @param string $xml path or URL |
||||
* @param string $type (schema|xml) |
||||
* @access private |
||||
*/ |
||||
function parseString($xml,$type){ |
||||
// parse xml string |
||||
if($xml != ""){ |
||||
|
||||
// Create an XML parser. |
||||
$this->parser = xml_parser_create(); |
||||
// Set the options for parsing the XML data. |
||||
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
||||
|
||||
// Set the object for the parser. |
||||
xml_set_object($this->parser, $this); |
||||
|
||||
// Set the element handlers for the parser. |
||||
if($type == "schema"){ |
||||
xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); |
||||
xml_set_character_data_handler($this->parser,'schemaCharacterData'); |
||||
} elseif($type == "xml"){ |
||||
xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); |
||||
xml_set_character_data_handler($this->parser,'xmlCharacterData'); |
||||
} |
||||
|
||||
// Parse the XML file. |
||||
if(!xml_parse($this->parser,$xml,true)){ |
||||
// Display an error message. |
||||
$errstr = sprintf('XML error parsing XML schema on line %d: %s', |
||||
xml_get_current_line_number($this->parser), |
||||
xml_error_string(xml_get_error_code($this->parser)) |
||||
); |
||||
$this->debug($errstr); |
||||
$this->debug("XML payload:\n" . $xml); |
||||
$this->setError($errstr); |
||||
} |
||||
|
||||
xml_parser_free($this->parser); |
||||
} else{ |
||||
$this->debug('no xml passed to parseString()!!'); |
||||
$this->setError('no xml passed to parseString()!!'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* gets a type name for an unnamed type |
||||
* |
||||
* @param string Element name |
||||
* @return string A type name for an unnamed type |
||||
* @access private |
||||
*/ |
||||
function CreateTypeName($ename) { |
||||
$scope = ''; |
||||
for ($i = 0; $i < count($this->complexTypeStack); $i++) { |
||||
$scope .= $this->complexTypeStack[$i] . '_'; |
||||
} |
||||
return $scope . $ename . '_ContainedType'; |
||||
} |
||||
|
||||
/** |
||||
* start-element handler |
||||
* |
||||
* @param string $parser XML parser object |
||||
* @param string $name element name |
||||
* @param string $attrs associative array of attributes |
||||
* @access private |
||||
*/ |
||||
function schemaStartElement($parser, $name, $attrs) { |
||||
|
||||
// position in the total number of elements, starting from 0 |
||||
$pos = $this->position++; |
||||
$depth = $this->depth++; |
||||
// set self as current value for this depth |
||||
$this->depth_array[$depth] = $pos; |
||||
$this->message[$pos] = array('cdata' => ''); |
||||
if ($depth > 0) { |
||||
$this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; |
||||
} else { |
||||
$this->defaultNamespace[$pos] = false; |
||||
} |
||||
|
||||
// get element prefix |
||||
if($prefix = $this->getPrefix($name)){ |
||||
// get unqualified name |
||||
$name = $this->getLocalPart($name); |
||||
} else { |
||||
$prefix = ''; |
||||
} |
||||
|
||||
// loop thru attributes, expanding, and registering namespace declarations |
||||
if(count($attrs) > 0){ |
||||
foreach($attrs as $k => $v){ |
||||
// if ns declarations, add to class level array of valid namespaces |
||||
if(ereg("^xmlns",$k)){ |
||||
//$this->xdebug("$k: $v"); |
||||
//$this->xdebug('ns_prefix: '.$this->getPrefix($k)); |
||||
if($ns_prefix = substr(strrchr($k,':'),1)){ |
||||
//$this->xdebug("Add namespace[$ns_prefix] = $v"); |
||||
$this->namespaces[$ns_prefix] = $v; |
||||
} else { |
||||
$this->defaultNamespace[$pos] = $v; |
||||
if (! $this->getPrefixFromNamespace($v)) { |
||||
$this->namespaces['ns'.(count($this->namespaces)+1)] = $v; |
||||
} |
||||
} |
||||
if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ |
||||
$this->XMLSchemaVersion = $v; |
||||
$this->namespaces['xsi'] = $v.'-instance'; |
||||
} |
||||
} |
||||
} |
||||
foreach($attrs as $k => $v){ |
||||
// expand each attribute |
||||
$k = strpos($k,':') ? $this->expandQname($k) : $k; |
||||
$v = strpos($v,':') ? $this->expandQname($v) : $v; |
||||
$eAttrs[$k] = $v; |
||||
} |
||||
$attrs = $eAttrs; |
||||
} else { |
||||
$attrs = array(); |
||||
} |
||||
// find status, register data |
||||
switch($name){ |
||||
case 'all': // (optional) compositor content for a complexType |
||||
case 'choice': |
||||
case 'group': |
||||
case 'sequence': |
||||
//$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); |
||||
$this->complexTypes[$this->currentComplexType]['compositor'] = $name; |
||||
//if($name == 'all' || $name == 'sequence'){ |
||||
// $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
||||
//} |
||||
break; |
||||
case 'attribute': // complexType attribute |
||||
//$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); |
||||
$this->xdebug("parsing attribute:"); |
||||
$this->appendDebug($this->varDump($attrs)); |
||||
if (!isset($attrs['form'])) { |
||||
$attrs['form'] = $this->schemaInfo['attributeFormDefault']; |
||||
} |
||||
if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { |
||||
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; |
||||
if (!strpos($v, ':')) { |
||||
// no namespace in arrayType attribute value... |
||||
if ($this->defaultNamespace[$pos]) { |
||||
// ...so use the default |
||||
$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; |
||||
} |
||||
} |
||||
} |
||||
if(isset($attrs['name'])){ |
||||
$this->attributes[$attrs['name']] = $attrs; |
||||
$aname = $attrs['name']; |
||||
} elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ |
||||
if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { |
||||
$aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; |
||||
} else { |
||||
$aname = ''; |
||||
} |
||||
} elseif(isset($attrs['ref'])){ |
||||
$aname = $attrs['ref']; |
||||
$this->attributes[$attrs['ref']] = $attrs; |
||||
} |
||||
|
||||
if($this->currentComplexType){ // This should *always* be |
||||
$this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; |
||||
} |
||||
// arrayType attribute |
||||
if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ |
||||
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
||||
$prefix = $this->getPrefix($aname); |
||||
if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ |
||||
$v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; |
||||
} else { |
||||
$v = ''; |
||||
} |
||||
if(strpos($v,'[,]')){ |
||||
$this->complexTypes[$this->currentComplexType]['multidimensional'] = true; |
||||
} |
||||
$v = substr($v,0,strpos($v,'[')); // clip the [] |
||||
if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ |
||||
$v = $this->XMLSchemaVersion.':'.$v; |
||||
} |
||||
$this->complexTypes[$this->currentComplexType]['arrayType'] = $v; |
||||
} |
||||
break; |
||||
case 'complexContent': // (optional) content for a complexType |
||||
break; |
||||
case 'complexType': |
||||
array_push($this->complexTypeStack, $this->currentComplexType); |
||||
if(isset($attrs['name'])){ |
||||
// TODO: what is the scope of named complexTypes that appear |
||||
// nested within other c complexTypes? |
||||
$this->xdebug('processing named complexType '.$attrs['name']); |
||||
//$this->currentElement = false; |
||||
$this->currentComplexType = $attrs['name']; |
||||
$this->complexTypes[$this->currentComplexType] = $attrs; |
||||
$this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; |
||||
// This is for constructs like |
||||
// <complexType name="ListOfString" base="soap:Array"> |
||||
// <sequence> |
||||
// <element name="string" type="xsd:string" |
||||
// minOccurs="0" maxOccurs="unbounded" /> |
||||
// </sequence> |
||||
// </complexType> |
||||
if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ |
||||
$this->xdebug('complexType is unusual array'); |
||||
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
||||
} else { |
||||
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
||||
} |
||||
} else { |
||||
$name = $this->CreateTypeName($this->currentElement); |
||||
$this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); |
||||
$this->currentComplexType = $name; |
||||
//$this->currentElement = false; |
||||
$this->complexTypes[$this->currentComplexType] = $attrs; |
||||
$this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; |
||||
// This is for constructs like |
||||
// <complexType name="ListOfString" base="soap:Array"> |
||||
// <sequence> |
||||
// <element name="string" type="xsd:string" |
||||
// minOccurs="0" maxOccurs="unbounded" /> |
||||
// </sequence> |
||||
// </complexType> |
||||
if(isset($attrs['base']) && ereg(':Array$',$attrs['base'])){ |
||||
$this->xdebug('complexType is unusual array'); |
||||
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
||||
} else { |
||||
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
||||
} |
||||
} |
||||
break; |
||||
case 'element': |
||||
array_push($this->elementStack, $this->currentElement); |
||||
if (!isset($attrs['form'])) { |
||||
$attrs['form'] = $this->schemaInfo['elementFormDefault']; |
||||
} |
||||
if(isset($attrs['type'])){ |
||||
$this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); |
||||
if (! $this->getPrefix($attrs['type'])) { |
||||
if ($this->defaultNamespace[$pos]) { |
||||
$attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; |
||||
$this->xdebug('used default namespace to make type ' . $attrs['type']); |
||||
} |
||||
} |
||||
// This is for constructs like |
||||
// <complexType name="ListOfString" base="soap:Array"> |
||||
// <sequence> |
||||
// <element name="string" type="xsd:string" |
||||
// minOccurs="0" maxOccurs="unbounded" /> |
||||
// </sequence> |
||||
// </complexType> |
||||
if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { |
||||
$this->xdebug('arrayType for unusual array is ' . $attrs['type']); |
||||
$this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; |
||||
} |
||||
$this->currentElement = $attrs['name']; |
||||
$ename = $attrs['name']; |
||||
} elseif(isset($attrs['ref'])){ |
||||
$this->xdebug("processing element as ref to ".$attrs['ref']); |
||||
$this->currentElement = "ref to ".$attrs['ref']; |
||||
$ename = $this->getLocalPart($attrs['ref']); |
||||
} else { |
||||
$type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); |
||||
$this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); |
||||
$this->currentElement = $attrs['name']; |
||||
$attrs['type'] = $this->schemaTargetNamespace . ':' . $type; |
||||
$ename = $attrs['name']; |
||||
} |
||||
if (isset($ename) && $this->currentComplexType) { |
||||
$this->xdebug("add element $ename to complexType $this->currentComplexType"); |
||||
$this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; |
||||
} elseif (!isset($attrs['ref'])) { |
||||
$this->xdebug("add element $ename to elements array"); |
||||
$this->elements[ $attrs['name'] ] = $attrs; |
||||
$this->elements[ $attrs['name'] ]['typeClass'] = 'element'; |
||||
} |
||||
break; |
||||
case 'enumeration': // restriction value list member |
||||
$this->xdebug('enumeration ' . $attrs['value']); |
||||
if ($this->currentSimpleType) { |
||||
$this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; |
||||
} elseif ($this->currentComplexType) { |
||||
$this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; |
||||
} |
||||
break; |
||||
case 'extension': // simpleContent or complexContent type extension |
||||
$this->xdebug('extension ' . $attrs['base']); |
||||
if ($this->currentComplexType) { |
||||
$this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; |
||||
} |
||||
break; |
||||
case 'import': |
||||
if (isset($attrs['schemaLocation'])) { |
||||
//$this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); |
||||
$this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); |
||||
} else { |
||||
//$this->xdebug('import namespace ' . $attrs['namespace']); |
||||
$this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); |
||||
if (! $this->getPrefixFromNamespace($attrs['namespace'])) { |
||||
$this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; |
||||
} |
||||
} |
||||
break; |
||||
case 'list': // simpleType value list |
||||
break; |
||||
case 'restriction': // simpleType, simpleContent or complexContent value restriction |
||||
$this->xdebug('restriction ' . $attrs['base']); |
||||
if($this->currentSimpleType){ |
||||
$this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; |
||||
} elseif($this->currentComplexType){ |
||||
$this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; |
||||
if(strstr($attrs['base'],':') == ':Array'){ |
||||
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
||||
} |
||||
} |
||||
break; |
||||
case 'schema': |
||||
$this->schemaInfo = $attrs; |
||||
$this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); |
||||
if (isset($attrs['targetNamespace'])) { |
||||
$this->schemaTargetNamespace = $attrs['targetNamespace']; |
||||
} |
||||
if (!isset($attrs['elementFormDefault'])) { |
||||
$this->schemaInfo['elementFormDefault'] = 'unqualified'; |
||||
} |
||||
if (!isset($attrs['attributeFormDefault'])) { |
||||
$this->schemaInfo['attributeFormDefault'] = 'unqualified'; |
||||
} |
||||
break; |
||||
case 'simpleContent': // (optional) content for a complexType |
||||
break; |
||||
case 'simpleType': |
||||
array_push($this->simpleTypeStack, $this->currentSimpleType); |
||||
if(isset($attrs['name'])){ |
||||
$this->xdebug("processing simpleType for name " . $attrs['name']); |
||||
$this->currentSimpleType = $attrs['name']; |
||||
$this->simpleTypes[ $attrs['name'] ] = $attrs; |
||||
$this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; |
||||
$this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; |
||||
} else { |
||||
$name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); |
||||
$this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); |
||||
$this->currentSimpleType = $name; |
||||
//$this->currentElement = false; |
||||
$this->simpleTypes[$this->currentSimpleType] = $attrs; |
||||
$this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; |
||||
} |
||||
break; |
||||
case 'union': // simpleType type list |
||||
break; |
||||
default: |
||||
//$this->xdebug("do not have anything to do for element $name"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* end-element handler |
||||
* |
||||
* @param string $parser XML parser object |
||||
* @param string $name element name |
||||
* @access private |
||||
*/ |
||||
function schemaEndElement($parser, $name) { |
||||
// bring depth down a notch |
||||
$this->depth--; |
||||
// position of current element is equal to the last value left in depth_array for my depth |
||||
if(isset($this->depth_array[$this->depth])){ |
||||
$pos = $this->depth_array[$this->depth]; |
||||
} |
||||
// get element prefix |
||||
if ($prefix = $this->getPrefix($name)){ |
||||
// get unqualified name |
||||
$name = $this->getLocalPart($name); |
||||
} else { |
||||
$prefix = ''; |
||||
} |
||||
// move on... |
||||
if($name == 'complexType'){ |
||||
$this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); |
||||
$this->currentComplexType = array_pop($this->complexTypeStack); |
||||
//$this->currentElement = false; |
||||
} |
||||
if($name == 'element'){ |
||||
$this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); |
||||
$this->currentElement = array_pop($this->elementStack); |
||||
} |
||||
if($name == 'simpleType'){ |
||||
$this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); |
||||
$this->currentSimpleType = array_pop($this->simpleTypeStack); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* element content handler |
||||
* |
||||
* @param string $parser XML parser object |
||||
* @param string $data element content |
||||
* @access private |
||||
*/ |
||||
function schemaCharacterData($parser, $data){ |
||||
$pos = $this->depth_array[$this->depth - 1]; |
||||
$this->message[$pos]['cdata'] .= $data; |
||||
} |
||||
|
||||
/** |
||||
* serialize the schema |
||||
* |
||||
* @access public |
||||
*/ |
||||
function serializeSchema(){ |
||||
|
||||
$schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); |
||||
$xml = ''; |
||||
// imports |
||||
if (sizeof($this->imports) > 0) { |
||||
foreach($this->imports as $ns => $list) { |
||||
foreach ($list as $ii) { |
||||
if ($ii['location'] != '') { |
||||
$xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; |
||||
} else { |
||||
$xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
// complex types |
||||
foreach($this->complexTypes as $typeName => $attrs){ |
||||
$contentStr = ''; |
||||
// serialize child elements |
||||
if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ |
||||
foreach($attrs['elements'] as $element => $eParts){ |
||||
if(isset($eParts['ref'])){ |
||||
$contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; |
||||
} else { |
||||
$contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; |
||||
foreach ($eParts as $aName => $aValue) { |
||||
// handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable |
||||
if ($aName != 'name' && $aName != 'type') { |
||||
$contentStr .= " $aName=\"$aValue\""; |
||||
} |
||||
} |
||||
$contentStr .= "/>\n"; |
||||
} |
||||
} |
||||
// compositor wraps elements |
||||
if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { |
||||
$contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." </$schemaPrefix:$attrs[compositor]>\n"; |
||||
} |
||||
} |
||||
// attributes |
||||
if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ |
||||
foreach($attrs['attrs'] as $attr => $aParts){ |
||||
$contentStr .= " <$schemaPrefix:attribute"; |
||||
foreach ($aParts as $a => $v) { |
||||
if ($a == 'ref' || $a == 'type') { |
||||
$contentStr .= " $a=\"".$this->contractQName($v).'"'; |
||||
} elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { |
||||
$this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; |
||||
$contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; |
||||
} else { |
||||
$contentStr .= " $a=\"$v\""; |
||||
} |
||||
} |
||||
$contentStr .= "/>\n"; |
||||
} |
||||
} |
||||
// if restriction |
||||
if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ |
||||
$contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." </$schemaPrefix:restriction>\n"; |
||||
// complex or simple content |
||||
if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ |
||||
$contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." </$schemaPrefix:complexContent>\n"; |
||||
} |
||||
} |
||||
// finalize complex type |
||||
if($contentStr != ''){ |
||||
$contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n"; |
||||
} else { |
||||
$contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; |
||||
} |
||||
$xml .= $contentStr; |
||||
} |
||||
// simple types |
||||
if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ |
||||
foreach($this->simpleTypes as $typeName => $eParts){ |
||||
$xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; |
||||
if (isset($eParts['enumeration'])) { |
||||
foreach ($eParts['enumeration'] as $e) { |
||||
$xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; |
||||
} |
||||
} |
||||
$xml .= " </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>"; |
||||
} |
||||
} |
||||
// elements |
||||
if(isset($this->elements) && count($this->elements) > 0){ |
||||
foreach($this->elements as $element => $eParts){ |
||||
$xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; |
||||
} |
||||
} |
||||
// attributes |
||||
if(isset($this->attributes) && count($this->attributes) > 0){ |
||||
foreach($this->attributes as $attr => $aParts){ |
||||
$xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; |
||||
} |
||||
} |
||||
// finish 'er up |
||||
$attr = ''; |
||||
foreach ($this->schemaInfo as $k => $v) { |
||||
if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { |
||||
$attr .= " $k=\"$v\""; |
||||
} |
||||
} |
||||
$el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; |
||||
foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { |
||||
$el .= " xmlns:$nsp=\"$ns\""; |
||||
} |
||||
$xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n"; |
||||
return $xml; |
||||
} |
||||
|
||||
/** |
||||
* adds debug data to the clas level debug string |
||||
* |
||||
* @param string $string debug data |
||||
* @access private |
||||
*/ |
||||
function xdebug($string){ |
||||
$this->debug('<' . $this->schemaTargetNamespace . '> '.$string); |
||||
} |
||||
|
||||
/** |
||||
* get the PHP type of a user defined type in the schema |
||||
* PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays |
||||
* returns false if no type exists, or not w/ the given namespace |
||||
* else returns a string that is either a native php type, or 'struct' |
||||
* |
||||
* @param string $type name of defined type |
||||
* @param string $ns namespace of type |
||||
* @return mixed |
||||
* @access public |
||||
* @deprecated |
||||
*/ |
||||
function getPHPType($type,$ns){ |
||||
if(isset($this->typemap[$ns][$type])){ |
||||
//print "found type '$type' and ns $ns in typemap<br>"; |
||||
return $this->typemap[$ns][$type]; |
||||
} elseif(isset($this->complexTypes[$type])){ |
||||
//print "getting type '$type' and ns $ns from complexTypes array<br>"; |
||||
return $this->complexTypes[$type]['phpType']; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* returns an associative array of information about a given type |
||||
* returns false if no type exists by the given name |
||||
* |
||||
* For a complexType typeDef = array( |
||||
* 'restrictionBase' => '', |
||||
* 'phpType' => '', |
||||
* 'compositor' => '(sequence|all)', |
||||
* 'elements' => array(), // refs to elements array |
||||
* 'attrs' => array() // refs to attributes array |
||||
* ... and so on (see addComplexType) |
||||
* ) |
||||
* |
||||
* For simpleType or element, the array has different keys. |
||||
* |
||||
* @param string $type |
||||
* @return mixed |
||||
* @access public |
||||
* @see addComplexType |
||||
* @see addSimpleType |
||||
* @see addElement |
||||
*/ |
||||
function getTypeDef($type){ |
||||
//$this->debug("in getTypeDef for type $type"); |
||||
if (substr($type, -1) == '^') { |
||||
$is_element = 1; |
||||
$type = substr($type, 0, -1); |
||||
} else { |
||||
$is_element = 0; |
||||
} |
||||
|
||||
if((! $is_element) && isset($this->complexTypes[$type])){ |
||||
$this->xdebug("in getTypeDef, found complexType $type"); |
||||
return $this->complexTypes[$type]; |
||||
} elseif((! $is_element) && isset($this->simpleTypes[$type])){ |
||||
$this->xdebug("in getTypeDef, found simpleType $type"); |
||||
if (!isset($this->simpleTypes[$type]['phpType'])) { |
||||
// get info for type to tack onto the simple type |
||||
// TODO: can this ever really apply (i.e. what is a simpleType really?) |
||||
$uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); |
||||
$ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); |
||||
$etype = $this->getTypeDef($uqType); |
||||
if ($etype) { |
||||
$this->xdebug("in getTypeDef, found type for simpleType $type:"); |
||||
$this->xdebug($this->varDump($etype)); |
||||
if (isset($etype['phpType'])) { |
||||
$this->simpleTypes[$type]['phpType'] = $etype['phpType']; |
||||
} |
||||
if (isset($etype['elements'])) { |
||||
$this->simpleTypes[$type]['elements'] = $etype['elements']; |
||||
} |
||||
} |
||||
} |
||||
return $this->simpleTypes[$type]; |
||||
} elseif(isset($this->elements[$type])){ |
||||
$this->xdebug("in getTypeDef, found element $type"); |
||||
if (!isset($this->elements[$type]['phpType'])) { |
||||
// get info for type to tack onto the element |
||||
$uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); |
||||
$ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); |
||||
$etype = $this->getTypeDef($uqType); |
||||
if ($etype) { |
||||
$this->xdebug("in getTypeDef, found type for element $type:"); |
||||
$this->xdebug($this->varDump($etype)); |
||||
if (isset($etype['phpType'])) { |
||||
$this->elements[$type]['phpType'] = $etype['phpType']; |
||||
} |
||||
if (isset($etype['elements'])) { |
||||
$this->elements[$type]['elements'] = $etype['elements']; |
||||
} |
||||
} elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { |
||||
$this->xdebug("in getTypeDef, element $type is an XSD type"); |
||||
$this->elements[$type]['phpType'] = 'scalar'; |
||||
} |
||||
} |
||||
return $this->elements[$type]; |
||||
} elseif(isset($this->attributes[$type])){ |
||||
$this->xdebug("in getTypeDef, found attribute $type"); |
||||
return $this->attributes[$type]; |
||||
} elseif (ereg('_ContainedType$', $type)) { |
||||
$this->xdebug("in getTypeDef, have an untyped element $type"); |
||||
$typeDef['typeClass'] = 'simpleType'; |
||||
$typeDef['phpType'] = 'scalar'; |
||||
$typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; |
||||
return $typeDef; |
||||
} |
||||
$this->xdebug("in getTypeDef, did not find $type"); |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* returns a sample serialization of a given type, or false if no type by the given name |
||||
* |
||||
* @param string $type name of type |
||||
* @return mixed |
||||
* @access public |
||||
* @deprecated |
||||
*/ |
||||
function serializeTypeDef($type){ |
||||
//print "in sTD() for type $type<br>"; |
||||
if($typeDef = $this->getTypeDef($type)){ |
||||
$str .= '<'.$type; |
||||
if(is_array($typeDef['attrs'])){ |
||||
foreach($typeDef['attrs'] as $attName => $data){ |
||||
$str .= " $attName=\"{type = ".$data['type']."}\""; |
||||
} |
||||
} |
||||
$str .= " xmlns=\"".$this->schema['targetNamespace']."\""; |
||||
if(count($typeDef['elements']) > 0){ |
||||
$str .= ">"; |
||||
foreach($typeDef['elements'] as $element => $eData){ |
||||
$str .= $this->serializeTypeDef($element); |
||||
} |
||||
$str .= "</$type>"; |
||||
} elseif($typeDef['typeClass'] == 'element') { |
||||
$str .= "></$type>"; |
||||
} else { |
||||
$str .= "/>"; |
||||
} |
||||
return $str; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* returns HTML form elements that allow a user |
||||
* to enter values for creating an instance of the given type. |
||||
* |
||||
* @param string $name name for type instance |
||||
* @param string $type name of type |
||||
* @return string |
||||
* @access public |
||||
* @deprecated |
||||
*/ |
||||
function typeToForm($name,$type){ |
||||
// get typedef |
||||
if($typeDef = $this->getTypeDef($type)){ |
||||
// if struct |
||||
if($typeDef['phpType'] == 'struct'){ |
||||
$buffer .= '<table>'; |
||||
foreach($typeDef['elements'] as $child => $childDef){ |
||||
$buffer .= " |
||||
<tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> |
||||
<td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; |
||||
} |
||||
$buffer .= '</table>'; |
||||
// if array |
||||
} elseif($typeDef['phpType'] == 'array'){ |
||||
$buffer .= '<table>'; |
||||
for($i=0;$i < 3; $i++){ |
||||
$buffer .= " |
||||
<tr><td align='right'>array item (type: $typeDef[arrayType]):</td> |
||||
<td><input type='text' name='parameters[".$name."][]'></td></tr>"; |
||||
} |
||||
$buffer .= '</table>'; |
||||
// if scalar |
||||
} else { |
||||
$buffer .= "<input type='text' name='parameters[$name]'>"; |
||||
} |
||||
} else { |
||||
$buffer .= "<input type='text' name='parameters[$name]'>"; |
||||
} |
||||
return $buffer; |
||||
} |
||||
|
||||
/** |
||||
* adds a complex type to the schema |
||||
* |
||||
* example: array |
||||
* |
||||
* addType( |
||||
* 'ArrayOfstring', |
||||
* 'complexType', |
||||
* 'array', |
||||
* '', |
||||
* 'SOAP-ENC:Array', |
||||
* array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), |
||||
* 'xsd:string' |
||||
* ); |
||||
* |
||||
* example: PHP associative array ( SOAP Struct ) |
||||
* |
||||
* addType( |
||||
* 'SOAPStruct', |
||||
* 'complexType', |
||||
* 'struct', |
||||
* 'all', |
||||
* array('myVar'=> array('name'=>'myVar','type'=>'string') |
||||
* ); |
||||
* |
||||
* @param name |
||||
* @param typeClass (complexType|simpleType|attribute) |
||||
* @param phpType: currently supported are array and struct (php assoc array) |
||||
* @param compositor (all|sequence|choice) |
||||
* @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) |
||||
* @param elements = array ( name = array(name=>'',type=>'') ) |
||||
* @param attrs = array( |
||||
* array( |
||||
* 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", |
||||
* "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" |
||||
* ) |
||||
* ) |
||||
* @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) |
||||
* @access public |
||||
* @see getTypeDef |
||||
*/ |
||||
function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ |
||||
$this->complexTypes[$name] = array( |
||||
'name' => $name, |
||||
'typeClass' => $typeClass, |
||||
'phpType' => $phpType, |
||||
'compositor'=> $compositor, |
||||
'restrictionBase' => $restrictionBase, |
||||
'elements' => $elements, |
||||
'attrs' => $attrs, |
||||
'arrayType' => $arrayType |
||||
); |
||||
|
||||
$this->xdebug("addComplexType $name:"); |
||||
$this->appendDebug($this->varDump($this->complexTypes[$name])); |
||||
} |
||||
|
||||
/** |
||||
* adds a simple type to the schema |
||||
* |
||||
* @param string $name |
||||
* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) |
||||
* @param string $typeClass (should always be simpleType) |
||||
* @param string $phpType (should always be scalar) |
||||
* @param array $enumeration array of values |
||||
* @access public |
||||
* @see nusoap_xmlschema |
||||
* @see getTypeDef |
||||
*/ |
||||
function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { |
||||
$this->simpleTypes[$name] = array( |
||||
'name' => $name, |
||||
'typeClass' => $typeClass, |
||||
'phpType' => $phpType, |
||||
'type' => $restrictionBase, |
||||
'enumeration' => $enumeration |
||||
); |
||||
|
||||
$this->xdebug("addSimpleType $name:"); |
||||
$this->appendDebug($this->varDump($this->simpleTypes[$name])); |
||||
} |
||||
|
||||
/** |
||||
* adds an element to the schema |
||||
* |
||||
* @param array $attrs attributes that must include name and type |
||||
* @see nusoap_xmlschema |
||||
* @access public |
||||
*/ |
||||
function addElement($attrs) { |
||||
if (! $this->getPrefix($attrs['type'])) { |
||||
$attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; |
||||
} |
||||
$this->elements[ $attrs['name'] ] = $attrs; |
||||
$this->elements[ $attrs['name'] ]['typeClass'] = 'element'; |
||||
|
||||
$this->xdebug("addElement " . $attrs['name']); |
||||
$this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Backward compatibility |
||||
*/ |
||||
class XMLSchema extends nusoap_xmlschema { |
||||
} |
||||
|
||||
|
||||
?> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,501 @@ |
||||
<?php |
||||
/* |
||||
$Id: nusoapmime.php,v 1.12 2007/04/17 16:34:03 snichol Exp $ |
||||
|
||||
NuSOAP - Web Services Toolkit for PHP |
||||
|
||||
Copyright (c) 2002 NuSphere Corporation |
||||
|
||||
This library is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU Lesser General Public |
||||
License as published by the Free Software Foundation; either |
||||
version 2.1 of the License, or (at your option) any later version. |
||||
|
||||
This library is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
Lesser General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU Lesser General Public |
||||
License along with this library; if not, write to the Free Software |
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
|
||||
The NuSOAP project home is: |
||||
http://sourceforge.net/projects/nusoap/ |
||||
|
||||
The primary support for NuSOAP is the mailing list: |
||||
nusoap-general@lists.sourceforge.net |
||||
|
||||
If you have any questions or comments, please email: |
||||
|
||||
Dietrich Ayala |
||||
dietrich@ganx4.com |
||||
http://dietrich.ganx4.com/nusoap |
||||
|
||||
NuSphere Corporation |
||||
http://www.nusphere.com |
||||
|
||||
*/ |
||||
|
||||
/*require_once('nusoap.php');*/ |
||||
/* PEAR Mail_MIME library */ |
||||
require_once('Mail/mimeDecode.php'); |
||||
require_once('Mail/mimePart.php'); |
||||
|
||||
/** |
||||
* nusoap_client_mime client supporting MIME attachments defined at |
||||
* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. |
||||
* |
||||
* @author Scott Nichol <snichol@users.sourceforge.net> |
||||
* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list |
||||
* @version $Id: nusoapmime.php,v 1.12 2007/04/17 16:34:03 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_client_mime extends nusoap_client { |
||||
/** |
||||
* @var array Each array element in the return is an associative array with keys |
||||
* data, filename, contenttype, cid |
||||
* @access private |
||||
*/ |
||||
var $requestAttachments = array(); |
||||
/** |
||||
* @var array Each array element in the return is an associative array with keys |
||||
* data, filename, contenttype, cid |
||||
* @access private |
||||
*/ |
||||
var $responseAttachments; |
||||
/** |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $mimeContentType; |
||||
|
||||
/** |
||||
* adds a MIME attachment to the current request. |
||||
* |
||||
* If the $data parameter contains an empty string, this method will read |
||||
* the contents of the file named by the $filename parameter. |
||||
* |
||||
* If the $cid parameter is false, this method will generate the cid. |
||||
* |
||||
* @param string $data The data of the attachment |
||||
* @param string $filename The filename of the attachment (default is empty string) |
||||
* @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) |
||||
* @param string $cid The content-id (cid) of the attachment (default is false) |
||||
* @return string The content-id (cid) of the attachment |
||||
* @access public |
||||
*/ |
||||
function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { |
||||
if (! $cid) { |
||||
$cid = md5(uniqid(time())); |
||||
} |
||||
|
||||
$info['data'] = $data; |
||||
$info['filename'] = $filename; |
||||
$info['contenttype'] = $contenttype; |
||||
$info['cid'] = $cid; |
||||
|
||||
$this->requestAttachments[] = $info; |
||||
|
||||
return $cid; |
||||
} |
||||
|
||||
/** |
||||
* clears the MIME attachments for the current request. |
||||
* |
||||
* @access public |
||||
*/ |
||||
function clearAttachments() { |
||||
$this->requestAttachments = array(); |
||||
} |
||||
|
||||
/** |
||||
* gets the MIME attachments from the current response. |
||||
* |
||||
* Each array element in the return is an associative array with keys |
||||
* data, filename, contenttype, cid. These keys correspond to the parameters |
||||
* for addAttachment. |
||||
* |
||||
* @return array The attachments. |
||||
* @access public |
||||
*/ |
||||
function getAttachments() { |
||||
return $this->responseAttachments; |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP body for the current request. |
||||
* |
||||
* @param string $soapmsg The SOAP payload |
||||
* @return string The HTTP body, which includes the SOAP payload |
||||
* @access private |
||||
*/ |
||||
function getHTTPBody($soapmsg) { |
||||
if (count($this->requestAttachments) > 0) { |
||||
$params['content_type'] = 'multipart/related; type="text/xml"'; |
||||
$mimeMessage =& new Mail_mimePart('', $params); |
||||
unset($params); |
||||
|
||||
$params['content_type'] = 'text/xml'; |
||||
$params['encoding'] = '8bit'; |
||||
$params['charset'] = $this->soap_defencoding; |
||||
$mimeMessage->addSubpart($soapmsg, $params); |
||||
|
||||
foreach ($this->requestAttachments as $att) { |
||||
unset($params); |
||||
|
||||
$params['content_type'] = $att['contenttype']; |
||||
$params['encoding'] = 'base64'; |
||||
$params['disposition'] = 'attachment'; |
||||
$params['dfilename'] = $att['filename']; |
||||
$params['cid'] = $att['cid']; |
||||
|
||||
if ($att['data'] == '' && $att['filename'] <> '') { |
||||
if ($fd = fopen($att['filename'], 'rb')) { |
||||
$data = fread($fd, filesize($att['filename'])); |
||||
fclose($fd); |
||||
} else { |
||||
$data = ''; |
||||
} |
||||
$mimeMessage->addSubpart($data, $params); |
||||
} else { |
||||
$mimeMessage->addSubpart($att['data'], $params); |
||||
} |
||||
} |
||||
|
||||
$output = $mimeMessage->encode(); |
||||
$mimeHeaders = $output['headers']; |
||||
|
||||
foreach ($mimeHeaders as $k => $v) { |
||||
$this->debug("MIME header $k: $v"); |
||||
if (strtolower($k) == 'content-type') { |
||||
// PHP header() seems to strip leading whitespace starting |
||||
// the second line, so force everything to one line |
||||
$this->mimeContentType = str_replace("\r\n", " ", $v); |
||||
} |
||||
} |
||||
|
||||
return $output['body']; |
||||
} |
||||
|
||||
return parent::getHTTPBody($soapmsg); |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP content type for the current request. |
||||
* |
||||
* Note: getHTTPBody must be called before this. |
||||
* |
||||
* @return string the HTTP content type for the current request. |
||||
* @access private |
||||
*/ |
||||
function getHTTPContentType() { |
||||
if (count($this->requestAttachments) > 0) { |
||||
return $this->mimeContentType; |
||||
} |
||||
return parent::getHTTPContentType(); |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP content type charset for the current request. |
||||
* returns false for non-text content types. |
||||
* |
||||
* Note: getHTTPBody must be called before this. |
||||
* |
||||
* @return string the HTTP content type charset for the current request. |
||||
* @access private |
||||
*/ |
||||
function getHTTPContentTypeCharset() { |
||||
if (count($this->requestAttachments) > 0) { |
||||
return false; |
||||
} |
||||
return parent::getHTTPContentTypeCharset(); |
||||
} |
||||
|
||||
/** |
||||
* processes SOAP message returned from server |
||||
* |
||||
* @param array $headers The HTTP headers |
||||
* @param string $data unprocessed response data from server |
||||
* @return mixed value of the message, decoded into a PHP type |
||||
* @access private |
||||
*/ |
||||
function parseResponse($headers, $data) { |
||||
$this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); |
||||
$this->responseAttachments = array(); |
||||
if (strstr($headers['content-type'], 'multipart/related')) { |
||||
$this->debug('Decode multipart/related'); |
||||
$input = ''; |
||||
foreach ($headers as $k => $v) { |
||||
$input .= "$k: $v\r\n"; |
||||
} |
||||
$params['input'] = $input . "\r\n" . $data; |
||||
$params['include_bodies'] = true; |
||||
$params['decode_bodies'] = true; |
||||
$params['decode_headers'] = true; |
||||
|
||||
$structure = Mail_mimeDecode::decode($params); |
||||
|
||||
foreach ($structure->parts as $part) { |
||||
if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { |
||||
$this->debug('Have root part of type ' . $part->headers['content-type']); |
||||
$root = $part->body; |
||||
$return = parent::parseResponse($part->headers, $part->body); |
||||
} else { |
||||
$this->debug('Have an attachment of type ' . $part->headers['content-type']); |
||||
$info['data'] = $part->body; |
||||
$info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; |
||||
$info['contenttype'] = $part->headers['content-type']; |
||||
$info['cid'] = $part->headers['content-id']; |
||||
$this->responseAttachments[] = $info; |
||||
} |
||||
} |
||||
|
||||
if (isset($return)) { |
||||
$this->responseData = $root; |
||||
return $return; |
||||
} |
||||
|
||||
$this->setError('No root part found in multipart/related content'); |
||||
return ''; |
||||
} |
||||
$this->debug('Not multipart/related'); |
||||
return parent::parseResponse($headers, $data); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* For backwards compatiblity, define soapclientmime unless the PHP SOAP extension is loaded. |
||||
*/ |
||||
if (!extension_loaded('soap')) { |
||||
class soapclientmime extends nusoap_client_mime { |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* nusoap_server_mime server supporting MIME attachments defined at |
||||
* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. |
||||
* |
||||
* @author Scott Nichol <snichol@users.sourceforge.net> |
||||
* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list |
||||
* @version $Id: nusoapmime.php,v 1.12 2007/04/17 16:34:03 snichol Exp $ |
||||
* @access public |
||||
*/ |
||||
class nusoap_server_mime extends nusoap_server { |
||||
/** |
||||
* @var array Each array element in the return is an associative array with keys |
||||
* data, filename, contenttype, cid |
||||
* @access private |
||||
*/ |
||||
var $requestAttachments = array(); |
||||
/** |
||||
* @var array Each array element in the return is an associative array with keys |
||||
* data, filename, contenttype, cid |
||||
* @access private |
||||
*/ |
||||
var $responseAttachments; |
||||
/** |
||||
* @var string |
||||
* @access private |
||||
*/ |
||||
var $mimeContentType; |
||||
|
||||
/** |
||||
* adds a MIME attachment to the current response. |
||||
* |
||||
* If the $data parameter contains an empty string, this method will read |
||||
* the contents of the file named by the $filename parameter. |
||||
* |
||||
* If the $cid parameter is false, this method will generate the cid. |
||||
* |
||||
* @param string $data The data of the attachment |
||||
* @param string $filename The filename of the attachment (default is empty string) |
||||
* @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) |
||||
* @param string $cid The content-id (cid) of the attachment (default is false) |
||||
* @return string The content-id (cid) of the attachment |
||||
* @access public |
||||
*/ |
||||
function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { |
||||
if (! $cid) { |
||||
$cid = md5(uniqid(time())); |
||||
} |
||||
|
||||
$info['data'] = $data; |
||||
$info['filename'] = $filename; |
||||
$info['contenttype'] = $contenttype; |
||||
$info['cid'] = $cid; |
||||
|
||||
$this->responseAttachments[] = $info; |
||||
|
||||
return $cid; |
||||
} |
||||
|
||||
/** |
||||
* clears the MIME attachments for the current response. |
||||
* |
||||
* @access public |
||||
*/ |
||||
function clearAttachments() { |
||||
$this->responseAttachments = array(); |
||||
} |
||||
|
||||
/** |
||||
* gets the MIME attachments from the current request. |
||||
* |
||||
* Each array element in the return is an associative array with keys |
||||
* data, filename, contenttype, cid. These keys correspond to the parameters |
||||
* for addAttachment. |
||||
* |
||||
* @return array The attachments. |
||||
* @access public |
||||
*/ |
||||
function getAttachments() { |
||||
return $this->requestAttachments; |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP body for the current response. |
||||
* |
||||
* @param string $soapmsg The SOAP payload |
||||
* @return string The HTTP body, which includes the SOAP payload |
||||
* @access private |
||||
*/ |
||||
function getHTTPBody($soapmsg) { |
||||
if (count($this->responseAttachments) > 0) { |
||||
$params['content_type'] = 'multipart/related; type="text/xml"'; |
||||
$mimeMessage =& new Mail_mimePart('', $params); |
||||
unset($params); |
||||
|
||||
$params['content_type'] = 'text/xml'; |
||||
$params['encoding'] = '8bit'; |
||||
$params['charset'] = $this->soap_defencoding; |
||||
$mimeMessage->addSubpart($soapmsg, $params); |
||||
|
||||
foreach ($this->responseAttachments as $att) { |
||||
unset($params); |
||||
|
||||
$params['content_type'] = $att['contenttype']; |
||||
$params['encoding'] = 'base64'; |
||||
$params['disposition'] = 'attachment'; |
||||
$params['dfilename'] = $att['filename']; |
||||
$params['cid'] = $att['cid']; |
||||
|
||||
if ($att['data'] == '' && $att['filename'] <> '') { |
||||
if ($fd = fopen($att['filename'], 'rb')) { |
||||
$data = fread($fd, filesize($att['filename'])); |
||||
fclose($fd); |
||||
} else { |
||||
$data = ''; |
||||
} |
||||
$mimeMessage->addSubpart($data, $params); |
||||
} else { |
||||
$mimeMessage->addSubpart($att['data'], $params); |
||||
} |
||||
} |
||||
|
||||
$output = $mimeMessage->encode(); |
||||
$mimeHeaders = $output['headers']; |
||||
|
||||
foreach ($mimeHeaders as $k => $v) { |
||||
$this->debug("MIME header $k: $v"); |
||||
if (strtolower($k) == 'content-type') { |
||||
// PHP header() seems to strip leading whitespace starting |
||||
// the second line, so force everything to one line |
||||
$this->mimeContentType = str_replace("\r\n", " ", $v); |
||||
} |
||||
} |
||||
|
||||
return $output['body']; |
||||
} |
||||
|
||||
return parent::getHTTPBody($soapmsg); |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP content type for the current response. |
||||
* |
||||
* Note: getHTTPBody must be called before this. |
||||
* |
||||
* @return string the HTTP content type for the current response. |
||||
* @access private |
||||
*/ |
||||
function getHTTPContentType() { |
||||
if (count($this->responseAttachments) > 0) { |
||||
return $this->mimeContentType; |
||||
} |
||||
return parent::getHTTPContentType(); |
||||
} |
||||
|
||||
/** |
||||
* gets the HTTP content type charset for the current response. |
||||
* returns false for non-text content types. |
||||
* |
||||
* Note: getHTTPBody must be called before this. |
||||
* |
||||
* @return string the HTTP content type charset for the current response. |
||||
* @access private |
||||
*/ |
||||
function getHTTPContentTypeCharset() { |
||||
if (count($this->responseAttachments) > 0) { |
||||
return false; |
||||
} |
||||
return parent::getHTTPContentTypeCharset(); |
||||
} |
||||
|
||||
/** |
||||
* processes SOAP message received from client |
||||
* |
||||
* @param array $headers The HTTP headers |
||||
* @param string $data unprocessed request data from client |
||||
* @return mixed value of the message, decoded into a PHP type |
||||
* @access private |
||||
*/ |
||||
function parseRequest($headers, $data) { |
||||
$this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); |
||||
$this->requestAttachments = array(); |
||||
if (strstr($headers['content-type'], 'multipart/related')) { |
||||
$this->debug('Decode multipart/related'); |
||||
$input = ''; |
||||
foreach ($headers as $k => $v) { |
||||
$input .= "$k: $v\r\n"; |
||||
} |
||||
$params['input'] = $input . "\r\n" . $data; |
||||
$params['include_bodies'] = true; |
||||
$params['decode_bodies'] = true; |
||||
$params['decode_headers'] = true; |
||||
|
||||
$structure = Mail_mimeDecode::decode($params); |
||||
|
||||
foreach ($structure->parts as $part) { |
||||
if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { |
||||
$this->debug('Have root part of type ' . $part->headers['content-type']); |
||||
$return = parent::parseRequest($part->headers, $part->body); |
||||
} else { |
||||
$this->debug('Have an attachment of type ' . $part->headers['content-type']); |
||||
$info['data'] = $part->body; |
||||
$info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; |
||||
$info['contenttype'] = $part->headers['content-type']; |
||||
$info['cid'] = $part->headers['content-id']; |
||||
$this->requestAttachments[] = $info; |
||||
} |
||||
} |
||||
|
||||
if (isset($return)) { |
||||
return $return; |
||||
} |
||||
|
||||
$this->setError('No root part found in multipart/related content'); |
||||
return; |
||||
} |
||||
$this->debug('Not multipart/related'); |
||||
return parent::parseRequest($headers, $data); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* For backwards compatiblity |
||||
*/ |
||||
class nusoapservermime extends nusoap_server_mime { |
||||
} |
||||
|
||||
?> |
Loading…
Reference in new issue