prefix * * @var namespaces * @access public */ $namespaces = array( 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd' => $XMLSchemaVersion, 'xsi' => $XMLSchemaVersion.'-instance', 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', 'si' => 'http://soapinterop.org/xsd'); /** * * nusoap_base * * @author Dietrich Ayala * @version v 0.6 * @access public */ class nusoap_base { var $title = 'NuSOAP'; var $version = '0.6'; var $error_str = false; // toggles automatic encoding of special characters var $charencoding = true; /** * set default encoding * * @var soap_defencoding * @access public */ var $soap_defencoding = 'UTF-8'; /** * load namespace uris into an array of uri => prefix * * @var namespaces * @access public */ var $namespaces = array( 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd' => 'http://www.w3.org/2001/XMLSchema', 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', 'si' => 'http://soapinterop.org/xsd'); /** * load types into typemap array * is this legacy yet? * @var typemap * @access public */ var $typemap = array( 'http://www.w3.org/2001/XMLSchema' => array( 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', // derived datatypes 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 'negativeInteger'=>'integer','long'=>'','int'=>'integer','short'=>'','byte'=>'','nonNegativeInteger'=>'integer', 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 'http://www.w3.org/1999/XMLSchema' => array( 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 'float'=>'double','dateTime'=>'string', 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array') ); /** * entities to convert * * @var xmlEntities * @access public */ var $xmlEntities = array('quot' => '"','amp' => '&', 'lt' => '<','gt' => '>','apos' => "'"); /** * constructor: loads schema version */ function nusoap_base(){ global $XMLSchemaVersion; $this->XMLSchemaVersion = $XMLSchemaVersion; } /** * 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"; } /** * returns error string if present * * @return boolean $string error string * @access public */ function getError(){ if($this->error_str != ""){ return $this->error_str; } return false; } /** * sets error string * * @return boolean $string error string * @access private */ function setError($str){ $this->error_str = $str; } /** * serializes PHP values in accordance w/ section 5 * @return string * @access public */ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false){ //print "in serialize_val: $val, $name, $type, $name_ns, $type_ns
"; // if no name, use item $name = (!$name|| is_numeric($name)) ? 'noname' : $name; // if name has ns, add ns prefix to name if($name_ns){ $prefix = 'nu'.rand(1000,9999); $name = $prefix.':'.$name; $xmlns .= " xmlns:$prefix=\"$name_ns\""; } // if type is prefixed, create type prefix if($type_ns == $this->namespaces['xsd'] || $type_ns == ''){ // need to fix this. shouldn't default to if no ns specified // w/o checking against typemap $type_prefix = 'xsd'; } elseif($type_ns){ $type_prefix = 'ns'.rand(1000,9999); $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; } // serialize attributes if present if($attributes){ foreach($attributes as $k => $v){ $atts .= " $k=\"$v\""; } } // detect type and serialize switch(true) { case is_null($val): $xml .= "<$name$xmlns xsi:type=\"xsd:nil\"/>\n"; break; case (is_bool($val) || $type == 'boolean'): if(!$val){ $val = 0; } $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":boolean\"$atts>$val\n"; break; case (is_int($val) || is_long($val) || $type == 'int'): $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":int\"$atts>$val\n"; break; case (is_float($val)|| is_double($val) || $type == 'float'): $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":float\"$atts>$val\n"; break; case (is_string($val) || $type == 'string'): if($this->charencoding){ $val = htmlspecialchars($val); } $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":string\"$atts>$val\n"; break; case is_object($val): break; break; case (is_array($val) || $type): // detect if struct or array if(ereg("^[0-9]+$",key($val)) || ereg('^ArrayOf',$type)){ foreach($val as $v){ $tt = gettype($v); $array_types[$tt] = 1; $xml .= $this->serialize_val($v,'item'); if(is_array($v) && is_numeric(key($v))){ $i += sizeof($v); } else { $i += 1; unset($array_types['array']); } } if(count($array_types) > 1){ $array_typename = "xsd:ur-type"; } else { $array_typename = "xsd:".$tt; } if($array_types['array']){ $array_type = $i.",".$i; } else { $array_type = $i; } $xml = "<$name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"$atts>\n".$xml."\n"; } else { // got a struct if($type && $type_prefix){ $type_str = " xsi:type=\"$type_prefix:$type\""; } $xml .= "<$name$xmlns$type_str$atts>\n"; foreach($val as $k => $v){ $xml .= $this->serialize_val($v,$k); } $xml .= "\n"; } break; default: $xml .= "not detected, got ".gettype($val)." for $val\n"; break; } return $xml; } /** * serialize message * * @param string body * @param string headers * @param array namespaces * @return string message * @access public */ function serializeEnvelope($body,$headers=false,$namespaces=array()){ // serialize namespaces foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ $ns_string .= "\n xmlns:$k=\"$v\""; } // serialize headers if($headers){ $headers = "\n".$headers."\n"; } // serialize envelope return "\n". "\n". $headers. "\n". $body. "\n". "\n"; } function formatDump($str){ $str = htmlspecialchars($str); return nl2br($str); } } // XML Schema Datatype Helper Functions //xsd:dateTime helpers /** * convert unix timestamp to ISO 8601 compliant date string * * @param string $timestamp Unix time stamp * @access public */ function timestamp_to_iso8601($timestamp,$utc=true){ $datestr = date("Y-m-d\TH:i:sO",$timestamp); if($utc){ $eregStr = "([0-9]{4})-". // centuries & years CCYY- "([0-9]{2})-". // months MM- "([0-9]{2})". // days DD "T". // separator T "([0-9]{2}):". // hours hh: "([0-9]{2}):". // minutes mm: "([0-9]{2})(\.[0-9]*)?". // seconds ss.ss... "(Z|[+\-][0-9]{2}:?[0-9]{2})?"; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's if(ereg($eregStr,$datestr,$regs)){ return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); } return false; } else { return $datestr; } } /** * convert ISO 8601 compliant date string to unix timestamp * * @param string $datestr ISO 8601 compliant date string * @access public */ function iso8601_to_timestamp($datestr){ $eregStr = "([0-9]{4})-". // centuries & years CCYY- "([0-9]{2})-". // months MM- "([0-9]{2})". // days DD "T". // separator T "([0-9]{2}):". // hours hh: "([0-9]{2}):". // minutes mm: "([0-9]{2})(\.[0-9]+)?". // seconds ss.ss... "(Z|[+\-][0-9]{2}:?[0-9]{2})?"; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's if(ereg($eregStr,$datestr,$regs)){ // not utc if($regs[8] != "Z"){ $op = substr($regs[8],0,1); $h = substr($regs[8],1,2); $m = substr($regs[8],strlen($regs[8])-2,2); if($op == "-"){ $regs[4] = $regs[4] + $h; $regs[5] = $regs[5] + $m; } elseif($op == "+"){ $regs[4] = $regs[4] - $h; $regs[5] = $regs[5] - $m; } } return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); } else { return false; } } ?> faultcode = $faultcode; $this->faultactor = $faultactor; $this->faultstring = $faultstring; $this->faultdetail = $faultdetail; } /** * serialize a fault * * @access public */ function serialize(){ foreach($this->namespaces as $k => $v){ $ns_string .= "\n xmlns:$k=\"$v\""; } $return_msg = "\n". "\n". "\n". "\n". "$this->faultcode\n". "$this->faultactor\n". "$this->faultstring\n". "$this->faultdetail\n". "\n". "\n". "\n"; return $return_msg; } } ?> * @access public */ class XMLSchema extends nusoap_base { /** * constructor * * @param string $schema schema document URI * @param string $xml xml document URI * @access public */ function XMLSchema($schema="",$xml=""){ $this->debug('xmlschema class instantiated, inside constructor'); // files $this->schema = $schema; $this->xml = $xml; // define internal arrays of bindings, ports, operations, messages, etc. $this->complexTypes = array(); // parser vars $this->parser; $this->position; $this->depth; $this->depth_array = array(); // parse schema file if($schema != ""){ $this->debug("initial schema file: $schema"); $this->parseFile($schema); } // parse xml file if($xml != ""){ $this->debug("initial xml file: $xml"); $this->parseFile($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 != ""){ $this->debug("parsing $xml"); $xmlStr = @join("",@file($xml)); if($xmlStr == ""){ $this->setError("No file at the specified URL: $xml."); return false; } else { $this->parseString($xmlStr,$type); 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 on line %d: %s", xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)) ); $this->debug("XML parse error: $errstr"); $this->setError("Parser error: $errstr"); } xml_parser_free($this->parser); } else{ $this->debug("no xml passed to parseString()!!"); $this->setError("no xml passed to parseString()!!"); } } /** * 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; // loop through atts, logging ns declarations foreach($attrs as $key => $value){ // if ns declarations, add to class level array of valid namespaces if(ereg("^xmlns",$key)){ if($ns_prefix = substr(strrchr($key,":"),1)){ $this->namespaces[$ns_prefix] = $value; } else { $this->namespaces['ns'.(count($this->namespaces)+1)] = $value; } if($value == 'http://www.w3.org/2001/XMLSchema'){ $this->XMLSchemaVersion = $value; $this->namespaces['xsi'] = $value.'-instance'; } elseif($value == 'http://www.w3.org/1999/XMLSchema'){ $this->XMLSchemaVersion = $value; $this->namespaces['xsi'] = $value.'-instance'; } } } // get element prefix if(ereg(":",$name)){ // get ns prefix $prefix = substr($name,0,strpos($name,":")); // get unqualified name $name = substr(strstr($name,":"),1); } //$this->debug("name: $name, prefix: $prefix"); // find status, register data switch($name){ case "all": $this->complexTypes[$this->currentComplexType]["compositor"] = "all"; $this->complexTypes[$this->currentComplexType]["phpType"] = "struct"; break; case "attribute": if($attrs["name"]){ $this->attributes[$attrs["name"]] = $attrs; $aname = $attrs["name"]; } elseif($attrs["ref"]){ $aname = $this->expandQName($attrs["ref"]); } if($this->currentComplexType){ $this->complexTypes[$this->currentComplexType]["attrs"][$aname] = $attrs; } elseif($this->currentElement){ $this->elements[$this->currentElement]['attrs'][$aname] = $attrs; } if($aname == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ foreach($attrs as $k => $v){ if(strstr($k,':') == ':arrayType'){ if(strpos($v,'[,]')){ $this->complexTypes[$this->currentComplexType]["multidimensional"] = true; } $v = substr($v,0,strpos($v,'[')); // clip the [] if(strpos($v,':')){ $v = $this->expandQName($v); } else { $v = $this->XMLSchemaVersion.':'.$v; } $this->complexTypes[$this->currentComplexType]["arrayType"] = $v; break; } } } break; case "complexContent": break; case 'complexType': if($attrs['name']){ $this->currentElement = false; $this->currentComplexType = $attrs['name']; $this->complexTypes[$this->currentComplexType] = $attrs; $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; if(ereg(':Array$',$attrs['base'])){ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } else { $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; } $this->xdebug("processing complexType $attrs[name]"); } break; case 'element': if(isset($attrs['type'])){ $this->xdebug("processing element ".$attrs['name']); $this->currentElement = $attrs['name']; $this->elements[ $attrs['name'] ] = $attrs; $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; $ename = $attrs['name']; } elseif(isset($attrs['ref'])){ $ename = $attrs['ref']; } else { $this->xdebug("adding complexType $attrs[name]"); $this->currentComplexType = $attrs['name']; $this->complexTypes[ $attrs['name'] ] = $attrs; $this->complexTypes[ $attrs['name'] ]['element'] = 1; $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; } if($ename && $this->currentComplexType){ $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; } break; case 'restriction': $this->xdebug("in restriction for ct: $this->currentComplexType and ce: $this->currentElement"); if($this->currentElement){ $this->elements[$this->currentElement]['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->schema = $attrs; $this->schema['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); break; case 'sequence': $this->complexTypes[$this->currentComplexType]['compositor'] = 'sequence'; break; case 'simpleType': $this->currentElement = $attrs['name']; $this->elements[ $attrs['name'] ] = $attrs; $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; break; } } /** * end-element handler * * @param string $parser XML parser object * @param string $name element name * @access private */ function schemaEndElement($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]; // bring depth down a notch $this->depth--; // move on... if($name == 'complexType'){ $this->currentComplexType = false; $this->currentElement = false; } if($name == 'element'){ $this->currentElement = false; } } /** * 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]; $this->message[$pos]["cdata"] .= $data; } /** * serialize the schema * * @access public */ function serializeSchema(){ $schemaPrefix = $this->getPrefixFromNamespace($this->schema['schemaVersion']); // complex types foreach($this->complexTypes as $typeName => $attrs){ $contentStr = ""; // serialize child elements if(count($attrs["elements"]) > 0){ foreach($attrs["elements"] as $element => $eParts){ $contentStr .= "\n"; } } // serialize attributes if(count($attrs["attrs"]) > 0){ foreach($attrs["attrs"] as $attr => $aParts){ $contentStr .= "\n"; } } // if restriction if($attrs["restrictionBase"]){ $contentStr = "<$schemaPrefix:restriction base=\"".$attrs["restrictionBase"]."\">\n". $contentStr."\n"; } if($attrs["complexContent"]){ $contentStr = "<$schemaPrefix:complexContent>\n". $contentStr."\n"; } elseif($attrs["sequence"]){ $contentStr = "<$schemaPrefix:sequence>\n". $contentStr."\n"; } elseif($attrs["all"]){ $contentStr = "<$schemaPrefix:all>\n". $contentStr."\n"; } if($attrs['element']){ if($contentStr != ""){ $contentStr = "<$schemaPrefix:element name=\"$typeName\">\n"."<$schemaPrefix:complexType>\n". $contentStr."\n"."\n"; } else { $contentStr = "<$schemaPrefix:element name=\"$typeName\">\n"."<$schemaPrefix:complexType/>\n". "\n"; } } else { if($contentStr != ""){ $contentStr = "<$schemaPrefix:complexType name=\"$typeName\">\n". $contentStr."\n"; } else { $contentStr = "<$schemaPrefix:complexType name=\"$typeName\"/>\n"; } } $xml .= $contentStr; } // elements if(count($this->elements) > 0){ foreach($this->elements as $element => $eParts){ $xml .= "<$schemaPrefix:element name=\"$element\" type=\"".$eParts['type']."\"/>\n"; } } // attributes if(count($this->attributes) > 0){ foreach($this->attributes as $attr => $aParts){ $xml .= "<$schemaPrefix:attribute name=\"$attr\" type=\"".$aParts['type']."\"/>\n"; } } $xml = "<$schemaPrefix:schema targetNamespace=\"".$this->schema["targetNamespace"]."\">\n". $xml."\n"; return $xml; } /** * expands a qualified name * * @param string $string qname * @return string expanded qname * @access private */ function expandQname($qname){ // get element prefix if(ereg(":",$qname)){ // get unqualified name $name = substr(strstr($qname,":"),1); // get ns prefix $prefix = substr($qname,0,strpos($qname,":")); if(isset($this->namespaces[$prefix])){ return $this->namespaces[$prefix].":".$name; } else { return false; } } else { return $qname; } } /** * adds debug data to the clas level debug string * * @param string $string debug data * @access private */ function xdebug($string){ $this->debug(" xmlschema: $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 */ function getPHPType($type,$ns){ global $typemap; if(isset($typemap[$ns][$type])){ //print "found type '$type' and ns $ns in typemap
"; return $typemap[$ns][$type]; } elseif(isset($this->complexTypes[$type])){ //print "getting type '$type' and ns $ns from complexTypes array
"; return $this->complexTypes[$type]["phpType"]; } return false; } /** * returns the local part of a prefixed string * returns the original string, if not prefixed * * @param string * @return string * @access public */ function getLocalPart($str){ if($sstr = strrchr($str,':')){ // get unqualified name return substr( $sstr, 1 ); } else { return $str; } } /** * returns the prefix part of a prefixed string * returns false, if not prefixed * * @param string * @return mixed * @access public */ function getPrefix($str){ if($pos = strrpos($str,':')){ // get prefix return substr($str,0,$pos); } return false; } /** * pass it a prefix, it returns a namespace * or false if no prefixes registered for the given namespace * * @param string * @return mixed * @access public */ function getNamespaceFromPrefix($prefix){ if(isset($this->namespaces[$prefix])){ return $this->namespaces[$prefix]; } //$this->setError("No namespace registered for prefix '$prefix'"); return false; } /** * returns the prefix for a given namespace * returns false if no namespace registered with the given prefix * * @param string * @return mixed * @access public */ function getPrefixFromNamespace($ns){ foreach($this->namespaces as $p => $n){ if($ns == $n){ $this->usedNamespaces[$p] = $ns; return $p; } } return false; } /** * returns an array of information about a given type * returns false if no type exists by the given name * * typeDef = array( * 'elements' => array(), // refs to elements array * 'restrictionBase' => '', * 'phpType' => '', * 'order' => '(sequence|all)', * 'attrs' => array() // refs to attributes array * ) * * @param string * @return mixed * @access public */ function getTypeDef($type){ if(isset($this->complexTypes[$type])){ return $this->complexTypes[$type]; } elseif(isset($this->elements[$type])){ return $this->elements[$type]; } elseif(isset($this->attributes[$type])){ return $this->attributes[$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 */ function serializeTypeDef($type){ //print "in sTD() for type $type
"; if($typeDef = $this->getTypeDef($type)){ $str .= "<$type"; if(is_array($typeDef['attrs'])){ foreach($attrs as $attName => $data){ $str .= " $attName=\"{type = ".$data['type']."}\""; } } $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; if(count($typeDef['elements']) > 0){ $str .= ">\n"; foreach($typeDef['elements'] as $element => $eData){ $str .= $this->serializeTypeDef($element); } $str .= "\n"; } elseif($typeDef['typeClass'] == 'element') { $str .= ">\n"; } else { $str .= "/>\n"; } 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 */ function typeToForm($name,$type){ // get typedef if($typeDef = $this->getTypeDef($type)){ // if struct if($typeDef['phpType'] == 'struct'){ $buffer .= ''; foreach($typeDef['elements'] as $child => $childDef){ $buffer .= " "; } $buffer .= '
$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
'; // if array } elseif($typeDef['phpType'] == 'array'){ $buffer .= ''; for($i=0;$i < 3; $i++){ $buffer .= " "; } $buffer .= '
array item (type: $typeDef[arrayType]):
'; // if scalar } else { $buffer .= ""; } } else { $buffer .= ""; } return $buffer; } } ?> * @version v 0.6 * @access public */ class soapval extends nusoap_base { /** * constructor * * @param string $name optional value name * @param string $type optional type name * @param mixed $value optional content of value * @param string $namespace optional namespace of value * @param string $type_namespace optional namespace of type * @param array $attributes associative array of attributes to add to element serialization * @access public */ function soapval($name="noname",$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { $this->name = $name; $this->value = $value; $this->type = $type; $this->element_ns = $element_ns; $this->type_ns = $type_ns; $this->attributes = $attributes; } /** * return serialized value * * @return string XML data * @access private */ function serialize() { return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes); } /** * decodes a soapval object into a PHP native type * * @param object $soapval optional SOAPx4 soapval object, else uses self * @return mixed * @access public */ function decode(){ return $this->value; } } ?> url = $url; $u = parse_url($url); foreach($u as $k => $v){ $this->debug("$k = $v"); $this->$k = $v; } if($u['query'] != ''){ $this->path .= $u['query']; } if(!isset($u['port']) && $u['scheme'] == 'http'){ $this->port = 80; } } /** * if authenticating, set user credentials here * * @param string $user * @param string $pass * @access public */ function setCredentials($user, $pass) { $this->user = $username; $this->pass = $pword; } /** * set the soapaction value * * @param string $soapaction * @access public */ function setSOAPAction($soapaction) { $this->soapaction = $soapaction; } /** * set proxy info here * * @param string $proxyhost * @param string $proxyport * @access public */ function setProxy($proxyhost, $proxyport) { $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; } /** * send the SOAP message via HTTP 1.0 * * @param string $msg message data * @param integer $timeout set timeout in seconds * @return string data * @access public */ function send($data, $timeout=0) { flush(); $this->debug('entered send() with data of length: '.strlen($data)); if($this->proxyhost && $this->proxyport){ $host = $this->proxyhost; $port = $this->proxyport; } else { $host = $this->host; $port = $this->port; } if($timeout > 0){ $fp = fsockopen($host, $port, $this->errno, $this->error_str, $timeout); } else { $fp = fsockopen($host, $port, $this->errno, $this->error_str); } //socket_set_blocking($fp,0); if (!$fp) { $this->debug("Couldn't open socket connection to server: $server!"); $this->setError("Couldn't open socket connection to server: $server."); return false; } $credentials = ''; if($this->user != '') { $credentials = 'Authorization: Basic '.base64_encode('$this->user:$this->pass').'\r\n'; } if($this->proxyhost && $this->proxyport){ $this-> outgoing_payload = "POST $this->url HTTP/1.0\r\n"; } else { $this->outgoing_payload = "POST $this->path HTTP/1.0\r\n"; } $this->outgoing_payload .= "User-Agent: $this->title v$this->version\r\n". "Host: ".$this->host."\r\n". $credentials. "Content-Type: text/xml\r\nContent-Length: ".strlen($data)."\r\n". "SOAPAction: \"$this->soapaction\""."\r\n\r\n". $data; // send if(!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { $this->setError("couldn't write message data to socket"); $this->debug("Write error"); } // get response $this->incoming_payload = ""; while ($data = fread($fp, 32768)) { $this->incoming_payload .= $data; } // close filepointer fclose($fp); $data = $this->incoming_payload; //print "data: $data"; // separate content from HTTP headers if(preg_match("/([^<]*?)\r?\n\r?\n(<.*>)/s",$data,$result)) { $this->debug("found proper separation of headers and document"); $this->debug("getting rid of headers, stringlen: ".strlen($data)); $clean_data = $result[2]; $this->debug("cleaned data, stringlen: ".strlen($clean_data)); /* if(ereg("^(.*)\r?\n\r?\n",$data)) { $this->debug("found proper separation of headers and document"); $this->debug("getting rid of headers, stringlen: ".strlen($data)); $clean_data = ereg_replace("^[^<]*\r\n\r\n","", $data); $this->debug("cleaned data, stringlen: ".strlen($clean_data)); */ } else { $this->setError('no proper separation of headers and document.'); return false; } if(strlen($clean_data) == 0){ $this->debug("no data after headers!"); $this->setError("no data present after HTTP headers."); return false; } return $clean_data; } /** * send the SOAP message via HTTPS 1.0 using CURL * * @param string $msg message data * @param integer $timeout set timeout in seconds * @return string data * @access public */ function sendHTTPS($data, $timeout=0) { flush(); $this->debug('entered sendHTTPS() with data of length: '.strlen($data)); // init CURL $ch = curl_init(); // set proxy if($this->proxyhost && $this->proxyport){ $host = $this->proxyhost; $port = $this->proxyport; } else { $host = $this->host; $port = $this->port; } // set url $hostURL = ($port != '') ? "https://$host:$port" : "https://$host"; // add path $hostURL .= $this->path; curl_setopt($ch, CURLOPT_URL, $hostURL); // set other options curl_setopt($ch, CURLOPT_HEADER, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // set timeout if($timeout != 0){ curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); } $credentials = ''; if($this->user != '') { $credentials = 'Authorization: Basic '.base64_encode('$this->user:$this->pass').'\r\n'; } if($this->proxyhost && $this->proxyport){ $this-> outgoing_payload = "POST $this->url HTTP/1.0\r\n"; } else { $this->outgoing_payload = "POST $this->path HTTP/1.0\r\n"; } $this->outgoing_payload .= "User-Agent: $this->title v$this->version\r\n". "Host: ".$this->host."\r\n". $credentials. "Content-Type: text/xml\r\nContent-Length: ".strlen($data)."\r\n". "SOAPAction: \"$this->soapaction\""."\r\n\r\n". $data; // set payload curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); // send and receive $this->incoming_payload = curl_exec($ch); $data = $this->incoming_payload; $err = "cURL ERROR: ".curl_errno($ch).": ".curl_error($ch)."
"; if($err != ''){ foreach(curl_getinfo($ch) as $k => $v){ $err .= "$k: $v
"; } $this->setError($err); curl_close($ch); return false; } curl_close($ch); // separate content from HTTP headers if(ereg("^(.*)\r?\n\r?\n",$data)) { $this->debug("found proper separation of headers and document"); $this->debug("getting rid of headers, stringlen: ".strlen($data)); $clean_data = ereg_replace("^[^<]*\r\n\r\n","", $data); $this->debug("cleaned data, stringlen: ".strlen($clean_data)); } else { $this->setError('no proper separation of headers and document.'); return false; } if(strlen($clean_data) == 0){ $this->debug("no data after headers!"); $this->setError("no data present after HTTP headers."); return false; } return $clean_data; } } ?> * @version v 0.6 * @access public */ class soap_server extends nusoap_base { // assoc array of operations => opData var $operations = array(); var $responseHeaders = false; var $headers = ""; var $request = ""; var $charset_encoding = "UTF-8"; var $fault = false; var $result = "successful"; /** * constructor * * @param string $wsdl path or URL to a WSDL file * @access public */ function soap_server($wsdl=false){ // turn on debugging? global $debug; if(isset($debug)){ $this->debug_flag = true; } $this->wsdl = false; // wsdl if($wsdl){ $this->wsdl = new wsdl($wsdl); if($err = $this->wsdl->getError()){ die("WSDL ERROR: $err"); } } } /** * processes request and returns response * * @param string $data usually is the value of $HTTP_RAW_POST_DATA * @access public */ function service($data){ // print wsdl if(ereg('^wsdl',$GLOBALS['QUERY_STRING'])){ header("Content-Type: text/xml\r\n"); print $this->wsdl->serialize(); // print web interface } elseif($data == '' && $this->wsdl){ print $this->webDescription(); } else { // $response is the serialized response message $response = $this->parse_request($data); $this->debug("server sending..."); $payload = $response; //$payload .= ""; // print headers if($this->fault){ $header[] = "Status: 500 Internal Server Error\r\n"; } else { $header[] = "Status: 200 OK\r\n"; } $header[] = "Server: $this->title Server v$this->version\r\n"; $header[] = "Connection: Close\r\n"; $header[] = "Content-Type: text/xml; charset=$this->charset_encoding\r\n"; $header[] = "Content-Length: ".strlen($payload)."\r\n\r\n"; reset($header); foreach($header as $hdr){ header($hdr); } $this->response = join("\n",$header).$payload; print $payload; } } /** * parses request and posts response * * @param string $data XML string * @return object SOAPx4 soapmsg object * @access private */ function parse_request($data="") { $this->debug("entering parseRequest() on ".date("H:i Y-m-d")); // get headers if(function_exists("getallheaders")){ $this->headers = getallheaders(); foreach($this->headers as $k=>$v){ $dump .= "$k: $v\r\n"; $this->debug("$k: $v"); } // get SOAPAction header if($this->headers['SOAPAction']){ $this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']); } // get the character encoding of the incoming request if(strpos($headers_array['Content-Type'],"=")){ $enc = str_replace("\"","",substr(strstr($headers_array["Content-Type"],"="),1)); if(eregi("^(ISO-8859-1|US-ASCII|UTF-8)$",$enc)){ $this->xml_encoding = $enc; } else { $this->xml_encoding = 'us-ascii'; } } $this->debug("got encoding: $this->xml_encoding"); } elseif(is_array($_SERVER)){ $this->headers['User-Agent'] = $_SERVER['HTTP_USER_AGENT']; $this->SOAPAction = $_SERVER['SOAPAction']; } $this->request = $dump."\r\n\r\n".$data; // parse response, get soap parser obj $parser = new soap_parser($data,$this->xml_encoding); // if fault occurred during message parsing if($err = $parser->getError()){ // parser debug $this->debug("parser debug: \n".$parser->debug_str); $this->result = "fault: error in msg parsing or eval: $err"; $this->fault("Server","error in msg parsing or eval:\n".$err); // return soapresp return $this->fault->serialize(); // else successfully parsed request into soapval object } else { // get/set methodname $this->methodname = $parser->root_struct_name; $this->debug("method name: $this->methodname"); // does method exist? if(!function_exists($this->methodname)){ // "method not found" fault here $this->debug("method '$this->methodname' not found!"); $this->debug("parser debug: \n".$parser->debug_str); $this->result = "fault: method not found"; $this->fault("Server","method '$this->methodname' not defined in service '$this->service'"); return $this->fault->serialize(); } if($this->wsdl){ if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){ $this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service"); return $this->fault->serialize(); } } $this->debug("method '$this->methodname' exists"); // evaluate message, getting back parameters $this->debug("calling parser->get_response()"); $request_data = $parser->get_response(); $this->debug('Parsed response dump: $request_data'); // parser debug $this->debug("parser debug: \n".$parser->debug_str); // verify that request parameters match the method's signature if($this->verify_method($this->methodname,$request_data)){ // if there are parameters to pass if($request_data){ $this->debug("calling '$this->methodname' with params"); if (! function_exists('call_user_func_array')) { $this->debug("calling method using eval()"); $funcCall = $this->methodname."("; foreach($request_data as $param) { $funcCall .= "\"$param\","; } $funcCall = substr($funcCall, 0, -1).')'; $this->debug("function call:
$funcCall"); eval("\$method_response = $funcCall;"); } else { $this->debug("calling method using call_user_func_array()"); $method_response = call_user_func_array("$this->methodname",$request_data); } } else { // call method w/ no parameters $this->debug("calling $this->methodname w/ no params"); //$method_response = call_user_func($this->methodname); $m = $this->methodname; $method_response = $m(); } $this->debug("done calling method: $this->methodname, received $method_response of type".gettype($method_response)); // if we got nothing back. this might be ok (echoVoid) if(isset($method_response) && $method_response != "" || is_bool($method_response)) { // if fault if(get_class($method_response) == 'soap_fault'){ $this->debug('got a fault object from method'); $this->fault = $method_response; return $method_response->serialize(); // if return val is soapval object } elseif(get_class($method_response) == 'soapval'){ $this->debug('got a soapval object from method'); $return_val = $method_response->serialize(); // returned other } else { $this->debug("got a ".gettype($method_response)." from method"); $this->debug("serializing return value"); if($this->wsdl){ if(sizeof($this->opData['output']['parts']) > 1){ $opParams = $method_response; } else { $opParams = array($method_response); } $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); } else { $return_val = $this->serialize_val($method_response); } } } $this->debug("serializing response"); $payload = "<".$this->methodname."Response>\n".$return_val."methodname."Response>\n"; $this->result = "successful"; if($this->wsdl){ //$this->debug("WSDL debug data:\n".$this->wsdl->debug_str); } return $this->serializeEnvelope($payload,$this->responseHeaders); } else { // debug $this->debug("ERROR: request not verified against method signature"); $this->result = "fault: request failed validation against method signature"; // return fault $this->fault("Server","Sorry, operation '$this->methodname' not defined in service."); return $this->fault->serialize(); } } } /** * takes the soapval object that was created by parsing the request * and compares to the method's signature, if available. * * @param object SOAPx4 soapval object * @return boolean * @access private */ function verify_method($operation,$request){ if(isset($this->operations[$operation])){ return true; } return false; } /** * add a method to the dispatch map * * @param string $methodname * @param string $in array of input values * @param string $out array of output values * @access public */ function add_to_map($methodname,$in,$out){ $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); } /** * register a service with the server * * @param string $methodname * @param string $in array of input values * @param string $out array of output values * @param string $namespace * @param string $soapaction * @param string $style (rpc|literal) * @access public */ function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false){ $this->operations[$name] = array( 'name' => $name, 'in' => $in, 'out' => $out, 'namespace' => $namespage, 'soapaction' => $soapaction, 'style' => $style); return true; } /** * create a fault. this also acts as a flag to the server that a fault has occured. * * @param string faultcode * @param string faultactor * @param string faultstring * @param string faultdetail * @access public */ function fault($faultcode,$faultactor,$faultstring='',$faultdetail=''){ $this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail); } /** * prints html description of services * * @access private */ function webDescription(){ $b .= " NuSOAP: ".$this->wsdl->serviceName."


".$this->wsdl->serviceName."
"; return $b; } /** * sets up wsdl object * this acts as a flag to enable internal WSDL generation * NOTE: NOT FUNCTIONAL * * @param string $serviceName, name of the service * @param string $namespace, tns namespace */ function configureWSDL($serviceName,$namespace){ $this->wsdl = new wsdl; $this->wsdl->serviceName = $serviceName; $this->wsdl->namespaces['tns'] = $namespace; $this->wsdl->namespaces['soap'] = "http://schemas.xmlsoap.org/wsdl/soap/"; $this->wsdl->namespaces['wsdl'] = "http://schemas.xmlsoap.org/wsdl/"; } } ?> * @access public */ class wsdl extends XMLSchema { /** * constructor * * @param string $wsdl WSDL document URL * @access public */ function wsdl($wsdl=""){ $this->wsdl = $wsdl; // define internal arrays of bindings, ports, operations, messages, etc. //$this->namespaces = array(); $this->complexTypes = array(); $this->messages = array(); $this->currentMessage; $this->currentOperation; $this->portTypes = array(); $this->currentPortType; $this->bindings = array(); $this->currentBinding; $this->ports = array(); $this->currentPort; $this->opData = array(); $this->status = ""; $this->documentation = false; // array of wsdl docs to import $this->import = array(); // parser vars $this->parser; $this->position; $this->depth; $this->depth_array = array(); // parse wsdl file if($wsdl != ""){ $this->debug("initial wsdl file: $wsdl"); $this->parseWSDL($wsdl); } // imports if(sizeof($this->import) > 0){ foreach($this->import as $ns => $url){ $this->debug("importing wsdl from $url"); $this->parseWSDL($url); } } } /** * parses the wsdl document * * @param string $wsdl path or URL * @access private */ function parseWSDL($wsdl=""){ // parse wsdl file if($wsdl != ""){ $this->debug("getting $wsdl"); if ($fp = @fopen($wsdl,"r")) { while($data = fread($fp, 32768)) { $wsdl_string .= $data; } fclose($fp); } else { $this->setError("bad path to WSDL file."); return false; } // Create an XML parser. $this->parser = xml_parser_create(); // 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); // 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"); //xml_set_default_handler($this->parser, "default_handler"); // Parse the XML file. if(!xml_parse($this->parser,$wsdl_string,true)){ // Display an error message. $errstr = sprintf("XML error on line %d: %s", xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)) ); $this->debug("XML parse error: $errstr"); $this->setError("Parser error: $errstr"); return false; } xml_parser_free($this->parser); } else{ $this->debug("no wsdl passed to parseWSDL()!!"); $this->setError("no wsdl passed to parseWSDL()!!"); return false; } // add new data to operation data foreach($this->bindings as $binding => $bindingData){ if(is_array($bindingData['operations'])){ foreach($bindingData['operations'] as $operation => $data){ $this->debug("post-parse data gathering for $operation"); $this->bindings[$binding]['operations'][$operation]['input'] = array_merge($this->bindings[$binding]['operations'][$operation]['input'],$this->portTypes[ $bindingData['portType'] ][$operation]['input']); $this->bindings[$binding]['operations'][$operation]['output'] = array_merge($this->bindings[$binding]['operations'][$operation]['output'],$this->portTypes[ $bindingData['portType'] ][$operation]['output']); $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; if($this->bindings[$binding]['operations'][$operation]['style'] == ''){ $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; } $this->bindings[$binding]['operations'][$operation]['transport'] = $bindingData['transport']; $this->bindings[$binding]['operations'][$operation]['documentation'] = $this->portTypes[ $bindingData['portType'] ][$operation]['documentation']; $this->bindings[$binding]['operations'][$operation]['endpoint'] = $bindingData['endpoint']; } } } return true; } /** * start-element handler * * @param string $parser XML parser object * @param string $name element name * @param string $attrs associative array of attributes * @access private */ function start_element($parser, $name, $attrs) { if($this->status == "schema" || ereg("schema$",$name)){ //$this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); $this->status = "schema"; $this->schemaStartElement($parser,$name,$attrs); } else { // 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; // get element prefix if(ereg(":",$name)){ // get ns prefix $prefix = substr($name,0,strpos($name,":")); // get unqualified name $name = substr(strstr($name,":"),1); } //$this->debug("name: $name, prefix: $prefix"); // loop through atts, logging ns declarations foreach($attrs as $key => $value){ // if ns declarations, add to class level array of valid namespaces if(ereg("^xmlns",$key)){ if($ns_prefix = substr(strrchr($key,":"),1)){ $this->namespaces[$ns_prefix] = $value; } else { $this->namespaces['ns'.(count($this->namespaces)+1)] = $value; } if($value == 'http://www.w3.org/2001/XMLSchema'){ $this->XMLSchemaVersion = $value; $this->namespaces['xsi'] = $value.'-instance'; } elseif($value == 'http://www.w3.org/1999/XMLSchema'){ $this->XMLSchemaVersion = $value; $this->namespaces['xsi'] = $value.'-instance'; } } } // find status, register data switch($this->status){ case 'message': if($name == 'part'){ if($attrs['type']){ //print "msg ".$this->currentMessage.": found part $attrs[name]: ".implode(',',$attrs)."
"; $this->messages[$this->currentMessage][$attrs['name']] = $this->expandQname($attrs['type']); //print "i've stored it as: ".$this->messages[$this->currentMessage][$attrs['name']]."
"; } if($attrs['element']){ $this->messages[$this->currentMessage][$attrs['name']] = $this->expandQname($attrs['element']); } } break; case 'portType': switch($name){ case 'operation': $this->currentPortOperation = $attrs["name"]; $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); $this->portTypes[$this->currentPortType][$attrs["name"]]["parameterOrder"] = $attrs["parameterOrder"]; break; case 'documentation': $this->documentation = true; break; // merge input/output data default: $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $this->getLocalPart($attrs['message']); break; } break; case 'binding': switch($name){ case 'binding': // get ns prefix if(isset($attrs['style'])){ $this->bindings[$this->currentBinding]['prefix'] = $prefix; } $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding],$attrs); break; case 'header': $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; break; case 'operation': if($attrs['soapAction'] || $attrs['style']){ $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; } elseif($attrs['name']) { $this->currentOperation = $attrs['name']; $this->debug("current binding operation: $this->currentOperation"); $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = $this->bindings[$this->currentBinding]['endpoint']; } break; case 'input': $this->opStatus = 'input'; break; case 'output': $this->opStatus = 'output'; break; case 'body': $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus],$attrs); break; } break; case "service": switch($name){ case "port": $this->currentPort = $attrs['name']; $this->debug("current port: $this->currentPort"); $this->ports[$this->currentPort]['binding'] = substr(strstr($attrs['binding'],":"),1); break; case "address": $this->ports[$this->currentPort]['location'] = $attrs['location']; $this->ports[$this->currentPort]['bindingType'] = $this->getNamespaceFromPrefix($prefix); $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $this->getNamespaceFromPrefix($prefix); $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; //echo "port $this->currentPort, has binding ".$this->ports[$this->currentPort]['binding']." and endpoint ".$attrs['location']."
"; break; } break; } // set status switch($name){ case "import": if(isset($attrs['location'])){ $this->import[$attrs['namespace']] = $attrs['location']; } break; case "types": $this->status = "schema"; break; case "message": $this->status = "message"; $this->messages[$attrs["name"]] = array(); $this->currentMessage = $attrs["name"]; break; case "portType": $this->status = "portType"; $this->portTypes[$attrs["name"]] = array(); $this->currentPortType = $attrs["name"]; break; case "binding": if(isset($attrs['name'])){ // get binding name if(ereg(":",$attrs['name'])){ $this->currentBinding = substr(strstr($attrs['name'],":"),1); $prefix = substr($name,0,strpos($attrs['name'],":")); } else { $this->currentBinding = $attrs['name']; } $this->status = "binding"; $this->bindings[$this->currentBinding]['portType'] = substr(strstr($attrs['type'],":"),1); $this->debug("current binding: $this->currentBinding of portType: ".$attrs['type']); } break; case "service": $this->serviceName = $attrs["name"]; $this->status = "service"; break; case "definitions": foreach ($attrs as $name=>$value) { $this->wsdl_info[$name]=$value; } break; } } } /** * end-element handler * * @param string $parser XML parser object * @param string $name element name * @access private */ function end_element($parser, $name) { // unset schema status if(ereg('types$',$name) || ereg('schema$',$name)){ $this->status = ""; } if($this->status == 'schema'){ $this->schemaEndElement($parser, $name); } else { // position of current element is equal to the last value left in depth_array for my depth $pos = $this->depth_array[$this->depth]; // bring depth down a notch $this->depth--; } // end documentation if($this->documentation){ $this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; $this->documentation = false; } } /** * element content handler * * @param string $parser XML parser object * @param string $data element content * @access private */ function character_data($parser, $data){ $pos = $this->depth_array[$this->depth]; $this->message[$pos]["cdata"] .= $data; if($this->documentation){ $this->documentation .= $data; } } function getBindingData($binding){ if(is_array($this->bindings[$binding])){ return $this->bindings[$binding]; } } function getMessageData($operation,$portType,$msgType){ $name = $this->opData[$operation][$msgType]['message']; $this->debug( "getting msgData for $name, using $operation,$portType,$msgType
" ); return $this->messages[$name]; } /** * returns an assoc array of operation names => operation data * NOTE: currently only supports multiple services of differing binding types * This method needs some work * * @param string $bindingType eg: soap, smtp, dime (only soap is currently supported) * @return array * @access public */ function getOperations($bindingType = "soap"){ if($bindingType == "soap"){ $bindingType = "http://schemas.xmlsoap.org/wsdl/soap/"; } // loop thru ports foreach($this->ports as $port => $portData){ // binding type of port matches parameter if($portData['bindingType'] == $bindingType){ // get binding return $this->bindings[ $portData['binding'] ]['operations']; } } return array(); } /** * returns an associative array of data necessary for calling an operation * * @param string $operation, name of operation * @param string $bindingType, type of binding eg: soap * @return array * @access public */ function getOperationData($operation,$bindingType="soap"){ if($bindingType == "soap"){ $bindingType = "http://schemas.xmlsoap.org/wsdl/soap/"; } // loop thru ports foreach($this->ports as $port => $portData){ // binding type of port matches parameter if($portData['bindingType'] == $bindingType){ // get binding foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData){ if($operation == $bOperation){ return $opData; } } } } } /** * serialize the parsed wsdl * * @return string, serialization of WSDL * @access public */ function serialize(){ $xml = "namespaces as $k => $v){ $xml .= " xmlns:$k=\"$v\""; } $xml .= ">"; // imports if(sizeof($this->import) > 0){ foreach($this->import as $ns => $url){ $xml .= "\n"; } } // types if($this->schema){ $xml .= ""; //$xml .= $this->serializeSchema(); $xml .= ""; } // messages if(count($this->messages) >= 1){ foreach($this->messages as $msgName => $msgParts){ $xml .= ""; foreach($msgParts as $partName => $partType){ $xml .= ""; } $xml .= ""; } } // portTypes if(count($this->portTypes) >= 1){ foreach($this->portTypes as $portTypeName => $portOperations){ $xml .= ""; foreach($portOperations as $portOperation => $parameterOrder){ $xml .= ""; foreach($this->portTypes[$portTypeName][$portOperation] as $name => $attrs){ $xml .= "<$name"; if(is_array($attrs)){ foreach($attrs as $k => $v){ $xml .= " $k=\"$v\""; } } $xml .= "/>"; } $xml .= ""; } $xml .= ""; } } // bindings if(count($this->bindings) >= 1){ foreach($this->bindings as $bindingName => $attrs){ $xml .= ""; $xml .= ""; foreach($attrs["operations"] as $opName => $opParts){ $xml .= ""; $xml .= ""; $xml .= ""; $xml .= ""; $xml .= ""; $xml .= ""; $xml .= ""; $xml .= ""; $xml .= ""; } $xml .= ""; } } // services $xml .= "serviceName\">"; if(count($this->ports) >= 1){ foreach($this->ports as $pName => $attrs){ $xml .= ""; $xml .= "soap:address location=\"".$attrs["location"]."\"/>"; $xml .= ""; } } $xml .= ""; return $xml.""; } /** * serialize a PHP value according to a WSDL message definition * * TODO * - only serialize namespaces used in the message * - multi-ref serialization * - validate PHP values against type definitions, return errors if invalid * - probably more stuff :) * - implement 'out' functionality or write new function for 'out' parameters * * @param string type name * @param mixed param value * @return mixed new param or false if initial value didn't validate */ function serializeRPCParameters($operation,$direction,$parameters){ if($direction != 'input' && $direction != 'output'){ $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); return false; } if(!$opData = $this->getOperationData($operation)){ return false; } $this->debug( "in serializeRPCParameters with xml schema version $this->XMLSchemaVersion"); // set input params if(sizeof($opData[$direction]['parts']) > 0){ foreach($opData[$direction]['parts'] as $name => $type){ $xml .= $this->serializeType($name,$type,array_shift($parameters)); } } return $xml; } /** * serializes a PHP value according a given type definition * * @param string $name, name of type * @param string $type, type of type, heh * @param mixed $value, a native PHP value * @return string serialization * @access public */ function serializeType($name,$type,$value){ $this->debug("in serializeType: $name, $type, $value"); if(strpos($type,':')){ $uqType = substr($type,strrpos($type,":")+1); $ns = substr($type,0,strrpos($type,":")); $this->debug("got a prefixed type: $uqType, $ns"); if($ns == $this->XMLSchemaVersion){ if($uqType == 'boolean' && !$value){ $value = 0; } elseif($uqType == 'boolean'){ $value = 1; } if($uqType == 'string' && $this->charencoding){ $value = htmlspecialchars($value); } // it's a scalar return "<$name xsi:type=\"".$this->getPrefixFromNamespace($this->XMLSchemaVersion).":$uqType\">$value\n"; } } else { $uqType = $type; } $typeDef = $this->getTypeDef($uqType); $phpType = $typeDef['phpType']; $this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: ".$typeDef['arrayType']); // if php type == struct, map value to the element names if($phpType == "struct"){ $xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace($ns).":$uqType\">\n"; if(is_array($this->complexTypes[$uqType]["elements"])){ foreach($this->complexTypes[$uqType]["elements"] as $eName => $attrs){ // get value if(isset($value[$eName])){ $v = $value[$eName]; } elseif(is_array($value)) { $v = array_shift($value); } if(!isset($attrs['type'])){ $xml .= $this->serializeType($eName,$attrs['name'],$v); } else { $this->debug("calling serialize_val() for $eName, $v, ".$this->getLocalPart($attrs['type'])); $xml .= $this->serialize_val($v,$eName,$this->getLocalPart($attrs['type']),null,$this->getNamespaceFromPrefix($this->getPrefix($attrs['type']))); } } } $xml .= "\n"; } elseif($phpType == "array"){ $rows = sizeof($value); if($typeDef['multidimensional']){ $nv = array(); foreach($value as $v){ $cols = ','.sizeof($v); $nv = array_merge($nv,$v); } $value = $nv; } if(is_array($value) && sizeof($value) >= 1){ foreach($value as $k => $v){ if(strpos($typeDef['arrayType'],':')){ $contents .= $this->serializeType('item',$typeDef['arrayType'],$v); } else { $contents .= $this->serialize_val($v,'item',$typeDef['arrayType'],null,$this->XMLSchemaVersion); } } } $xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').":Array\" ". $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .":arrayType=\"" .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">\n" .$contents ."\n"; } return $xml; } } ?> * @version v 0.051 * @access public */ class soap_parser extends nusoap_base { /** * constructor * * @param string $xml SOAP message * @param string $encoding character encoding scheme of message * @access public */ function soap_parser($xml,$encoding="UTF-8",$method=""){ $this->xml = $xml; $this->xml_encoding = $encoding; $this->method = $method; $this->root_struct = ""; $this->root_struct_name = ""; $this->root_header = ""; // determines where in the message we are (envelope,header,body,method) $this->status = ""; $this->position = 0; $this->depth = 0; $this->default_namespace = ""; $this->namespaces = array(); $this->message = array(); $this->fault = false; $this->fault_code = ""; $this->fault_str = ""; $this->fault_detail = ""; $this->errstr = ""; $this->depth_array = array(); $this->debug_flag = true; $this->debug_str = ""; $this->soapresponse = NULL; $this->responseHeaders = ""; // for multiref parsing: // array of id => pos $this->ids = array(); // array of id => hrefs => pos $this->multirefs = array(); $this->entities = array ( "&" => "&", "<" => "<", ">" => ">", "'" => "'", '"' => """ ); // Check whether content has been read. if(!empty($xml)){ $this->debug("Entering soap_parser()"); // Create an XML parser. $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); // Set the object for the parser. // old code modified by JeanLuc: xml_set_object($this->parser, &$this); 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"); //xml_set_default_handler($this->parser, "default_handler"); // Parse the XML file. if(!xml_parse($this->parser,$xml,true)){ // Display an error message. $err = sprintf("XML error on line %d: %s", xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser))); $this->debug("parse error: $err"); $this->errstr = $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 != ""){ $this->responseHeaders = $this->message[$this->root_header]['result']; } } xml_parser_free($this->parser); } else { $this->debug("xml was empty, didn't parse!"); $this->errstr = "xml was empty, didn't parse!"; } } /** * start-element handler * * @param string $parser XML parser object * @param string $name element name * @param string $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]["pos"] = $pos; // 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->root_header = $pos; $this->status = "header"; } elseif($name == "Body"){ $this->status = "body"; $this->body_position = $pos; // set method } elseif($this->status == "body" && $pos == ($this->body_position+1)){ //if($name == $this->method."Response" || $name == $this->method || $name == "Fault"){ $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 $pos"); //} } // set my status $this->message[$pos]["status"] = $this->status; // set name $this->message[$pos]["name"] = htmlspecialchars($name); // set attrs $this->message[$pos]["attrs"] = $attrs; // get namespace if($prefix){ $this->message[$pos]["namespace"] = $this->namespaces[$prefix]; $this->default_namespace = $this->namespaces[$prefix]; } else { $this->message[$pos]["namespace"] = $this->default_namespace; } // loop through atts, logging ns and type declarations foreach($attrs as $key => $value){ // if ns declarations, add to class level array of valid namespaces if(strpos($key,'xmlns:')){ $prefix = substr(strrchr($key,":"),1); if(ereg('^http://www.w3.org/[0-9]{4}/XMLSchema$',$value)){ global $XMLSchemaVersion,$namespaces; $XMLSchemaVersion = $value; $namespaces["xsd"] = $XMLSchemaVersion; $namespaces["xsi"] = $XMLSchemaVersion."-instance"; } $this->namespaces[substr(strrchr($key,":"),1)] = $value; // set method namespace if($name == $this->root_struct_name){ $this->methodNamespace = $value; } // if it's a type declaration, set type } elseif(strpos($key,":type")){ $this->message[$pos]["type"] = substr(strrchr($value,":"),1); $this->message[$pos]["typePrefix"] = substr($value,0,strpos($key,":")-1); // should do something here with the namespace of specified type? } elseif(strpos($key,":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]['arraySize'] = $regs[3]; $this->message[$pos]['arrayCols'] = $regs[4]; } } // log id if($key == "id"){ $this->ids[$value] = $pos; } // root if(strpos($key,":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"); } } } /** * end-element handler * * @param string $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]; // bring depth down a notch $this->depth--; // build to native type if($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]; } elseif($this->message[$pos]['children'] != ""){ $this->message[$pos]['result'] = $this->buildVal($pos); } else { $this->message[$pos]['result'] = $this->message[$pos]['cdata']; } } // switch status if($pos == $this->root_struct){ $this->status = "body"; } elseif(eregi(":Body",$name)){ $this->status = "header"; } elseif(eregi(":Header",$name)){ $this->status = "envelope"; } elseif(eregi(":Envelope",$name)){ // resolve hrefs/ids if(sizeof($this->multirefs) > 0){ foreach($this->multirefs as $id => $hrefs){ $this->debug("resolving multirefs for id: $id"); foreach($hrefs as $refPos => $ref){ $this->debug("resolving href at pos $refPos"); $this->multirefs[$id][$refPos] = $this->buildval($this->ids[$id]); } } } } // set parent back to my parent $this->parent = $this->message[$pos]["parent"]; } /** * element content handler * * @param string $parser XML parser object * @param string $data element content * @access private */ function character_data($parser, $data){ $pos = $this->depth_array[$this->depth]; $this->message[$pos]["cdata"] .= $data; } /** * get the parsed message * * @return object SOAPx4 soap_val object * @access public */ function get_response(){ return $this->soapresponse; } /** * get the parsed headers * * @return mixed object SOAPx4 soapval object or empty if no headers * @access public */ function getHeaders(){ return $this->responseHeaders; } /** * decodes entities * * @param string $text string to translate * @access private */ function decode_entities($text){ foreach($this->entities as $entity => $encoded){ $text = str_replace($encoded,$entity,$text); } return $text; } /** * builds response structures for compound values (arrays/structs) * * @param string $pos position in node tree * @access private */ function buildVal($pos){ // build self $this->debug("inside buildVal() for ".$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]["type"]); // if there are children... if($this->message[$pos]["children"] != ""){ $children = explode("|",$this->message[$pos]["children"]); array_shift($children); // knock off empty // loop thru them, getting params foreach($children as $child_pos){ // md array if($this->message[$pos]['arrayCols']){ $this->debug("got an MD array element: $r, $c"); $params[$r][] = $this->message[$child_pos]['result']; $c++; if($c == $this->message[$pos]['arrayCols']){ $c = 0; $r++; } } elseif($this->message[$pos]['type'] == 'array'){ $params[] =& $this->message[$child_pos]['result']; } else { $params[$this->message[$child_pos]["name"]] =& $this->message[$child_pos]['result']; } } return is_array($params) ? $params : array(); } else { //return $this->message[$pos]['cdata']; return strtr($this->message[$pos]['cdata'],array_flip($this->entities)); } } /** * for building SOAP header values * * @param string $pos position in node tree * @access private */ function buildSoapVal($pos){ // if there are children... if($this->message[$pos]["children"] != ""){ $children = explode("|",$this->message[$pos]["children"]); // loop thru them, getting params foreach($children as $c => $child_pos){ if($this->message[$child_pos]["type"] != NULL) { $this->debug("adding ".$this->message[$child_pos]["name"].", pos: $child_pos"); $params[] = $this->message[$child_pos]['result']; } } } // build self $this->debug("building ".$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]["type"]); if($params){ return new soapval($this->message[$pos]["name"], $this->message[$pos]["type"] , $params); } else { return new soapval($this->message[$pos]["name"], $this->message[$pos]["type"] , $this->message[$pos]["cdata"]); } } } ?> call( string methodname [ ,array parameters] ); * * // bye bye client * unset($soapclient); * * @author Dietrich Ayala * @version v 0.6 * @access public */ class soapclient extends nusoap_base { var $username; var $password; var $requestHeaders = false; var $responseHeaders; var $endpoint; var $portName; var $error_str = false; /** * fault related variables * * @var fault * @var faultcode * @var faultstring * @var faultdetail * @access public */ var $fault, $faultcode, $faultstring, $faultdetail; /** * constructor * * @param string $endpoint SOAP server or WSDL URL * @param string $wsdl optional, set to true if using WSDL * @param int $portName optional portName in WSDL document * @access public */ function soapclient($endpoint,$wsdl="",$portName=""){ $this->endpoint = $endpoint; $this->portName = $portName; // make values if($wsdl != ""){ $this->endpointType = "wsdl"; $this->wsdlFile = $this->endpoint; if($portName != ""){ $this->portName = $portName; } // instantiate wsdl object and parse wsdl file $this->debug("instantiating wsdl class with doc: $endpoint"); $this->wsdl = new wsdl($this->wsdlFile); // catch errors if($errstr = $this->wsdl->getError()){ $this->debug("got wsdl error: $errstr"); $this->debug("wsdl debug: \n".$this->wsdl->debug_str); $this->setError('wsdl error: '.$errstr); } elseif($this->operations = $this->wsdl->getOperations()){ $this->debug( "got ".count($this->operations)." operations from wsdl $this->wsdlFile
"); } } } /** * calls method, returns PHP native type * * @param string $method SOAP server URL or path * @param array $params array of parameters, can be associative or not * @param string $namespace optional method namespace * @param string $soapAction optional SOAPAction value * @param boolean $headers optional array of soapval objects for headers * @return mixed * @access public */ function call($operation,$params=array(),$namespace="",$soapAction="",$headers=false){ $this->operation = $operation; $this->fault = false; $this->error_str = ""; $this->request = ""; $this->response = ""; $this->faultstring = ""; $this->faultcode = ""; $this->opData = array(); // if wsdl, get operation data and process parameters if($this->endpointType == "wsdl" && $opData = $this->getOperationData($operation)){ $this->opData = $opData; $soapAction = $opData["soapAction"]; $this->endpoint = $opData['endpoint']; $this->portName = $opData['portName']; $namespace = $opData['input']['namespace']; $style = $opData['style']; // add ns to ns array if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ $this->wsdl->namespaces['galactivism'] = $namespace; } // serialize payload if($style == 'rpc'){ $payload .= "<".$this->wsdl->getPrefixFromNamespace($namespace).":$operation>\n". $this->wsdl->serializeRPCParameters($operation,'input',$params). "wsdl->getPrefixFromNamespace($namespace).":$operation>\n"; } elseif($opData['input']['use'] == 'literal') { $payload .= array_shift($params); } // serialize envelope $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$this->wsdl->usedNamespaces); $this->debug("wsdl debug: \n".$this->wsdl->debug_str); } elseif($this->endpointType == "wsdl") { $this->setError( "operation $operation not present."); $this->debug("operation '$operation' not present."); $this->debug("wsdl debug: \n".$this->wsdl->debug_str); return false; // no wsdl } else { // make message if(!$style){ $style = 'rpc'; } // add ns to ns array if($namespace != ''){ $this->namespaces['galactivism'] = $namespace; } // serialize envelope foreach($params as $k => $v){ $payload .= $this->serialize_val($v,$k); } // old code modified by JeanLuc: $payload = "\n".$payload."\n"; $payload = "<$namespace:$operation>\n".$payload."\n"; // New code $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders); } $this->debug("endpoint: $this->endpoint, soapAction: $soapAction, namespace: $namespace"); // send $this->debug("sending msg (len: ".strlen($soapmsg).") w/ soapaction '$soapAction'..."); $return = $this->send($soapmsg,$soapAction); if($errstr = $this->getError()){ $this->debug("Error: $errstr"); return false; } else { $this->return = $return; $this->debug($dbg."sent message successfully and got a(n) ".gettype($return)." back"); // fault? if(is_array($return) && $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
"); } return $return; } else { // array of return values if(is_array($return)){ // multiple 'out' parameters if(sizeof($return) > 1){ return $return; } // single 'out' parameter return array_shift($return); // nothing returned (ie, echoVoid) } else { return ""; } } } } /** * 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(isset($this->operations[$operation])){ return $this->operations[$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 timeout in seconds * @return mixed native PHP types. * @access public */ function send($msg, $soapaction = "", $timeout=0) { // detect transport switch(true){ // http(s) case ereg('^http',$this->endpoint): $this->debug('transporting via HTTP'); //require_once('file:///C|/Documents%20and%20Settings/Jean-Luc/Bureau/nusoap-0.6.1/class.soap_transport_http.php'); $http = new soap_transport_http($this->endpoint); $http->setSOAPAction($soapaction); if($this->proxyhost && $this->proxyport){ $http->setProxy($this->proxyhost,$this->proxyport); } $this->debug('sending message, length: '.strlen($msg)); if(ereg('^http:',$this->endpoint)){ $response = $http->send($msg,$timeout); } elseif(ereg('^https',$this->endpoint)){ if (!extension_loaded('curl')) { $this->setError('CURL Extension is required for HTTPS'); return false; } $response = $http->sendHTTPS($msg,$timeout); } $this->debug("transport debug data...\n".$http->debug_str); $this->request = $http->outgoing_payload; $this->response = $http->incoming_payload; if($err = $http->getError()){ $this->setError("HTTP Error: $err"); return false; } $this->debug('got response, length: '.strlen($response)); return $this->parseResponse($response); break; default: $this->setError('no transport found, or selected transport is not yet supported!'); return false; break; } } /** * processes SOAP message returned from server * * @param string unprocessed response data from server * @return object SOAPx4 soapval object * @access public */ function parseResponse($data) { $this->debug("Entering parseResponse(), about to create soap_parser instance"); $parser = new soap_parser($data,$this->xml_encoding,$this->operation); // 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 decoded message $return = $parser->get_response(); // add parser debug data to our debug $this->debug($parser->debug_str); // destroy the parser object unset($parser); // return decode message return $return; } } /** * set the SOAP headers * * @param $headers string XML * @access public */ function setHeaders($headers){ $this->requestHeaders = $headers; } /** * get the response headers * * @return mixed object SOAPx4 soapval object or empty if no headers * @access public */ function getHeaders(){ if($this->responseHeaders != "") { return $this->responseHeaders; } } /** * set proxy info here * * @param string $proxyhost * @param string $proxyport * @access public */ function setHTTPProxy($proxyhost, $proxyport) { $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; } /** * if authenticating, set user credentials here * * @param string $username * @param string $pword * @access public */ function setCredentials($username, $pword) { $this->user = $username; $this->pass = $pword; } /** * dynamically creates proxy class, allowing user to directly call methods from wsdl * * @return object soap_proxy object * @access public */ function getProxy(){ foreach($this->operations as $operation => $opData){ if($operation != ""){ // create param string if(sizeof($opData['input']['parts']) > 0){ foreach($opData["input"]["parts"] as $name => $type){ $paramStr .= "\$$name,"; } $paramStr = substr($paramStr,0,strlen($paramStr)-1); } $evalStr .= " function $operation ($paramStr){ // load params into array \$params = array($paramStr); return \$this->call('$operation',\$params,'".$opData['namespace']."','".$opData['soapAction']."'); } "; unset($paramStr); } } $evalStr = " class soap_proxy extends soapclient { $evalStr } "; //print "proxy class:
$evalStr
"; // eval the class eval($evalStr); // instantiate proxy object $proxy = new soap_proxy(""); // 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; return $proxy; } } ?>