+<?php
+
+/*
+
+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
+
+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
+
+*/
+
+/* load classes
+
+// necessary classes
+require_once('class.soapclient.php');
+require_once('class.soap_val.php');
+require_once('class.soap_parser.php');
+require_once('class.soap_fault.php');
+
+// transport classes
+require_once('class.soap_transport_http.php');
+
+// optional add-on classes
+require_once('class.xmlschema.php');
+require_once('class.wsdl.php');
+
+// server class
+require_once('class.soap_server.php');*/
+
+
+// make errors handle properly in windows (thx, thong@xmethods.com)
+error_reporting(2039);
+
+/**
+* set schema version
+*
+* @var XMLSchemaVersion
+* @access public
+*/
+$XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
+
+/**
+* load namespace uris into an array of uri => 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 <dietricha@ganx4.com>
+* @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<br>";
+ // 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</$name>\n";
+ break;
+ case (is_int($val) || is_long($val) || $type == 'int'):
+ $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":int\"$atts>$val</$name>\n";
+ break;
+ case (is_float($val)|| is_double($val) || $type == 'float'):
+ $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":float\"$atts>$val</$name>\n";
+ break;
+ case (is_string($val) || $type == 'string'):
+ if($this->charencoding){
+ $val = htmlspecialchars($val);
+ }
+ $xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":string\"$atts>$val</$name>\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."</$name>\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 .= "</$name>\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 = "<SOAP-ENV:Header>\n".$headers."</SOAP-ENV:Header>\n";
+ }
+ // serialize envelope
+ return
+ "<?xml version=\"1.0\"?".">\n".
+ "<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"$ns_string>\n".
+ $headers.
+ "<SOAP-ENV:Body>\n".
+ $body.
+ "</SOAP-ENV:Body>\n".
+ "</SOAP-ENV:Envelope>\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;
+ }
+}
+
+
+?>
+<?php
+
+/**
+* soap_fault class, allows for creation of faults
+* mainly used for returning faults from deployed functions
+* in a server instance.
+* @access public
+*/
+class soap_fault extends nusoap_base {
+
+ var $faultcode;
+ var $faultactor;
+ var $faultstring;
+ var $faultdetail;
+
+ /**
+ * constructor
+ *
+ * @param string $faultcode
+ * @param string $faultactor (client | server)
+ * @param string $faultstring
+ * @param string $faultdetail
+ */
+ function soap_fault($faultcode,$faultactor,$faultstring='',$faultdetail=''){
+ $this->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 =
+ "<?xml version=\"1.0\"?".">\n".
+ "<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"$ns_string>\n".
+ "<SOAP-ENV:Body>\n".
+ "<SOAP-ENV:Fault>\n".
+ "<faultcode>$this->faultcode</faultcode>\n".
+ "<faultactor>$this->faultactor</faultactor>\n".
+ "<faultstring>$this->faultstring</faultstring>\n".
+ "<faultdetail>$this->faultdetail</faultdetail>\n".
+ "</SOAP-ENV:Fault>\n".
+ "</SOAP-ENV:Body>\n".
+ "</SOAP-ENV:Envelope>\n";
+ return $return_msg;
+ }
+}
+
+?><?
+/*
+
+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
+
+*/
+
+/**
+* parses an XML Schema, allows access to it's data, other utility methods
+* no validation... yet.
+* very experimental and limited. As is discussed on XML-DEV, I'm one of the people
+* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
+* tutorials I refer to :)
+*
+* @author Dietrich Ayala <dietricha@ganx4.com>
+* @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 .= "<element ref=\"$element\"/>\n";
+ }
+ }
+ // serialize attributes
+ if(count($attrs["attrs"]) > 0){
+ foreach($attrs["attrs"] as $attr => $aParts){
+ $contentStr .= "<attribute ref=\"$attr\"/>\n";
+ }
+ }
+
+ // if restriction
+ if($attrs["restrictionBase"]){
+ $contentStr = "<$schemaPrefix:restriction base=\"".$attrs["restrictionBase"]."\">\n".
+ $contentStr."</$schemaPrefix:restriction>\n";
+ }
+ if($attrs["complexContent"]){
+ $contentStr = "<$schemaPrefix:complexContent>\n".
+ $contentStr."</$schemaPrefix:complexContent>\n";
+ } elseif($attrs["sequence"]){
+ $contentStr = "<$schemaPrefix:sequence>\n".
+ $contentStr."</$schemaPrefix:sequence>\n";
+ } elseif($attrs["all"]){
+ $contentStr = "<$schemaPrefix:all>\n".
+ $contentStr."</$schemaPrefix:all>\n";
+ }
+ if($attrs['element']){
+ if($contentStr != ""){
+ $contentStr = "<$schemaPrefix:element name=\"$typeName\">\n"."<$schemaPrefix:complexType>\n".
+ $contentStr."</$schemaPrefix:complexType>\n"."</$schemaPrefix:element>\n";
+ } else {
+ $contentStr = "<$schemaPrefix:element name=\"$typeName\">\n"."<$schemaPrefix:complexType/>\n".
+ "</$schemaPrefix:element>\n";
+ }
+ } else {
+ if($contentStr != ""){
+ $contentStr = "<$schemaPrefix:complexType name=\"$typeName\">\n".
+ $contentStr."</$schemaPrefix:complexType>\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."</$schemaPrefix:schema>\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<br>";
+ return $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 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<br>";
+ 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 .= "</$type>\n";
+ } elseif($typeDef['typeClass'] == 'element') {
+ $str .= "></$type>\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 .= '<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;
+ }
+}
+
+?>
+<?php
+
+/*
+
+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
+
+*/
+
+/**
+* for creating serializable abstractions of native PHP types
+* NOTE: this is only really used when WSDL is not available.
+*
+* @author Dietrich Ayala <dietricha@ganx4.com>
+* @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;
+ }
+}
+
+?>
+<?php
+/*
+
+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
+
+*/
+
+/**
+* transport class for sending/receiving data via HTTP and HTTPS
+* NOTE: PHP must be compiled with the CURL extension for HTTPS support
+* HTTPS support is experimental!
+*
+* @access public
+*/
+class soap_transport_http extends nusoap_base {
+
+ var $username;
+ var $password;
+ var $url;
+ /**
+ * constructor
+ */
+ function soap_transport_http($url){
+ $this->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: <xmp>$data</xmp>";
+ // 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)."<br>";
+
+ if($err != ''){
+ foreach(curl_getinfo($ch) as $k => $v){
+ $err .= "$k: $v<br>";
+ }
+ $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;
+ }
+}
+
+?>
+<?php
+/*
+
+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
+
+*/
+
+/**
+*
+* soap_server allows the user to create a SOAP server
+* that is capable of receiving messages and returning responses
+*
+* NOTE: WSDL functionality is experimental
+*
+* @author Dietrich Ayala <dietricha@ganx4.com>
+* @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 .= "<!--\n$this->debug_str\n-->";
+ // 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:<br>$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."</".$this->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 .= "
+ <html><head><title>NuSOAP: ".$this->wsdl->serviceName."</title>
+ <style type=\"text/css\">
+ body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
+ p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
+ pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
+ ul { margin-top: 10px; margin-left: 20px; }
+ li { list-style-type: none; margin-top: 10px; color: #000000; }
+ .content{
+ margin-left: 0px; padding-bottom: 2em; }
+ .nav {
+ padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
+ margin-top: 10px; margin-left: 0px; color: #000000;
+ background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
+ .title {
+ font-family: arial; font-size: 26px; color: #ffffff;
+ background-color: #999999; width: 105%; margin-left: 0px;
+ padding-top: 10px; padding-bottom: 10px; padding-left: 15px;}
+ .hidden {
+ position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
+ font-family: arial; overflow: hidden; width: 600;
+ padding: 20px; font-size: 10px; background-color: #999999;
+ layer-background-color:#FFFFFF; }
+ a,a:active { color: charcoal; font-weight: bold; }
+ a:visited { color: #666666; font-weight: bold; }
+ a:hover { color: cc3300; font-weight: bold; }
+ </style>
+ <script language=\"JavaScript\" type=\"text/javascript\">
+ <!--
+ // POP-UP CAPTIONS...
+ function lib_bwcheck(){ //Browsercheck (needed)
+ this.ver=navigator.appVersion
+ this.agent=navigator.userAgent
+ this.dom=document.getElementById?1:0
+ this.opera5=this.agent.indexOf(\"Opera 5\")>-1
+ this.ie5=(this.ver.indexOf(\"MSIE 5\")>-1 && this.dom && !this.opera5)?1:0;
+ this.ie6=(this.ver.indexOf(\"MSIE 6\")>-1 && this.dom && !this.opera5)?1:0;
+ this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
+ this.ie=this.ie4||this.ie5||this.ie6
+ this.mac=this.agent.indexOf(\"Mac\")>-1
+ this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
+ this.ns4=(document.layers && !this.dom)?1:0;
+ this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
+ return this
+ }
+ var bw = new lib_bwcheck()
+ //Makes crossbrowser object.
+ function makeObj(obj){
+ this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
+ if(!this.evnt) return false
+ this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
+ this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
+ this.writeIt=b_writeIt;
+ return this
+ }
+ // A unit of measure that will be added when setting the position of a layer.
+ //var px = bw.ns4||window.opera?\"\":\"px\";
+ function b_writeIt(text){
+ if (bw.ns4){this.wref.write(text);this.wref.close()}
+ else this.wref.innerHTML = text
+ }
+ //Shows the messages
+ var oDesc;
+ function popup(divid){
+ if(oDesc = new makeObj(divid)){
+ oDesc.css.visibility = \"visible\"
+ }
+ }
+ function popout(){ // Hides message
+ if(oDesc) oDesc.css.visibility = \"hidden\"
+ }
+ //-->
+ </script>
+ </head>
+ <body>
+ <div class='content'>
+ <br><br>
+ <div class='title'>".$this->wsdl->serviceName."</div>
+ <div class='nav'>
+ <p>View the <a href='$PHP_SELF?wsdl'>WSDL</a> for the service.
+ Click on an operation name to view it's details.</p>
+ <ul>
+ ";
+ foreach($this->wsdl->getOperations() as $op => $data){
+ $b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>";
+ // create hidden div
+ $b .= "<div id='$op' class='hidden'>
+ <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
+ foreach($data as $donnie => $marie){
+ if($donnie == 'input' || $donnie == 'output'){
+ $b .= "<font color='white'>".ucfirst($donnie).":</font><br>";
+ foreach($marie as $captain => $tenille){
+ if($captain == 'parts'){
+ $b .= " $captain:<br>";
+ foreach($tenille as $joanie => $chachi){
+ $b .= " $joanie: $chachi<br>";
+ }
+ } else {
+ $b .= " $captain: $tenille<br>";
+ }
+ }
+ } else {
+ $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
+ }
+ }
+ /*$b .= "<pre>".$this->formatDump(
+ $this->wsdl->serializeEnvelope(
+ $this->wsdl->serializeRPCParameters($op,array())))."</pre>";
+ $b .= "</div>";*/
+ }
+ $b .= "
+ <ul>
+ </div>
+ </div>
+ </body></html>";
+ 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/";
+ }
+}
+
+?>
+<?
+/*
+
+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
+
+*/
+
+/**
+* parses a WSDL file, allows access to it's data, other utility methods
+*
+* @author Dietrich Ayala <dietricha@ganx4.com>
+* @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)."<br>";
+ $this->messages[$this->currentMessage][$attrs['name']] = $this->expandQname($attrs['type']);
+ //print "i've stored it as: ".$this->messages[$this->currentMessage][$attrs['name']]."<br>";
+ }
+ 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']."<br>";
+ 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<br>" );
+ 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 = "<?xml version=\"1.0\"?><definitions";
+ foreach($this->namespaces as $k => $v){
+ $xml .= " xmlns:$k=\"$v\"";
+ }
+ $xml .= ">";
+
+ // imports
+ if(sizeof($this->import) > 0){
+ foreach($this->import as $ns => $url){
+ $xml .= "<import location=\"$url\" namespace=\"$ns\" />\n";
+ }
+ }
+
+ // types
+ if($this->schema){
+ $xml .= "<types>";
+ //$xml .= $this->serializeSchema();
+ $xml .= "</types>";
+ }
+
+ // messages
+ if(count($this->messages) >= 1){
+ foreach($this->messages as $msgName => $msgParts){
+ $xml .= "<message name=\"$msgName\">";
+ foreach($msgParts as $partName => $partType){
+ $xml .= "<part name=\"$partName\" type=\"$partType\" />";
+ }
+ $xml .= "</message>";
+ }
+ }
+ // portTypes
+ if(count($this->portTypes) >= 1){
+ foreach($this->portTypes as $portTypeName => $portOperations){
+ $xml .= "<portType name=\"$portTypeName\">";
+ foreach($portOperations as $portOperation => $parameterOrder){
+ $xml .= "<operation name=\"$portOperation\" parameterOrder=\"$parameterOrder\">";
+ foreach($this->portTypes[$portTypeName][$portOperation] as $name => $attrs){
+ $xml .= "<$name";
+ if(is_array($attrs)){
+ foreach($attrs as $k => $v){
+ $xml .= " $k=\"$v\"";
+ }
+ }
+ $xml .= "/>";
+ }
+ $xml .= "</operation>";
+ }
+ $xml .= "</portType>";
+ }
+ }
+ // bindings
+ if(count($this->bindings) >= 1){
+ foreach($this->bindings as $bindingName => $attrs){
+ $xml .= "<binding name=\"$msgName\" type=\"".$attrs["type"]."\">";
+ $xml .= "<soap:binding style=\"".$attrs["style"]."\" transport=\"".$attrs["transport"]."\"/>";
+ foreach($attrs["operations"] as $opName => $opParts){
+ $xml .= "<operation name=\"$opName\">";
+ $xml .= "<soap:operation soapAction=\"".$opParts["soapAction"]."\"/>";
+ $xml .= "<input>";
+ $xml .= "<soap:body use=\"".$opParts["input"]["use"]."\" namespace=\"".$opParts["input"]["namespace"]."\" encodingStyle=\"".$opParts["input"]["encodingStyle"]."\"/>";
+ $xml .= "</input>";
+ $xml .= "<output>";
+ $xml .= "<soap:body use=\"".$opParts["output"]["use"]."\" namespace=\"".$opParts["output"]["namespace"]."\" encodingStyle=\"".$opParts["output"]["encodingStyle"]."\"/>";
+ $xml .= "</output>";
+ $xml .= "</operation>";
+ }
+ $xml .= "</message>";
+ }
+ }
+ // services
+ $xml .= "<service name=\"$this->serviceName\">";
+ if(count($this->ports) >= 1){
+ foreach($this->ports as $pName => $attrs){
+ $xml .= "<port name=\"$pName\" binding=\"".$attrs["binding"]."\">";
+ $xml .= "soap:address location=\"".$attrs["location"]."\"/>";
+ $xml .= "</port>";
+ }
+ }
+ $xml .= "</service>";
+ return $xml."</definitions>";
+ }
+
+ /**
+ * 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</$name>\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 <all> 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 .= "</$name>\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
+ ."</$name>\n";
+ }
+ return $xml;
+ }
+}
+
+?>
+<?
+/*
+
+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
+
+*/
+
+/**
+*
+* soap_parser class parses SOAP XML messages
+*
+* @author Dietrich Ayala <dietricha@ganx4.com>
+* @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.
+ 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"]);
+ }
+ }
+}
+
+?>
+<?php
+
+/**
+*
+* soapclient higher level class for easy usage.
+*
+* usage:
+*
+* // instantiate client with server info
+* $soapclient = new soapclient( string path [ ,boolean wsdl] );
+*
+* // call method, get results
+* echo $soapclient->call( string methodname [ ,array parameters] );
+*
+* // bye bye client
+* unset($soapclient);
+*
+* @author Dietrich Ayala <dietricha@ganx4.com>
+* @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<br>");
+ }
+ }
+ }
+
+ /**
+ * 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).
+ "</".$this->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);
+ }
+ $payload = "<galactivism:$operation>\n".$payload."</galactivism:$operation>\n";
+ $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<br>");
+ }
+ 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('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:<pre>$evalStr</pre>";
+ // 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;
+ }
+}
+
+?>
\ No newline at end of file