diff --git a/thirdparty/pear/SOAP/Base.php b/thirdparty/pear/SOAP/Base.php new file mode 100644 index 0000000..78491dc --- /dev/null +++ b/thirdparty/pear/SOAP/Base.php @@ -0,0 +1,1231 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +/** + * SOAP_OBJECT_STRUCT makes PEAR::SOAP use objects for SOAP structures rather + * than arrays. This has been done to provide a closer match to php-soap. If + * the old behaviour is needed, set to false. The old behaviour is + * deprecated. + * + * @global bool $GLOBALS['SOAP_OBJECT_STRUCT'] + */ +$GLOBALS['SOAP_OBJECT_STRUCT'] = true; + +/** + * SOAP_RAW_CONVERT makes PEAR::SOAP attempt to determine what SOAP type a PHP + * string COULD be. This may result in slightly better interoperability when + * you are not using WSDL, and are being lazy and not using SOAP_Value to + * define types for your values. + * + * @global bool $GLOBALS['SOAP_RAW_CONVERT'] + */ +$GLOBALS['SOAP_RAW_CONVERT'] = false; + +require_once 'PEAR.php'; +require_once 'SOAP/Type/dateTime.php'; +require_once 'SOAP/Type/hexBinary.php'; + +// optional features +$GLOBALS['SOAP_options'] = array(); + +@include_once 'Mail/mimePart.php'; +@include_once 'Mail/mimeDecode.php'; +if (class_exists('Mail_mimePart')) { + $GLOBALS['SOAP_options']['Mime'] = 1; + define('MAIL_MIMEPART_CRLF', "\r\n"); +} + +@include_once 'Net/DIME.php'; +if (class_exists('Net_DIME_Message')) { + $GLOBALS['SOAP_options']['DIME'] = 1; +} + +/** + * Enable debugging information? + * + * @global bool $GLOBALS['SOAP_DEBUG'] + * @name $SOAP_DEBUG + */ +$GLOBALS['SOAP_DEBUG'] = false; + +if (!function_exists('version_compare') || + version_compare(phpversion(), '4.1', '<')) { + die("requires PHP 4.1 or higher\n"); +} +if (version_compare(phpversion(), '4.1', '>=') && + version_compare(phpversion(), '4.2', '<')) { + define('FLOAT', 'double'); +} else { + define('FLOAT', 'float'); +} + +if (!defined('INF')) { + define('INF', 1.8e307); +} +if (!defined('NAN')) { + define('NAN', 0.0); +} + +define('SOAP_LIBRARY_VERSION', '0.8.0RC4'); +define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.8.0RC4-devel'); + +// Set schema version. +define('SOAP_XML_SCHEMA_VERSION', 'http://www.w3.org/2001/XMLSchema'); +define('SOAP_XML_SCHEMA_INSTANCE', 'http://www.w3.org/2001/XMLSchema-instance'); +define('SOAP_XML_SCHEMA_1999', 'http://www.w3.org/1999/XMLSchema'); +define('SOAP_SCHEMA', 'http://schemas.xmlsoap.org/wsdl/soap/'); +define('SOAP_SCHEMA_ENCODING', 'http://schemas.xmlsoap.org/soap/encoding/'); +define('SOAP_ENVELOP', 'http://schemas.xmlsoap.org/soap/envelope/'); + +define('SCHEMA_DISCO', 'http://schemas.xmlsoap.org/disco/'); +define('SCHEMA_DISCO_SCL', 'http://schemas.xmlsoap.org/disco/scl/'); + +define('SCHEMA_SOAP', 'http://schemas.xmlsoap.org/wsdl/soap/'); +define('SCHEMA_SOAP_HTTP', 'http://schemas.xmlsoap.org/soap/http'); +define('SCHEMA_WSDL_HTTP', 'http://schemas.xmlsoap.org/wsdl/http/'); +define('SCHEMA_MIME', 'http://schemas.xmlsoap.org/wsdl/mime/'); +define('SCHEMA_WSDL', 'http://schemas.xmlsoap.org/wsdl/'); +define('SCHEMA_DIME', 'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/'); +define('SCHEMA_CONTENT', 'http://schemas.xmlsoap.org/ws/2002/04/content-type/'); +define('SCHEMA_REF', 'http://schemas.xmlsoap.org/ws/2002/04/reference/'); + +define('SOAP_DEFAULT_ENCODING', 'UTF-8'); + +class SOAP_Base_Object extends PEAR +{ + /** + * Store debugging information in $_debug_data? + * + * @see $debug_data, SOAP_Base + * @var boolean $_debug_flag + */ + var $_debug_flag = false; + + /** + * String containing debugging information if $_debug_flag is true. + * + * @access public + * @see $debug_flag, SOAP_Base + * @var string $_debug_data + */ + var $_debug_data = ''; + + /** + * Supported encodings, limited by XML extension. + * + * @var array $_encodings + */ + var $_encodings = array('ISO-8859-1', 'US-ASCII', 'UTF-8'); + + /** + * Fault code. + * + * @var string $_myfaultcode + */ + var $_myfaultcode = ''; + + /** + * Recent PEAR_Error object. + * + * @var PEAR_Error $fault + */ + var $fault = null; + + /** + * Constructor. + * + * @see $debug_data, _debug() + * + * @param string $faultcode Error code. + */ + function SOAP_Base_Object($faultcode = 'Client') + { + $this->_myfaultcode = $faultcode; + $this->_debug_flag = $GLOBALS['SOAP_DEBUG']; + parent::PEAR('SOAP_Fault'); + } + + /** + * Raises a SOAP error. + * + * Please refer to the SOAP definition for an impression of what a certain + * parameter stands for. + * + * Use $debug_flag to store errors to the member variable $debug_data + * + * @see $debug_flag, $debug_data, SOAP_Fault + * + * @param string|object $str Error message or object. + * @param string $detail Detailed error message. + * @param string $actorURI + * @param mixed $code + * @param mixed $mode + * @param mixed $options + * @param boolean $skipmsg + */ + function &_raiseSoapFault($str, $detail = '', $actorURI = '', $code = null, + $mode = null, $options = null, $skipmsg = false) + { + // Pass through previous faults. + $is_instance = isset($this); + if (is_object($str)) { + $fault =& $str; + } else { + if (!$code) { + $code = $is_instance ? $this->_myfaultcode : 'Client'; + } + $fault =& new SOAP_Fault($str, + $code, + $actorURI, + $detail, + $mode, + $options); + } + if ($is_instance) { + $this->fault =& $fault; + } + + return $fault; + } + + function __isfault() + { + return $this->fault != null; + } + + function &__getfault() + { + return $this->fault; + } + + /** + * Adds a string to the debug data. + * + * @param string $string Debugging message. + */ + function _debug($string) + { + if ($this->_debug_flag) { + $this->_debug_data .= get_class($this) . ': ' . + str_replace('>', ">\r\n", $string) . "\n"; + } + } + +} + +/** + * Common base class of all SOAP classes. + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + */ +class SOAP_Base extends SOAP_Base_Object +{ + var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema', + 'http://www.w3.org/1999/XMLSchema'); + var $_XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + // load types into typemap array + var $_typemap = array( + 'http://www.w3.org/2001/XMLSchema' => array( + 'string' => 'string', + 'boolean' => 'boolean', + 'float' => FLOAT, + 'double' => FLOAT, + 'decimal' => FLOAT, + 'duration' => 'integer', + 'dateTime' => 'string', + 'time' => 'string', + 'date' => 'string', + 'gYearMonth' => 'integer', + 'gYear' => 'integer', + 'gMonthDay' => 'integer', + 'gDay' => 'integer', + 'gMonth' => 'integer', + 'hexBinary' => 'string', + 'base64Binary' => 'string', + // derived datatypes + 'normalizedString' => 'string', + 'token' => 'string', + 'language' => 'string', + 'NMTOKEN' => 'string', + 'NMTOKENS' => 'string', + 'Name' => 'string', + 'NCName' => 'string', + 'ID' => 'string', + 'IDREF' => 'string', + 'IDREFS' => 'string', + 'ENTITY' => 'string', + 'ENTITIES' => 'string', + 'integer' => 'integer', + 'nonPositiveInteger' => 'integer', + 'negativeInteger' => 'integer', + 'long' => 'integer', + 'int' => 'integer', + 'short' => 'integer', + 'byte' => 'string', + 'nonNegativeInteger' => 'integer', + 'unsignedLong' => 'integer', + 'unsignedInt' => 'integer', + 'unsignedShort' => 'integer', + 'unsignedByte' => 'integer', + 'positiveInteger' => 'integer', + 'anyType' => 'string', + 'anyURI' => 'string', + 'QName' => 'string' + ), + 'http://www.w3.org/1999/XMLSchema' => array( + 'i4' => 'integer', + 'int' => 'integer', + 'boolean' => 'boolean', + 'string' => 'string', + 'double' => FLOAT, + 'float' => FLOAT, + 'dateTime' => 'string', + 'timeInstant' => 'string', + 'base64Binary' => 'string', + 'base64' => 'string', + 'ur-type' => 'string' + ), + 'http://schemas.xmlsoap.org/soap/encoding/' => array( + 'base64' => 'string', + 'array' => 'array', + 'Array' => 'array', + 'Struct' => 'array') + ); + + /** + * Default class name to use for decoded response objects. + * + * @var string $_defaultObjectClassname + */ + var $_defaultObjectClassname = 'stdClass'; + + // Load namespace URIs into an array of URI => prefix. + var $_namespaces; + var $_namespace; + + var $_xmlEntities = array('&' => '&', + '<' => '<', + '>' => '>', + "'" => ''', + '"' => '"'); + + var $_doconversion = false; + + var $__attachments = array(); + + var $_wsdl = null; + + /** + * True if we use section 5 encoding, or false if this is literal. + * + * @var boolean $_section5 + */ + var $_section5 = true; + + // Handle type to class mapping. + var $_auto_translation = false; + var $_type_translation = array(); + + /** + * Constructor. + * + * @see $debug_data, _debug() + * + * @param string $faultcode Error code. + */ + function SOAP_Base($faultcode = 'Client') + { + parent::SOAP_Base_Object($faultcode); + $this->_resetNamespaces(); + } + + function _resetNamespaces() + { + $this->_namespaces = array( + 'http://schemas.xmlsoap.org/soap/envelope/' => 'SOAP-ENV', + 'http://www.w3.org/2001/XMLSchema' => 'xsd', + 'http://www.w3.org/2001/XMLSchema-instance' => 'xsi', + 'http://schemas.xmlsoap.org/soap/encoding/' => 'SOAP-ENC'); + } + + /** + * Sets the schema version used in the SOAP message. + * + * @access private + * @see $_XMLSchema + * + * @param string $schemaVersion The schema version. + */ + function _setSchemaVersion($schemaVersion) + { + if (!in_array($schemaVersion, $this->_XMLSchema)) { + return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion"); + } + $this->_XMLSchemaVersion = $schemaVersion; + $tmpNS = array_flip($this->_namespaces); + $tmpNS['xsd'] = $this->_XMLSchemaVersion; + $tmpNS['xsi'] = $this->_XMLSchemaVersion . '-instance'; + $this->_namespaces = array_flip($tmpNS); + } + + function _getNamespacePrefix($ns) + { + if ($this->_namespace && $ns == $this->_namespace) { + return ''; + } + if (isset($this->_namespaces[$ns])) { + return $this->_namespaces[$ns]; + } + $prefix = 'ns' . count($this->_namespaces); + $this->_namespaces[$ns] = $prefix; + return $prefix; + } + + function _getNamespaceForPrefix($prefix) + { + $flipped = array_flip($this->_namespaces); + if (isset($flipped[$prefix])) { + return $flipped[$prefix]; + } + return null; + } + + function _isSoapValue(&$value) + { + return is_a($value, 'SOAP_Value'); + } + + function _serializeValue(&$value, $name = '', $type = false, + $elNamespace = null, $typeNamespace = null, + $options = array(), $attributes = array(), + $artype = '') + { + $namespaces = array(); + $arrayType = $array_depth = $xmlout_value = null; + $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = ''; + $xmlout_type = $xmlns = $ptype = $array_type_ns = ''; + + if (!$name || is_numeric($name)) { + $name = 'item'; + } + + if ($this->_wsdl) { + list($ptype, $arrayType, $array_type_ns, $array_depth) + = $this->_wsdl->getSchemaType($type, $name, $typeNamespace); + } + + if (!$arrayType) { + $arrayType = $artype; + } + if (!$ptype) { + $ptype = $this->_getType($value); + } + if (!$type) { + $type = $ptype; + } + + if (strcasecmp($ptype, 'Struct') == 0 || + strcasecmp($type, 'Struct') == 0) { + // Struct + $vars = null; + if (is_object($value)) { + $vars = get_object_vars($value); + } else { + $vars = &$value; + } + if (is_array($vars)) { + foreach (array_keys($vars) as $k) { + // Hide private vars. + if ($k[0] == '_') continue; + if (is_object($vars[$k])) { + if (is_a($vars[$k], 'SOAP_Value')) { + $xmlout_value .= $vars[$k]->serialize($this); + } else { + // XXX get the members and serialize them instead + // converting to an array is more overhead than we + // should really do. + $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k]), $k, false, $this->_section5 ? null : $elNamespace); + } + } else { + $xmlout_value .= $this->_serializeValue($vars[$k], $k, false, $this->_section5 ? null : $elNamespace); + } + } + } + } elseif (strcasecmp($ptype, 'Array') == 0 || + strcasecmp($type, 'Array') == 0) { + // Array. + $typeNamespace = SOAP_SCHEMA_ENCODING; + $orig_type = $type; + $type = 'Array'; + $numtypes = 0; + // XXX this will be slow on larger arrays. Basically, it flattens + // arrays to allow us to serialize multi-dimensional arrays. We + // only do this if arrayType is set, which will typically only + // happen if we are using WSDL + if (isset($options['flatten']) || + ($arrayType && + (strchr($arrayType, ',') || strstr($arrayType, '][')))) { + $numtypes = $this->_multiArrayType($value, $arrayType, + $ar_size, $xmlout_value); + } + + $array_type = $array_type_prefix = ''; + if ($numtypes != 1) { + $arrayTypeQName =& new QName($arrayType); + $arrayType = $arrayTypeQName->name; + $array_types = array(); + $array_val = null; + + // Serialize each array element. + $ar_size = count($value); + foreach ($value as $array_val) { + if ($this->_isSoapValue($array_val)) { + $array_type = $array_val->type; + $array_types[$array_type] = 1; + $array_type_ns = $array_val->type_namespace; + $xmlout_value .= $array_val->serialize($this); + } else { + $array_type = $this->_getType($array_val); + $array_types[$array_type] = 1; + $xmlout_value .= $this->_serializeValue($array_val, 'item', $array_type, $this->_section5 ? null : $elNamespace); + } + } + + $xmlout_offset = ' SOAP-ENC:offset="[0]"'; + if (!$arrayType) { + /* + $numtypes = count($array_types); + if ($numtypes == 1) { + $arrayType = $array_type; + } + */ + // Using anyType is more interoperable. + if ($array_type == 'Struct') { + $array_type = ''; + } elseif ($array_type == 'Array') { + $arrayType = 'anyType'; + $array_type_prefix = 'xsd'; + } else { + if (!$arrayType) { + $arrayType = $array_type; + } + } + } + } + if (!$arrayType || $numtypes > 1) { + // Should reference what schema we're using. + $arrayType = 'xsd:anyType'; + } else { + if ($array_type_ns) { + $array_type_prefix = $this->_getNamespacePrefix($array_type_ns); + } elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) { + $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion]; + } + if ($array_type_prefix) { + $arrayType = $array_type_prefix . ':' . $arrayType; + } + } + + $xmlout_arrayType = ' SOAP-ENC:arrayType="' . $arrayType; + if ($array_depth != null) { + for ($i = 0; $i < $array_depth; $i++) { + $xmlout_arrayType .= '[]'; + } + } + $xmlout_arrayType .= "[$ar_size]\""; + } elseif ($this->_isSoapValue($value)) { + $xmlout_value = $value->serialize($this); + } elseif ($type == 'string') { + $xmlout_value = htmlspecialchars($value); + } elseif ($type == 'rawstring') { + $xmlout_value =& $value; + } elseif ($type == 'boolean') { + $xmlout_value = $value ? 'true' : 'false'; + } else { + $xmlout_value =& $value; + } + + // Add namespaces. + if ($elNamespace) { + $elPrefix = $this->_getNamespacePrefix($elNamespace); + if ($elPrefix) { + $xmlout_name = "$elPrefix:$name"; + } else { + $xmlout_name = $name; + } + } else { + $xmlout_name = $name; + } + + if ($typeNamespace) { + $typePrefix = $this->_getNamespacePrefix($typeNamespace); + if ($typePrefix) { + $xmlout_type = "$typePrefix:$type"; + } else { + $xmlout_type = $type; + } + } elseif ($type && + isset($this->_typemap[$this->_XMLSchemaVersion][$type])) { + $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion]; + if ($typePrefix) { + $xmlout_type = "$typePrefix:$type"; + } else { + $xmlout_type = $type; + } + } + + // Handle additional attributes. + $xml_attr = ''; + if (count($attributes)) { + foreach ($attributes as $k => $v) { + $kqn =& new QName($k); + $vqn =& new QName($v); + $xml_attr .= ' ' . $kqn->fqn() . '="' . $vqn->fqn() . '"'; + } + } + + // Store the attachment for mime encoding. + if (isset($options['attachment']) && + !PEAR::isError($options['attachment'])) { + $this->__attachments[] = $options['attachment']; + } + + if ($this->_section5) { + if ($xmlout_type) { + $xmlout_type = " xsi:type=\"$xmlout_type\""; + } + if (is_null($xmlout_value)) { + $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" . + "$xml_attr xsi:nil=\"true\"/>"; + } else { + $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" . + "$xmlout_offset$xml_attr>$xmlout_value"; + } + } else { + if (is_null($xmlout_value)) { + $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>"; + } else { + $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" . + $xmlout_value . ""; + } + } + + return $xml; + } + + /** + * Converts a PHP type to a SOAP type. + * + * @access private + * + * @param string $value The value to inspect. + * + * @return string The value's SOAP type. + */ + function _getType(&$value) + { + global $SOAP_OBJECT_STRUCT, $SOAP_RAW_CONVERT; + + $type = gettype($value); + switch ($type) { + case 'object': + if (is_a($value, 'soap_value')) { + $type = $value->type; + } else { + $type = 'Struct'; + } + break; + + case 'array': + // Hashes are always handled as structs. + if ($this->_isHash($value)) { + $type = 'Struct'; + } else { + $ar_size = count($value); + reset($value); + $key1 = key($value); + if ($ar_size > 0 && is_a($key1, 'SOAP_Value')) { + // FIXME: for non-wsdl structs that are all the same type + $key2 = key($value); + if ($ar_size > 1 && + $this->_isSoapValue($key1) && + $this->_isSoapValue($key2) && + $key1->name != $key2->name) { + // This is a struct, not an array. + $type = 'Struct'; + } else { + $type = 'Array'; + } + } else { + $type = 'Array'; + } + } + break; + + case 'integer': + case 'long': + $type = 'int'; + break; + + case 'boolean': + break; + + case 'double': + // double is deprecated in PHP 4.2 and later. + $type = 'float'; + break; + + case 'null': + $type = ''; + break; + + case 'string': + if ($SOAP_RAW_CONVERT) { + if (is_numeric($value)) { + if (strstr($value, '.')) { + $type = 'float'; + } else { + $type = 'int'; + } + } else { + if (SOAP_Type_hexBinary::is_hexbin($value)) { + $type = 'hexBinary'; + } else { + if ($this->_isBase64($value)) { + $type = 'base64Binary'; + } else { + $dt =& new SOAP_Type_dateTime($value); + if ($dt->toUnixtime() != -1) { + $type = 'dateTime'; + } + } + } + } + } + break; + + default: + break; + } + + return $type; + } + + function _multiArrayType(&$value, &$type, &$size, &$xml) + { + $sz = count($value); + if (is_array($value)) { + // Seems we have a multi dimensional array, figure it out if we + // do. + $c = count($value); + for ($i = 0; $i < $c; $i++) { + $this->_multiArrayType($value[$i], $type, $size, $xml); + } + + if ($size) { + $size = $sz. ',' . $size; + } else { + $size = $sz; + } + + return 1; + } else { + if (is_object($value)) { + $type = $value->type; + $xml .= $value->serialize($this); + } else { + $type = $this->_getType($value); + $xml .= $this->_serializeValue($value, 'item', $type); + } + } + $size = null; + + return 1; + } + + /** + * Returns whether a string is base64 encoded data. + * + * @param string $value The string to check. + * + * @return boolean True if the specified value seems to be base64 encoded. + */ + function _isBase64(&$value) + { + $l = strlen($value); + if ($l) { + return $value[$l - 1] == '=' && + preg_match('/[A-Za-z=\/\+]+/', $value); + } + return false; + } + + /** + * Returns whether a type is a base64 type. + * + * @param string $type A type name. + * + * @return boolean True if the type name is a base64 type. + */ + function _isBase64Type($type) + { + return $type == 'base64' || $type == 'base64Binary'; + } + + /** + * Returns whether an array is a hash. + * + * @param array $a An array to check. + * + * @return boolean True if the specified array is a hash. + */ + function _isHash(&$a) + { + // I really dislike having to loop through this in PHP code, really + // large arrays will be slow. We need a C function to do this. + $names = array(); + $it = 0; + foreach ($a as $k => $v) { + // Checking the type is faster than regexp. + $t = gettype($k); + if ($t != 'integer') { + return true; + } elseif ($this->_isSoapValue($v)) { + $names[$v->name] = 1; + } + // If someone has a large hash they should really be defining the + // type. + if ($it++ > 10) { + return false; + } + } + return count($names)>1; + } + + function _un_htmlentities($string) + { + $trans_tbl = get_html_translation_table(HTML_ENTITIES); + $trans_tbl = array_flip($trans_tbl); + return strtr($string, $trans_tbl); + } + + function &_decode(&$soapval) + { + global $SOAP_OBJECT_STRUCT; + + if (!$this->_isSoapValue($soapval)) { + return $soapval; + } elseif (is_array($soapval->value)) { + if ($SOAP_OBJECT_STRUCT && $soapval->type != 'Array') { + $classname = $this->_defaultObjectClassname; + if (isset($this->_type_translation[$soapval->tqn->fqn()])) { + // This will force an error in PHP if the class does not + // exist. + $classname = $this->_type_translation[$soapval->tqn->fqn()]; + } elseif (isset($this->_type_translation[$soapval->type])) { + // This will force an error in PHP if the class does not + // exist. + $classname = $this->_type_translation[$soapval->type]; + } elseif ($this->_auto_translation) { + if (class_exists($soapval->type)) { + $classname = $soapval->type; + } elseif ($this->_wsdl) { + $t = $this->_wsdl->getComplexTypeNameForElement($soapval->name, $soapval->namespace); + if ($t && class_exists($t)) { + $classname = $t; + } + } + } + $return =& new $classname; + } else { + $return = array(); + } + + $counter = 1; + $isstruct = !$SOAP_OBJECT_STRUCT || !is_array($return); + foreach ($soapval->value as $item) { + if (is_object($return)) { + if ($this->_wsdl) { + // Get this child's WSDL information. + // /$soapval->ns/$soapval->type/$item->ns/$item->name + $child_type = $this->_wsdl->getComplexTypeChildType( + $soapval->namespace, + $soapval->name, + $item->namespace, + $item->name); + if ($child_type) { + $item->type = $child_type; + } + } + if (!$isstruct || $item->type == 'Array') { + if (isset($return->{$item->name}) && + is_object($return->{$item->name})) { + $return->{$item->name} =& $this->_decode($item); + } elseif (isset($return->{$item->name}) && + is_array($return->{$item->name})) { + $return->{$item->name}[] = $this->_decode($item); + } elseif (is_array($return)) { + $return[] =& $this->_decode($item); + } else { + $return->{$item->name} =& $this->_decode($item); + } + } elseif (isset($return->{$item->name})) { + $isstruct = false; + if (count(get_object_vars($return)) == 1) { + $d =& $this->_decode($item); + $return = array($return->{$item->name}, $d); + } else { + $d =& $this->_decode($item); + $return->{$item->name} = array($return->{$item->name}, $d); + } + } else { + $return->{$item->name} =& $this->_decode($item); + } + // Set the attributes as members in the class. + if (method_exists($return, '__set_attribute')) { + foreach ($soapval->attributes as $key => $value) { + call_user_func_array(array(&$return, + '__set_attribute'), + array($key, $value)); + } + } + } else { + if ($soapval->arrayType && $this->_isSoapValue($item)) { + if ($this->_isBase64Type($item->type) && + !$this->_isBase64Type($soapval->arrayType)) { + // Decode the value if we're losing the base64 + // type information. + $item->value = base64_decode($item->value); + } + $item->type = $soapval->arrayType; + } + if (!$isstruct) { + $return[] = $this->_decode($item); + } elseif (isset($return[$item->name])) { + $isstruct = false; + $d =& $this->_decode($item); + $return = array($return[$item->name], $d); + } else { + $return[$item->name] = $this->_decode($item); + } + } + } + + return $return; + } + + if ($soapval->type == 'boolean') { + if ($soapval->value != '0' && + strcasecmp($soapval->value, 'false') != 0) { + $soapval->value = true; + } else { + $soapval->value = false; + } + } elseif ($soapval->type && + isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) { + // If we can, set variable type. + settype($soapval->value, + $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]); + } + + if ($this->_isBase64Type($soapval->type)) { + return base64_decode($soapval->value); + } else { + return $soapval->value; + } + } + + /** + * Creates the SOAP envelope with the SOAP envelop data. + * + * @access private + * + * @param + * @param array $headers + * @param string $encoding + * @param array $options + * + * @return string + */ + function _makeEnvelope(&$method, &$headers, + $encoding = SOAP_DEFAULT_ENCODING, + $options = array()) + { + $smsg = $header_xml = $ns_string = ''; + + if ($headers) { + $c = count($headers); + for ($i = 0; $i < $c; $i++) { + $header_xml .= $headers[$i]->serialize($this); + } + $header_xml = "\r\n$header_xml\r\n\r\n"; + } + + if (!isset($options['input']) || $options['input'] == 'parse') { + if (is_array($method)) { + $c = count($method); + for ($i = 0; $i < $c; $i++) { + $smsg .= $method[$i]->serialize($this); + } + } else { + $smsg = $method->serialize($this); + } + } else { + $smsg = $method; + } + $body = "\r\n" . $smsg . "\r\n\r\n"; + + foreach ($this->_namespaces as $k => $v) { + $ns_string .= " xmlns:$v=\"$k\"\r\n"; + } + if ($this->_namespace) { + $ns_string .= " xmlns=\"{$this->_namespace}\"\r\n"; + } + + /* If 'use' == 'literal', we do not put in the encodingStyle. This is + * denoted by $this->_section5 being false. 'use' can be defined at a + * more granular level than we are dealing with here, so this does not + * work for all services. */ + $xml = "\r\n\r\n". + "_section5 ? ' SOAP-ENV:encodingStyle="' . SOAP_SCHEMA_ENCODING . '"' : ''). + ">\r\n". + "$header_xml$body\r\n"; + + return $xml; + } + + function _makeMimeMessage(&$xml, $encoding = SOAP_DEFAULT_ENCODING) + { + global $SOAP_options; + + if (!isset($SOAP_options['Mime'])) { + return $this->_raiseSoapFault('Mime is not installed'); + } + + // Encode any attachments. + // See http://www.w3.org/TR/SOAP-attachments + // Now we have to mime encode the message. + $params = array('content_type' => 'multipart/related; type=text/xml'); + $msg =& new Mail_mimePart('', $params); + + // Add the xml part. + $params['content_type'] = 'text/xml'; + $params['charset'] = $encoding; + $params['encoding'] = 'base64'; + $msg->addSubPart($xml, $params); + + // Add the attachements + $c = count($this->__attachments); + for ($i = 0; $i < $c; $i++) { + $attachment =& $this->__attachments[$i]; + $msg->addSubPart($attachment['body'], $attachment); + } + + return $msg->encode(); + } + + // TODO: this needs to be used from the Transport system. + function _makeDIMEMessage($xml) + { + global $SOAP_options; + + if (!isset($SOAP_options['DIME'])) { + return $this->_raiseSoapFault('DIME is not installed'); + } + + // Encode any attachments. + // See http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt + // Now we have to DIME encode the message + $dime =& new Net_DIME_Message(); + $msg = $dime->encodeData($xml, SOAP_ENVELOP, null, NET_DIME_TYPE_URI); + + // Add the attachments. + $c = count($this->__attachments); + for ($i = 0; $i < $c; $i++) { + $attachment =& $this->__attachments[$i]; + $msg .= $dime->encodeData($attachment['body'], + $attachment['content_type'], + $attachment['cid'], + NET_DIME_TYPE_MEDIA); + } + $msg .= $dime->endMessage(); + + return $msg; + } + + function _decodeMimeMessage(&$data, &$headers, &$attachments) + { + global $SOAP_options; + + if (!isset($SOAP_options['Mime'])) { + $this->_raiseSoapFault('Mime Unsupported, install PEAR::Mail::Mime', '', '', 'Server'); + return; + } + + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + // Lame thing to have to do for decoding. + $decoder =& new Mail_mimeDecode($data); + $structure = $decoder->decode($params); + + if (isset($structure->body)) { + $data = $structure->body; + $headers = $structure->headers; + + return; + } elseif (isset($structure->parts)) { + $data = $structure->parts[0]->body; + $headers = array_merge($structure->headers, + $structure->parts[0]->headers); + if (count($structure->parts) > 1) { + $mime_parts = array_splice($structure->parts,1); + // Prepare the parts for the SOAP parser. + + $c = count($mime_parts); + for ($i = 0; $i < $c; $i++) { + $p =& $mime_parts[$i]; + if (isset($p->headers['content-location'])) { + // TODO: modify location per SwA note section 3 + // http://www.w3.org/TR/SOAP-attachments + $attachments[$p->headers['content-location']] = $p->body; + } else { + $cid = 'cid:' . substr($p->headers['content-id'], 1, -1); + $attachments[$cid] = $p->body; + } + } + } + + return; + } + + $this->_raiseSoapFault('Mime parsing error', '', '', 'Server'); + } + + function _decodeDIMEMessage(&$data, &$headers, &$attachments) + { + global $SOAP_options; + + if (!isset($SOAP_options['DIME'])) { + $this->_raiseSoapFault('DIME Unsupported, install PEAR::Net::DIME', '', '', 'Server'); + return; + } + + // This SHOULD be moved to the transport layer, e.g. PHP itself should + // handle parsing DIME ;) + $dime =& new Net_DIME_Message(); + $err = $dime->decodeData($data); + if (PEAR::isError($err)) { + $this->_raiseSoapFault('Failed to decode the DIME message!', '', '', 'Server'); + return; + } + if (strcasecmp($dime->parts[0]['type'], SOAP_ENVELOP) != 0) { + $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!', '', '', 'Server'); + return; + } + + $data = $dime->parts[0]['data']; + // Fake it for now. + $headers['content-type'] = 'text/xml'; + $c = count($dime->parts); + for ($i = 0; $i < $c; $i++) { + $part =& $dime->parts[$i]; + // We need to handle URI's better. + $id = strncmp($part['id'], 'cid:', 4) + ? 'cid:' . $part['id'] + : $part['id']; + $attachments[$id] = $part['data']; + } + } + + function __set_type_translation($type, $class = null) + { + $tq =& new QName($type); + if (!$class) { + $class = $tq->name; + } + $this->_type_translation[$type]=$class; + } + +} + +/** + * Class used to handle QNAME values in XML. + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + */ +class QName +{ + var $name = ''; + var $ns = ''; + var $namespace=''; + + function QName($name, $namespace = '') + { + if ($name && $name[0] == '{') { + preg_match('/\{(.*?)\}(.*)/', $name, $m); + $this->name = $m[2]; + $this->namespace = $m[1]; + } elseif (substr_count($name, ':') == 1) { + $s = explode(':', $name); + $s = array_reverse($s); + $this->name = $s[0]; + $this->ns = $s[1]; + $this->namespace = $namespace; + } else { + $this->name = $name; + $this->namespace = $namespace; + } + + // A little more magic than should be in a qname. + $p = strpos($this->name, '['); + if ($p) { + // TODO: Need to re-examine this logic later. + // Chop off []. + $this->arraySize = explode(',', substr($this->name, $p + 1, -$p - 2)); + $this->arrayInfo = substr($this->name, $p); + $this->name = substr($this->name, 0, $p); + } + } + + function fqn() + { + if ($this->namespace) { + return '{' . $this->namespace . '}' . $this->name; + } elseif ($this->ns) { + return $this->ns . ':' . $this->name; + } + return $this->name; + } + +} diff --git a/thirdparty/pear/SOAP/Client.php b/thirdparty/pear/SOAP/Client.php new file mode 100644 index 0000000..81c63f3 --- /dev/null +++ b/thirdparty/pear/SOAP/Client.php @@ -0,0 +1,734 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Value.php'; +require_once 'SOAP/Base.php'; +require_once 'SOAP/Transport.php'; +require_once 'SOAP/WSDL.php'; +require_once 'SOAP/Fault.php'; +require_once 'SOAP/Parser.php'; + +// Arnaud: the following code was taken from DataObject and adapted to suit + +// this will be horrifically slow!!!! +// NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer +// these two are BC/FC handlers for call in PHP4/5 + +if (!class_exists('SOAP_Client_Overload')) { + if (substr(phpversion(), 0, 1) == 5) { + class SOAP_Client_Overload extends SOAP_Base { + function __call($method, $args) + { + $return = null; + $this->_call($method, $args, $return); + return $return; + } + } + } else { + if (!function_exists('clone')) { + eval('function clone($t) { return $t; }'); + } + eval(' + class SOAP_Client_Overload extends SOAP_Base { + function __call($method, $args, &$return) + { + return $this->_call($method, $args, $return); + } + }'); + } +} + +/** + * SOAP Client Class + * + * This class is the main interface for making soap requests. + * + * basic usage: + * $soapclient = new SOAP_Client( string path [ , boolean wsdl] ); + * echo $soapclient->call( string methodname [ , array parameters] ); + * + * + * Originally based on SOAPx4 by Dietrich Ayala + * http://dietrich.ganx4.com/soapx4 + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + * @author Stig Bakken Conversion to PEAR + * @author Dietrich Ayala Original Author + */ +class SOAP_Client extends SOAP_Client_Overload +{ + /** + * Communication endpoint. + * + * Currently the following transport formats are supported: + * - HTTP + * - SMTP + * + * Example endpoints: + * http://www.example.com/soap/server.php + * https://www.example.com/soap/server.php + * mailto:soap@example.com + * + * @see SOAP_Client() + * @var $_endpoint string + */ + var $_endpoint = ''; + + /** + * The SOAP PORT name that is used by the client. + * + * @var $_portName string + */ + var $_portName = ''; + + /** + * Endpoint type e.g. 'wdsl'. + * + * @var $__endpointType string + */ + var $__endpointType = ''; + + /** + * The received xml. + * + * @var $xml string + */ + var $xml; + + /** + * The outgoing and incoming data stream for debugging. + * + * @var $wire string + */ + var $wire; + var $__last_request = null; + var $__last_response = null; + + /** + * Options. + * + * @var $__options array + */ + var $__options = array('trace'=>0); + + /** + * The character encoding used for XML parser, etc. + * + * @var $_encoding string + */ + var $_encoding = SOAP_DEFAULT_ENCODING; + + /** + * The array of SOAP_Headers that we are sending. + * + * @var $headersOut array + */ + var $headersOut = null; + + /** + * The headers we recieved back in the response. + * + * @var $headersIn array + */ + var $headersIn = null; + + /** + * Options for the HTTP_Request class (see HTTP/Request.php). + * + * @var $__proxy_params array + */ + var $__proxy_params = array(); + + var $_soap_transport = null; + + /** + * Constructor. + * + * @access public + * + * @param string $endpoint An URL. + * @param boolean $wsdl Whether the endpoint is a WSDL file. + * @param string $portName + * @param array $proxy_params Options for the HTTP_Request class (see + * HTTP/Request.php) + */ + function SOAP_Client($endpoint, $wsdl = false, $portName = false, + $proxy_params = array()) + { + parent::SOAP_Base('Client'); + + $this->_endpoint = $endpoint; + $this->_portName = $portName; + $this->__proxy_params = $proxy_params; + + // This hack should perhaps be removed as it might cause unexpected + // behaviour. + $wsdl = $wsdl + ? $wsdl + : strtolower(substr($endpoint, -4)) == 'wsdl'; + + // make values + if ($wsdl) { + $this->__endpointType = 'wsdl'; + // instantiate wsdl class + $this->_wsdl =& new SOAP_WSDL($this->_endpoint, + $this->__proxy_params); + if ($this->_wsdl->fault) { + $this->_raiseSoapFault($this->_wsdl->fault); + } + } + } + + function _reset() + { + $this->xml = null; + $this->wire = null; + $this->__last_request = null; + $this->__last_response = null; + $this->headersIn = null; + $this->headersOut = null; + } + + /** + * Sets the character encoding. + * + * Limited to 'UTF-8', 'US_ASCII' and 'ISO-8859-1'. + * + * @access public + * + * @param string encoding + * + * @return mixed SOAP_Fault on error. + */ + function setEncoding($encoding) + { + if (in_array($encoding, $this->_encodings)) { + $this->_encoding = $encoding; + return; + } + return $this->_raiseSoapFault('Invalid Encoding'); + } + + /** + * Adds a header to the envelope. + * + * @access public + * + * @param SOAP_Header $soap_value A SOAP_Header or an array with the + * elements 'name', 'namespace', + * 'mustunderstand', and 'actor' to send + * as a header. + */ + function addHeader(&$soap_value) + { + // Add a new header to the message. + if (is_a($soap_value, 'SOAP_Header')) { + $this->headersOut[] =& $soap_value; + } elseif (is_array($soap_value)) { + // name, value, namespace, mustunderstand, actor + $this->headersOut[] =& new SOAP_Header($soap_value[0], + null, + $soap_value[1], + $soap_value[2], + $soap_value[3]);; + } else { + $this->_raiseSoapFault('Invalid parameter provided to addHeader(). Must be an array or a SOAP_Header.'); + } + } + + /** + * Calls a method on the SOAP endpoint. + * + * The namespace parameter is overloaded to accept an array of options + * that can contain data necessary for various transports if it is used as + * an array, it MAY contain a namespace value and a soapaction value. If + * it is overloaded, the soapaction parameter is ignored and MUST be + * placed in the options array. This is done to provide backwards + * compatibility with current clients, but may be removed in the future. + * The currently supported values are:
+     *   namespace
+     *   soapaction
+     *   timeout (HTTP socket timeout)
+     *   transfer-encoding (SMTP, Content-Transfer-Encoding: header)
+     *   from (SMTP, From: header)
+     *   subject (SMTP, Subject: header)
+     *   headers (SMTP, hash of extra SMTP headers)
+     * 
+ * + * @access public + * + * @param string $method The method to call. + * @param array $params The method parameters. + * @param string|array $namespace Namespace or hash with options. + * @param string $soapAction + * + * @return mixed The method result or a SOAP_Fault on error. + */ + function &call($method, &$params, $namespace = false, $soapAction = false) + { + $this->headersIn = null; + $this->__last_request = null; + $this->__last_response = null; + $this->wire = null; + $this->xml = null; + + $soap_data =& $this->__generate($method, $params, $namespace, $soapAction); + if (PEAR::isError($soap_data)) { + $fault =& $this->_raiseSoapFault($soap_data); + return $fault; + } + + // __generate() may have changed the endpoint if the WSDL has more + // than one service, so we need to see if we need to generate a new + // transport to hook to a different URI. Since the transport protocol + // can also change, we need to get an entirely new object. This could + // probably be optimized. + if (!$this->_soap_transport || + $this->_endpoint != $this->_soap_transport->url) { + $this->_soap_transport =& SOAP_Transport::getTransport($this->_endpoint); + if (PEAR::isError($this->_soap_transport)) { + $fault =& $this->_soap_transport; + $this->_soap_transport = null; + $fault =& $this->_raiseSoapFault($fault); + return $fault; + } + } + $this->_soap_transport->encoding = $this->_encoding; + + // Send the message. + $transport_options = array_merge_recursive($this->__proxy_params, + $this->__options); + $this->xml = $this->_soap_transport->send($soap_data, $transport_options); + + // Save the wire information for debugging. + if ($this->__options['trace'] > 0) { + $this->__last_request =& $this->_soap_transport->outgoing_payload; + $this->__last_response =& $this->_soap_transport->incoming_payload; + $this->wire = $this->__get_wire(); + } + if ($this->_soap_transport->fault) { + $fault =& $this->_raiseSoapFault($this->xml); + return $fault; + } + + $this->__attachments =& $this->_soap_transport->attachments; + $this->__result_encoding = $this->_soap_transport->result_encoding; + + if (isset($this->__options['result']) && + $this->__options['result'] != 'parse') { + return $this->xml; + } + + $result = &$this->__parse($this->xml, $this->__result_encoding, $this->__attachments); + + return $result; + } + + /** + * Sets an option to use with the transport layers. + * + * For example: + * + * $soapclient->setOpt('curl', CURLOPT_VERBOSE, 1) + * + * to pass a specific option to curl if using an SSL connection. + * + * @access public + * + * @param string $category Category to which the option applies or option + * name. + * @param string $option An option name if $category is a category name, + * an option value if $category is an option name. + * @param string $value An option value if $category is a category + * name. + */ + function setOpt($category, $option, $value = null) + { + if (!is_null($value)) { + if (!isset($this->__options[$category])) { + $this->__options[$category] = array(); + } + $this->__options[$category][$option] = $value; + } else { + $this->__options[$category] = $option; + } + } + + /** + * Call method supporting the overload extension. + * + * If the overload extension is loaded, you can call the client class with + * a soap method name: + * + * $soap = new SOAP_Client(....); + * $value = $soap->getStockQuote('MSFT'); + * + * + * @access public + * + * @param string $method The method to call. + * @param array $params The method parameters. + * @param string $return_value Will get the method's return value + * assigned. + * + * @return boolean Always true. + */ + function _call($method, $params, &$return_value) + { + // Overloading lowercases the method name, we need to look into the + // wsdl and try to find the correct method name to get the correct + // case for the call. + if ($this->_wsdl) { + $this->_wsdl->matchMethod($method); + } + + $return_value =& $this->call($method, $params); + + return true; + } + + function &__getlastrequest() + { + $request =& $this->__last_request; + return $request; + } + + function &__getlastresponse() + { + $response =& $this->__last_response; + return $response; + } + + function __use($use) + { + $this->__options['use'] = $use; + } + + function __style($style) + { + $this->__options['style'] = $style; + } + + function __trace($level) + { + $this->__options['trace'] = $level; + } + + function &__generate($method, &$params, $namespace = false, + $soapAction = false) + { + $this->fault = null; + $this->__options['input']='parse'; + $this->__options['result']='parse'; + $this->__options['parameters'] = false; + + if ($params && gettype($params) != 'array') { + $params = array($params); + } + + if (gettype($namespace) == 'array') { + foreach ($namespace as $optname => $opt) { + $this->__options[strtolower($optname)] = $opt; + } + if (isset($this->__options['namespace'])) { + $namespace = $this->__options['namespace']; + } else { + $namespace = false; + } + } else { + // We'll place $soapAction into our array for usage in the + // transport. + $this->__options['soapaction'] = $soapAction; + $this->__options['namespace'] = $namespace; + } + + if ($this->__endpointType == 'wsdl') { + $this->_setSchemaVersion($this->_wsdl->xsd); + + // Get port name. + if (!$this->_portName) { + $this->_portName = $this->_wsdl->getPortName($method); + } + if (PEAR::isError($this->_portName)) { + $fault =& $this->_raiseSoapFault($this->_portName); + return $fault; + } + + // Get endpoint. + $this->_endpoint = $this->_wsdl->getEndpoint($this->_portName); + if (PEAR::isError($this->_endpoint)) { + $fault =& $this->_raiseSoapFault($this->_endpoint); + return $fault; + } + + // Get operation data. + $opData = $this->_wsdl->getOperationData($this->_portName, $method); + + if (PEAR::isError($opData)) { + $fault =& $this->_raiseSoapFault($opData); + return $fault; + } + $namespace = $opData['namespace']; + $this->__options['style'] = $opData['style']; + $this->__options['use'] = $opData['input']['use']; + $this->__options['soapaction'] = $opData['soapAction']; + + // Set input parameters. + if ($this->__options['input'] == 'parse') { + $this->__options['parameters'] = $opData['parameters']; + $nparams = array(); + if (isset($opData['input']['parts']) && + count($opData['input']['parts'])) { + $i = 0; + foreach ($opData['input']['parts'] as $name => $part) { + $xmlns = ''; + $attrs = array(); + // Is the name a complex type? + if (isset($part['element'])) { + $xmlns = $this->_wsdl->namespaces[$part['namespace']]; + $part = $this->_wsdl->elements[$part['namespace']][$part['type']]; + $name = $part['name']; + } + if (isset($params[$name]) || + $this->_wsdl->getDataHandler($name, $part['namespace'])) { + $nparams[$name] =& $params[$name]; + } else { + // We now force an associative array for + // parameters if using WSDL. + $fault =& $this->_raiseSoapFault("The named parameter $name is not in the call parameters."); + return $fault; + } + if (gettype($nparams[$name]) != 'object' || + !is_a($nparams[$name], 'SOAP_Value')) { + // Type is likely a qname, split it apart, and get + // the type namespace from WSDL. + $qname =& new QName($part['type']); + if ($qname->ns) { + $type_namespace = $this->_wsdl->namespaces[$qname->ns]; + } elseif (isset($part['namespace'])) { + $type_namespace = $this->_wsdl->namespaces[$part['namespace']]; + } else { + $type_namespace = null; + } + $qname->namespace = $type_namespace; + $type = $qname->name; + $pqname = $name; + if ($xmlns) { + $pqname = '{' . $xmlns . '}' . $name; + } + $nparams[$name] =& new SOAP_Value($pqname, + $qname->fqn(), + $nparams[$name], + $attrs); + } else { + // WSDL fixups to the SOAP value. + } + } + } + $params =& $nparams; + unset($nparams); + } + } else { + $this->_setSchemaVersion(SOAP_XML_SCHEMA_VERSION); + } + + // Serialize the message. + $this->_section5 = (!isset($this->__options['use']) || + $this->__options['use'] != 'literal'); + + if (!isset($this->__options['style']) || + $this->__options['style'] == 'rpc') { + $this->__options['style'] = 'rpc'; + $this->docparams = true; + $mqname =& new QName($method, $namespace); + $methodValue =& new SOAP_Value($mqname->fqn(), 'Struct', $params); + $soap_msg = $this->_makeEnvelope($methodValue, + $this->headersOut, + $this->_encoding, + $this->__options); + } else { + if (!$params) { + $mqname =& new QName($method, $namespace); + $mynull = null; + $params =& new SOAP_Value($mqname->fqn(), 'Struct', $mynull); + } elseif ($this->__options['input'] == 'parse') { + if (is_array($params)) { + $nparams = array(); + $keys = array_keys($params); + foreach ($keys as $k) { + if (gettype($params[$k]) != 'object') { + $nparams[] =& new SOAP_Value($k, + false, + $params[$k]); + } else { + $nparams[] =& $params[$k]; + } + } + $params =& $nparams; + } + if ($this->__options['parameters']) { + $mqname =& new QName($method, $namespace); + $params =& new SOAP_Value($mqname->fqn(), + 'Struct', + $params); + } + } + $soap_msg = $this->_makeEnvelope($params, + $this->headersOut, + $this->_encoding, + $this->__options); + } + unset($this->headersOut); + + if (PEAR::isError($soap_msg)) { + $fault =& $this->_raiseSoapFault($soap_msg); + return $fault; + } + + // Handle MIME or DIME encoding. + // TODO: DIME encoding should move to the transport, do it here for + // now and for ease of getting it done. + if (count($this->__attachments)) { + if ((isset($this->__options['attachments']) && + $this->__options['attachments'] == 'Mime') || + isset($this->__options['Mime'])) { + $soap_msg =& $this->_makeMimeMessage($soap_msg, + $this->_encoding); + } else { + // default is dime + $soap_msg =& $this->_makeDIMEMessage($soap_msg, + $this->_encoding); + $this->__options['headers']['Content-Type'] = 'application/dime'; + } + if (PEAR::isError($soap_msg)) { + $fault =& $this->_raiseSoapFault($soap_msg); + return $fault; + } + } + + // Instantiate client. + if (is_array($soap_msg)) { + $soap_data =& $soap_msg['body']; + if (count($soap_msg['headers'])) { + if (isset($this->__options['headers'])) { + $this->__options['headers'] = array_merge($this->__options['headers'], $soap_msg['headers']); + } else { + $this->__options['headers'] = $soap_msg['headers']; + } + } + } else { + $soap_data =& $soap_msg; + } + + return $soap_data; + } + + function &__parse(&$response, $encoding, &$attachments) + { + // Parse the response. + $response =& new SOAP_Parser($response, $encoding, $attachments); + if ($response->fault) { + $fault =& $this->_raiseSoapFault($response->fault); + return $fault; + } + + // Return array of parameters. + $return =& $response->getResponse(); + $headers =& $response->getHeaders(); + if ($headers) { + $this->headersIn =& $this->__decodeResponse($headers, false); + } + + $decoded = &$this->__decodeResponse($return); + return $decoded; + } + + function &__decodeResponse(&$response, $shift = true) + { + if (!$response) { + $decoded = null; + return $decoded; + } + + // Check for valid response. + if (PEAR::isError($response)) { + $fault =& $this->_raiseSoapFault($response); + return $fault; + } elseif (!is_a($response, 'soap_value')) { + $fault =& $this->_raiseSoapFault("Didn't get SOAP_Value object back from client"); + return $fault; + } + + // Decode to native php datatype. + $returnArray =& $this->_decode($response); + + // Fault? + if (PEAR::isError($returnArray)) { + $fault =& $this->_raiseSoapFault($returnArray); + return $fault; + } + + if (is_object($returnArray) && + strcasecmp(get_class($returnArray), 'stdClass') == 0) { + $returnArray = get_object_vars($returnArray); + } + if (is_array($returnArray)) { + if (isset($returnArray['faultcode']) || + isset($returnArray['SOAP-ENV:faultcode'])) { + $faultcode = $faultstring = $faultdetail = $faultactor = ''; + foreach ($returnArray as $k => $v) { + if (stristr($k, 'faultcode')) $faultcode = $v; + if (stristr($k, 'faultstring')) $faultstring = $v; + if (stristr($k, 'detail')) $faultdetail = $v; + if (stristr($k, 'faultactor')) $faultactor = $v; + } + $fault =& $this->_raiseSoapFault($faultstring, $faultdetail, $faultactor, $faultcode); + return $fault; + } + // Return array of return values. + if ($shift && count($returnArray) == 1) { + $decoded = array_shift($returnArray); + return $decoded; + } + return $returnArray; + } + return $returnArray; + } + + function __get_wire() + { + if ($this->__options['trace'] > 0 && + ($this->__last_request || $this->__last_response)) { + return "OUTGOING:\n\n" . + $this->__last_request . + "\n\nINCOMING\n\n" . + preg_replace("/>\r\n<", $this->__last_response); + } + + return null; + } + +} diff --git a/thirdparty/pear/SOAP/Copy of Base.php b/thirdparty/pear/SOAP/Copy of Base.php new file mode 100644 index 0000000..a1ef47f --- /dev/null +++ b/thirdparty/pear/SOAP/Copy of Base.php @@ -0,0 +1,1229 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +/** + * SOAP_OBJECT_STRUCT makes PEAR::SOAP use objects for SOAP structures rather + * than arrays. This has been done to provide a closer match to php-soap. If + * the old behaviour is needed, set to false. The old behaviour is + * deprecated. + * + * @global bool $GLOBALS['SOAP_OBJECT_STRUCT'] + */ +$GLOBALS['SOAP_OBJECT_STRUCT'] = true; + +/** + * SOAP_RAW_CONVERT makes PEAR::SOAP attempt to determine what SOAP type a PHP + * string COULD be. This may result in slightly better interoperability when + * you are not using WSDL, and are being lazy and not using SOAP_Value to + * define types for your values. + * + * @global bool $GLOBALS['SOAP_RAW_CONVERT'] + */ +$GLOBALS['SOAP_RAW_CONVERT'] = false; + +require_once 'PEAR.php'; +require_once 'SOAP/Type/dateTime.php'; +require_once 'SOAP/Type/hexBinary.php'; + +// optional features +$GLOBALS['SOAP_options'] = array(); + +@include_once 'Mail/mimePart.php'; +@include_once 'Mail/mimeDecode.php'; +if (class_exists('Mail_mimePart')) { + $GLOBALS['SOAP_options']['Mime'] = 1; + define('MAIL_MIMEPART_CRLF', "\r\n"); +} + +@include_once 'Net/DIME.php'; +if (class_exists('Net_DIME_Message')) { + $GLOBALS['SOAP_options']['DIME'] = 1; +} + +/** + * Enable debugging information? + * + * @global bool $GLOBALS['SOAP_DEBUG'] + * @name $SOAP_DEBUG + */ +$GLOBALS['SOAP_DEBUG'] = false; + +if (!function_exists('version_compare') || + version_compare(phpversion(), '4.1', '<')) { + die("requires PHP 4.1 or higher\n"); +} +if (version_compare(phpversion(), '4.1', '>=') && + version_compare(phpversion(), '4.2', '<')) { + define('FLOAT', 'double'); +} else { + define('FLOAT', 'float'); +} + +if (!defined('INF')) { + define('INF', 1.8e307); +} +if (!defined('NAN')) { + define('NAN', 0.0); +} + +define('SOAP_LIBRARY_VERSION', '0.8.0RC4'); +define('SOAP_LIBRARY_NAME', 'PEAR-SOAP 0.8.0RC4-devel'); + +// Set schema version. +define('SOAP_XML_SCHEMA_VERSION', 'http://www.w3.org/2001/XMLSchema'); +define('SOAP_XML_SCHEMA_INSTANCE', 'http://www.w3.org/2001/XMLSchema-instance'); +define('SOAP_XML_SCHEMA_1999', 'http://www.w3.org/1999/XMLSchema'); +define('SOAP_SCHEMA', 'http://schemas.xmlsoap.org/wsdl/soap/'); +define('SOAP_SCHEMA_ENCODING', 'http://schemas.xmlsoap.org/soap/encoding/'); +define('SOAP_ENVELOP', 'http://schemas.xmlsoap.org/soap/envelope/'); + +define('SCHEMA_DISCO', 'http://schemas.xmlsoap.org/disco/'); +define('SCHEMA_DISCO_SCL', 'http://schemas.xmlsoap.org/disco/scl/'); + +define('SCHEMA_SOAP', 'http://schemas.xmlsoap.org/wsdl/soap/'); +define('SCHEMA_SOAP_HTTP', 'http://schemas.xmlsoap.org/soap/http'); +define('SCHEMA_WSDL_HTTP', 'http://schemas.xmlsoap.org/wsdl/http/'); +define('SCHEMA_MIME', 'http://schemas.xmlsoap.org/wsdl/mime/'); +define('SCHEMA_WSDL', 'http://schemas.xmlsoap.org/wsdl/'); +define('SCHEMA_DIME', 'http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/'); +define('SCHEMA_CONTENT', 'http://schemas.xmlsoap.org/ws/2002/04/content-type/'); +define('SCHEMA_REF', 'http://schemas.xmlsoap.org/ws/2002/04/reference/'); + +define('SOAP_DEFAULT_ENCODING', 'UTF-8'); + +class SOAP_Base_Object extends PEAR +{ + /** + * Store debugging information in $_debug_data? + * + * @see $debug_data, SOAP_Base + * @var boolean $_debug_flag + */ + var $_debug_flag = false; + + /** + * String containing debugging information if $_debug_flag is true. + * + * @access public + * @see $debug_flag, SOAP_Base + * @var string $_debug_data + */ + var $_debug_data = ''; + + /** + * Supported encodings, limited by XML extension. + * + * @var array $_encodings + */ + var $_encodings = array('ISO-8859-1', 'US-ASCII', 'UTF-8'); + + /** + * Fault code. + * + * @var string $_myfaultcode + */ + var $_myfaultcode = ''; + + /** + * Recent PEAR_Error object. + * + * @var PEAR_Error $fault + */ + var $fault = null; + + /** + * Constructor. + * + * @see $debug_data, _debug() + * + * @param string $faultcode Error code. + */ + function SOAP_Base_Object($faultcode = 'Client') + { + $this->_myfaultcode = $faultcode; + $this->_debug_flag = $GLOBALS['SOAP_DEBUG']; + parent::PEAR('SOAP_Fault'); + } + + /** + * Raises a SOAP error. + * + * Please refer to the SOAP definition for an impression of what a certain + * parameter stands for. + * + * Use $debug_flag to store errors to the member variable $debug_data + * + * @see $debug_flag, $debug_data, SOAP_Fault + * + * @param string|object $str Error message or object. + * @param string $detail Detailed error message. + * @param string $actorURI + * @param mixed $code + * @param mixed $mode + * @param mixed $options + * @param boolean $skipmsg + */ + function &_raiseSoapFault($str, $detail = '', $actorURI = '', $code = null, + $mode = null, $options = null, $skipmsg = false) + { + // Pass through previous faults. + $is_instance = isset($this); + if (is_object($str)) { + $fault =& $str; + } else { + if (!$code) { + $code = $is_instance ? $this->_myfaultcode : 'Client'; + } + $fault =& new SOAP_Fault($str, + $code, + $actorURI, + $detail, + $mode, + $options); + } + if ($is_instance) { + $this->fault =& $fault; + } + + return $fault; + } + + function __isfault() + { + return $this->fault != null; + } + + function &__getfault() + { + return $this->fault; + } + + /** + * Adds a string to the debug data. + * + * @param string $string Debugging message. + */ + function _debug($string) + { + if ($this->_debug_flag) { + $this->_debug_data .= get_class($this) . ': ' . + str_replace('>', ">\r\n", $string) . "\n"; + } + } + +} + +/** + * Common base class of all SOAP classes. + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + */ +class SOAP_Base extends SOAP_Base_Object +{ + var $_XMLSchema = array('http://www.w3.org/2001/XMLSchema', + 'http://www.w3.org/1999/XMLSchema'); + var $_XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + // load types into typemap array + var $_typemap = array( + 'http://www.w3.org/2001/XMLSchema' => array( + 'string' => 'string', + 'boolean' => 'boolean', + 'float' => FLOAT, + 'double' => FLOAT, + 'decimal' => FLOAT, + 'duration' => 'integer', + 'dateTime' => 'string', + 'time' => 'string', + 'date' => 'string', + 'gYearMonth' => 'integer', + 'gYear' => 'integer', + 'gMonthDay' => 'integer', + 'gDay' => 'integer', + 'gMonth' => 'integer', + 'hexBinary' => 'string', + 'base64Binary' => 'string', + // derived datatypes + 'normalizedString' => 'string', + 'token' => 'string', + 'language' => 'string', + 'NMTOKEN' => 'string', + 'NMTOKENS' => 'string', + 'Name' => 'string', + 'NCName' => 'string', + 'ID' => 'string', + 'IDREF' => 'string', + 'IDREFS' => 'string', + 'ENTITY' => 'string', + 'ENTITIES' => 'string', + 'integer' => 'integer', + 'nonPositiveInteger' => 'integer', + 'negativeInteger' => 'integer', + 'long' => 'integer', + 'int' => 'integer', + 'short' => 'integer', + 'byte' => 'string', + 'nonNegativeInteger' => 'integer', + 'unsignedLong' => 'integer', + 'unsignedInt' => 'integer', + 'unsignedShort' => 'integer', + 'unsignedByte' => 'integer', + 'positiveInteger' => 'integer', + 'anyType' => 'string', + 'anyURI' => 'string', + 'QName' => 'string' + ), + 'http://www.w3.org/1999/XMLSchema' => array( + 'i4' => 'integer', + 'int' => 'integer', + 'boolean' => 'boolean', + 'string' => 'string', + 'double' => FLOAT, + 'float' => FLOAT, + 'dateTime' => 'string', + 'timeInstant' => 'string', + 'base64Binary' => 'string', + 'base64' => 'string', + 'ur-type' => 'string' + ), + 'http://schemas.xmlsoap.org/soap/encoding/' => array( + 'base64' => 'string', + 'array' => 'array', + 'Array' => 'array', + 'Struct' => 'array') + ); + + /** + * Default class name to use for decoded response objects. + * + * @var string $_defaultObjectClassname + */ + var $_defaultObjectClassname = 'stdClass'; + + // Load namespace URIs into an array of URI => prefix. + var $_namespaces; + var $_namespace; + + var $_xmlEntities = array('&' => '&', + '<' => '<', + '>' => '>', + "'" => ''', + '"' => '"'); + + var $_doconversion = false; + + var $__attachments = array(); + + var $_wsdl = null; + + /** + * True if we use section 5 encoding, or false if this is literal. + * + * @var boolean $_section5 + */ + var $_section5 = true; + + // Handle type to class mapping. + var $_auto_translation = false; + var $_type_translation = array(); + + /** + * Constructor. + * + * @see $debug_data, _debug() + * + * @param string $faultcode Error code. + */ + function SOAP_Base($faultcode = 'Client') + { + parent::SOAP_Base_Object($faultcode); + $this->_resetNamespaces(); + } + + function _resetNamespaces() + { + $this->_namespaces = array( + 'http://schemas.xmlsoap.org/soap/envelope/' => 'SOAP-ENV', + 'http://www.w3.org/2001/XMLSchema' => 'xsd', + 'http://www.w3.org/2001/XMLSchema-instance' => 'xsi', + 'http://schemas.xmlsoap.org/soap/encoding/' => 'SOAP-ENC'); + } + + /** + * Sets the schema version used in the SOAP message. + * + * @access private + * @see $_XMLSchema + * + * @param string $schemaVersion The schema version. + */ + function _setSchemaVersion($schemaVersion) + { + if (!in_array($schemaVersion, $this->_XMLSchema)) { + return $this->_raiseSoapFault("unsuported XMLSchema $schemaVersion"); + } + $this->_XMLSchemaVersion = $schemaVersion; + $tmpNS = array_flip($this->_namespaces); + $tmpNS['xsd'] = $this->_XMLSchemaVersion; + $tmpNS['xsi'] = $this->_XMLSchemaVersion . '-instance'; + $this->_namespaces = array_flip($tmpNS); + } + + function _getNamespacePrefix($ns) + { + if ($this->_namespace && $ns == $this->_namespace) { + return ''; + } + if (isset($this->_namespaces[$ns])) { + return $this->_namespaces[$ns]; + } + $prefix = 'ns' . count($this->_namespaces); + $this->_namespaces[$ns] = $prefix; + return $prefix; + } + + function _getNamespaceForPrefix($prefix) + { + $flipped = array_flip($this->_namespaces); + if (isset($flipped[$prefix])) { + return $flipped[$prefix]; + } + return null; + } + + function _isSoapValue(&$value) + { + return is_a($value, 'SOAP_Value'); + } + + function _serializeValue(&$value, $name = '', $type = false, + $elNamespace = null, $typeNamespace = null, + $options = array(), $attributes = array(), + $artype = '') + { + $namespaces = array(); + $arrayType = $array_depth = $xmlout_value = null; + $typePrefix = $elPrefix = $xmlout_offset = $xmlout_arrayType = ''; + $xmlout_type = $xmlns = $ptype = $array_type_ns = ''; + + if (!$name || is_numeric($name)) { + $name = 'item'; + } + + if ($this->_wsdl) { + list($ptype, $arrayType, $array_type_ns, $array_depth) + = $this->_wsdl->getSchemaType($type, $name, $typeNamespace); + } + + if (!$arrayType) { + $arrayType = $artype; + } + if (!$ptype) { + $ptype = $this->_getType($value); + } + if (!$type) { + $type = $ptype; + } + + if (strcasecmp($ptype, 'Struct') == 0 || + strcasecmp($type, 'Struct') == 0) { + // Struct + $vars = null; + if (is_object($value)) { + $vars = get_object_vars($value); + } else { + $vars = &$value; + } + if (is_array($vars)) { + foreach (array_keys($vars) as $k) { + // Hide private vars. + if ($k[0] == '_') continue; + if (is_object($vars[$k])) { + if (is_a($vars[$k], 'SOAP_Value')) { + $xmlout_value .= $vars[$k]->serialize($this); + } else { + // XXX get the members and serialize them instead + // converting to an array is more overhead than we + // should really do. + $xmlout_value .= $this->_serializeValue(get_object_vars($vars[$k]), $k, false, $this->_section5 ? null : $elNamespace); + } + } else { + $xmlout_value .= $this->_serializeValue($vars[$k], $k, false, $this->_section5 ? null : $elNamespace); + } + } + } + } elseif (strcasecmp($ptype, 'Array') == 0 || + strcasecmp($type, 'Array') == 0) { + // Array. + $typeNamespace = SOAP_SCHEMA_ENCODING; + $orig_type = $type; + $type = 'Array'; + $numtypes = 0; + // XXX this will be slow on larger arrays. Basically, it flattens + // arrays to allow us to serialize multi-dimensional arrays. We + // only do this if arrayType is set, which will typically only + // happen if we are using WSDL + if (isset($options['flatten']) || + ($arrayType && + (strchr($arrayType, ',') || strstr($arrayType, '][')))) { + $numtypes = $this->_multiArrayType($value, $arrayType, + $ar_size, $xmlout_value); + } + + $array_type = $array_type_prefix = ''; + if ($numtypes != 1) { + $arrayTypeQName =& new QName($arrayType); + $arrayType = $arrayTypeQName->name; + $array_types = array(); + $array_val = null; + + // Serialize each array element. + $ar_size = count($value); + foreach ($value as $array_val) { + if ($this->_isSoapValue($array_val)) { + $array_type = $array_val->type; + $array_types[$array_type] = 1; + $array_type_ns = $array_val->type_namespace; + $xmlout_value .= $array_val->serialize($this); + } else { + $array_type = $this->_getType($array_val); + $array_types[$array_type] = 1; + $xmlout_value .= $this->_serializeValue($array_val, 'item', $array_type, $this->_section5 ? null : $elNamespace); + } + } + + $xmlout_offset = ' SOAP-ENC:offset="[0]"'; + if (!$arrayType) { + $numtypes = count($array_types); + if ($numtypes == 1) { + $arrayType = $array_type; + } + // Using anyType is more interoperable. + if ($array_type == 'Struct') { + $array_type = ''; + } elseif ($array_type == 'Array') { + $arrayType = 'anyType'; + $array_type_prefix = 'xsd'; + } else { + if (!$arrayType) { + $arrayType = $array_type; + } + } + } + } + if (!$arrayType || $numtypes > 1) { + // Should reference what schema we're using. + $arrayType = 'xsd:anyType'; + } else { + if ($array_type_ns) { + $array_type_prefix = $this->_getNamespacePrefix($array_type_ns); + } elseif (isset($this->_typemap[$this->_XMLSchemaVersion][$arrayType])) { + $array_type_prefix = $this->_namespaces[$this->_XMLSchemaVersion]; + } + if ($array_type_prefix) { + $arrayType = $array_type_prefix . ':' . $arrayType; + } + } + + $xmlout_arrayType = ' SOAP-ENC:arrayType="' . $arrayType; + if ($array_depth != null) { + for ($i = 0; $i < $array_depth; $i++) { + $xmlout_arrayType .= '[]'; + } + } + $xmlout_arrayType .= "[$ar_size]\""; + } elseif ($this->_isSoapValue($value)) { + $xmlout_value = $value->serialize($this); + } elseif ($type == 'string') { + $xmlout_value = htmlspecialchars($value); + } elseif ($type == 'rawstring') { + $xmlout_value =& $value; + } elseif ($type == 'boolean') { + $xmlout_value = $value ? 'true' : 'false'; + } else { + $xmlout_value =& $value; + } + + // Add namespaces. + if ($elNamespace) { + $elPrefix = $this->_getNamespacePrefix($elNamespace); + if ($elPrefix) { + $xmlout_name = "$elPrefix:$name"; + } else { + $xmlout_name = $name; + } + } else { + $xmlout_name = $name; + } + + if ($typeNamespace) { + $typePrefix = $this->_getNamespacePrefix($typeNamespace); + if ($typePrefix) { + $xmlout_type = "$typePrefix:$type"; + } else { + $xmlout_type = $type; + } + } elseif ($type && + isset($this->_typemap[$this->_XMLSchemaVersion][$type])) { + $typePrefix = $this->_namespaces[$this->_XMLSchemaVersion]; + if ($typePrefix) { + $xmlout_type = "$typePrefix:$type"; + } else { + $xmlout_type = $type; + } + } + + // Handle additional attributes. + $xml_attr = ''; + if (count($attributes)) { + foreach ($attributes as $k => $v) { + $kqn =& new QName($k); + $vqn =& new QName($v); + $xml_attr .= ' ' . $kqn->fqn() . '="' . $vqn->fqn() . '"'; + } + } + + // Store the attachment for mime encoding. + if (isset($options['attachment']) && + !PEAR::isError($options['attachment'])) { + $this->__attachments[] = $options['attachment']; + } + + if ($this->_section5) { + if ($xmlout_type) { + $xmlout_type = " xsi:type=\"$xmlout_type\""; + } + if (is_null($xmlout_value)) { + $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" . + "$xml_attr xsi:nil=\"true\"/>"; + } else { + $xml = "\r\n<$xmlout_name$xmlout_type$xmlns$xmlout_arrayType" . + "$xmlout_offset$xml_attr>$xmlout_value"; + } + } else { + if (is_null($xmlout_value)) { + $xml = "\r\n<$xmlout_name$xmlns$xml_attr/>"; + } else { + $xml = "\r\n<$xmlout_name$xmlns$xml_attr>" . + $xmlout_value . ""; + } + } + + return $xml; + } + + /** + * Converts a PHP type to a SOAP type. + * + * @access private + * + * @param string $value The value to inspect. + * + * @return string The value's SOAP type. + */ + function _getType(&$value) + { + global $SOAP_OBJECT_STRUCT, $SOAP_RAW_CONVERT; + + $type = gettype($value); + switch ($type) { + case 'object': + if (is_a($value, 'soap_value')) { + $type = $value->type; + } else { + $type = 'Struct'; + } + break; + + case 'array': + // Hashes are always handled as structs. + if ($this->_isHash($value)) { + $type = 'Struct'; + } else { + $ar_size = count($value); + reset($value); + $key1 = key($value); + if ($ar_size > 0 && is_a($key1, 'SOAP_Value')) { + // FIXME: for non-wsdl structs that are all the same type + $key2 = key($value); + if ($ar_size > 1 && + $this->_isSoapValue($key1) && + $this->_isSoapValue($key2) && + $key1->name != $key2->name) { + // This is a struct, not an array. + $type = 'Struct'; + } else { + $type = 'Array'; + } + } else { + $type = 'Array'; + } + } + break; + + case 'integer': + case 'long': + $type = 'int'; + break; + + case 'boolean': + break; + + case 'double': + // double is deprecated in PHP 4.2 and later. + $type = 'float'; + break; + + case 'null': + $type = ''; + break; + + case 'string': + if ($SOAP_RAW_CONVERT) { + if (is_numeric($value)) { + if (strstr($value, '.')) { + $type = 'float'; + } else { + $type = 'int'; + } + } else { + if (SOAP_Type_hexBinary::is_hexbin($value)) { + $type = 'hexBinary'; + } else { + if ($this->_isBase64($value)) { + $type = 'base64Binary'; + } else { + $dt =& new SOAP_Type_dateTime($value); + if ($dt->toUnixtime() != -1) { + $type = 'dateTime'; + } + } + } + } + } + break; + + default: + break; + } + + return $type; + } + + function _multiArrayType(&$value, &$type, &$size, &$xml) + { + $sz = count($value); + if (is_array($value)) { + // Seems we have a multi dimensional array, figure it out if we + // do. + $c = count($value); + for ($i = 0; $i < $c; $i++) { + $this->_multiArrayType($value[$i], $type, $size, $xml); + } + + if ($size) { + $size = $sz. ',' . $size; + } else { + $size = $sz; + } + + return 1; + } else { + if (is_object($value)) { + $type = $value->type; + $xml .= $value->serialize($this); + } else { + $type = $this->_getType($value); + $xml .= $this->_serializeValue($value, 'item', $type); + } + } + $size = null; + + return 1; + } + + /** + * Returns whether a string is base64 encoded data. + * + * @param string $value The string to check. + * + * @return boolean True if the specified value seems to be base64 encoded. + */ + function _isBase64(&$value) + { + $l = strlen($value); + if ($l) { + return $value[$l - 1] == '=' && + preg_match('/[A-Za-z=\/\+]+/', $value); + } + return false; + } + + /** + * Returns whether a type is a base64 type. + * + * @param string $type A type name. + * + * @return boolean True if the type name is a base64 type. + */ + function _isBase64Type($type) + { + return $type == 'base64' || $type == 'base64Binary'; + } + + /** + * Returns whether an array is a hash. + * + * @param array $a An array to check. + * + * @return boolean True if the specified array is a hash. + */ + function _isHash(&$a) + { + // I really dislike having to loop through this in PHP code, really + // large arrays will be slow. We need a C function to do this. + $names = array(); + $it = 0; + foreach ($a as $k => $v) { + // Checking the type is faster than regexp. + $t = gettype($k); + if ($t != 'integer') { + return true; + } elseif ($this->_isSoapValue($v)) { + $names[$v->name] = 1; + } + // If someone has a large hash they should really be defining the + // type. + if ($it++ > 10) { + return false; + } + } + return count($names)>1; + } + + function _un_htmlentities($string) + { + $trans_tbl = get_html_translation_table(HTML_ENTITIES); + $trans_tbl = array_flip($trans_tbl); + return strtr($string, $trans_tbl); + } + + function &_decode(&$soapval) + { + global $SOAP_OBJECT_STRUCT; + + if (!$this->_isSoapValue($soapval)) { + return $soapval; + } elseif (is_array($soapval->value)) { + if ($SOAP_OBJECT_STRUCT && $soapval->type != 'Array') { + $classname = $this->_defaultObjectClassname; + if (isset($this->_type_translation[$soapval->tqn->fqn()])) { + // This will force an error in PHP if the class does not + // exist. + $classname = $this->_type_translation[$soapval->tqn->fqn()]; + } elseif (isset($this->_type_translation[$soapval->type])) { + // This will force an error in PHP if the class does not + // exist. + $classname = $this->_type_translation[$soapval->type]; + } elseif ($this->_auto_translation) { + if (class_exists($soapval->type)) { + $classname = $soapval->type; + } elseif ($this->_wsdl) { + $t = $this->_wsdl->getComplexTypeNameForElement($soapval->name, $soapval->namespace); + if ($t && class_exists($t)) { + $classname = $t; + } + } + } + $return =& new $classname; + } else { + $return = array(); + } + + $counter = 1; + $isstruct = !$SOAP_OBJECT_STRUCT || !is_array($return); + foreach ($soapval->value as $item) { + if (is_object($return)) { + if ($this->_wsdl) { + // Get this child's WSDL information. + // /$soapval->ns/$soapval->type/$item->ns/$item->name + $child_type = $this->_wsdl->getComplexTypeChildType( + $soapval->namespace, + $soapval->name, + $item->namespace, + $item->name); + if ($child_type) { + $item->type = $child_type; + } + } + if (!$isstruct || $item->type == 'Array') { + if (isset($return->{$item->name}) && + is_object($return->{$item->name})) { + $return->{$item->name} =& $this->_decode($item); + } elseif (isset($return->{$item->name}) && + is_array($return->{$item->name})) { + $return->{$item->name}[] = $this->_decode($item); + } elseif (is_array($return)) { + $return[] =& $this->_decode($item); + } else { + $return->{$item->name} =& $this->_decode($item); + } + } elseif (isset($return->{$item->name})) { + $isstruct = false; + if (count(get_object_vars($return)) == 1) { + $d =& $this->_decode($item); + $return = array($return->{$item->name}, $d); + } else { + $d =& $this->_decode($item); + $return->{$item->name} = array($return->{$item->name}, $d); + } + } else { + $return->{$item->name} =& $this->_decode($item); + } + // Set the attributes as members in the class. + if (method_exists($return, '__set_attribute')) { + foreach ($soapval->attributes as $key => $value) { + call_user_func_array(array(&$return, + '__set_attribute'), + array($key, $value)); + } + } + } else { + if ($soapval->arrayType && $this->_isSoapValue($item)) { + if ($this->_isBase64Type($item->type) && + !$this->_isBase64Type($soapval->arrayType)) { + // Decode the value if we're losing the base64 + // type information. + $item->value = base64_decode($item->value); + } + $item->type = $soapval->arrayType; + } + if (!$isstruct) { + $return[] = $this->_decode($item); + } elseif (isset($return[$item->name])) { + $isstruct = false; + $d =& $this->_decode($item); + $return = array($return[$item->name], $d); + } else { + $return[$item->name] = $this->_decode($item); + } + } + } + + return $return; + } + + if ($soapval->type == 'boolean') { + if ($soapval->value != '0' && + strcasecmp($soapval->value, 'false') != 0) { + $soapval->value = true; + } else { + $soapval->value = false; + } + } elseif ($soapval->type && + isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type])) { + // If we can, set variable type. + settype($soapval->value, + $this->_typemap[SOAP_XML_SCHEMA_VERSION][$soapval->type]); + } + + if ($this->_isBase64Type($soapval->type)) { + return base64_decode($soapval->value); + } else { + return $soapval->value; + } + } + + /** + * Creates the SOAP envelope with the SOAP envelop data. + * + * @access private + * + * @param + * @param array $headers + * @param string $encoding + * @param array $options + * + * @return string + */ + function _makeEnvelope(&$method, &$headers, + $encoding = SOAP_DEFAULT_ENCODING, + $options = array()) + { + $smsg = $header_xml = $ns_string = ''; + + if ($headers) { + $c = count($headers); + for ($i = 0; $i < $c; $i++) { + $header_xml .= $headers[$i]->serialize($this); + } + $header_xml = "\r\n$header_xml\r\n\r\n"; + } + + if (!isset($options['input']) || $options['input'] == 'parse') { + if (is_array($method)) { + $c = count($method); + for ($i = 0; $i < $c; $i++) { + $smsg .= $method[$i]->serialize($this); + } + } else { + $smsg = $method->serialize($this); + } + } else { + $smsg = $method; + } + $body = "\r\n" . $smsg . "\r\n\r\n"; + + foreach ($this->_namespaces as $k => $v) { + $ns_string .= " xmlns:$v=\"$k\"\r\n"; + } + if ($this->_namespace) { + $ns_string .= " xmlns=\"{$this->_namespace}\"\r\n"; + } + + /* If 'use' == 'literal', we do not put in the encodingStyle. This is + * denoted by $this->_section5 being false. 'use' can be defined at a + * more granular level than we are dealing with here, so this does not + * work for all services. */ + $xml = "\r\n\r\n". + "_section5 ? ' SOAP-ENV:encodingStyle="' . SOAP_SCHEMA_ENCODING . '"' : ''). + ">\r\n". + "$header_xml$body\r\n"; + + return $xml; + } + + function _makeMimeMessage(&$xml, $encoding = SOAP_DEFAULT_ENCODING) + { + global $SOAP_options; + + if (!isset($SOAP_options['Mime'])) { + return $this->_raiseSoapFault('Mime is not installed'); + } + + // Encode any attachments. + // See http://www.w3.org/TR/SOAP-attachments + // Now we have to mime encode the message. + $params = array('content_type' => 'multipart/related; type=text/xml'); + $msg =& new Mail_mimePart('', $params); + + // Add the xml part. + $params['content_type'] = 'text/xml'; + $params['charset'] = $encoding; + $params['encoding'] = 'base64'; + $msg->addSubPart($xml, $params); + + // Add the attachements + $c = count($this->__attachments); + for ($i = 0; $i < $c; $i++) { + $attachment =& $this->__attachments[$i]; + $msg->addSubPart($attachment['body'], $attachment); + } + + return $msg->encode(); + } + + // TODO: this needs to be used from the Transport system. + function _makeDIMEMessage($xml) + { + global $SOAP_options; + + if (!isset($SOAP_options['DIME'])) { + return $this->_raiseSoapFault('DIME is not installed'); + } + + // Encode any attachments. + // See http://search.ietf.org/internet-drafts/draft-nielsen-dime-soap-00.txt + // Now we have to DIME encode the message + $dime =& new Net_DIME_Message(); + $msg = $dime->encodeData($xml, SOAP_ENVELOP, null, NET_DIME_TYPE_URI); + + // Add the attachments. + $c = count($this->__attachments); + for ($i = 0; $i < $c; $i++) { + $attachment =& $this->__attachments[$i]; + $msg .= $dime->encodeData($attachment['body'], + $attachment['content_type'], + $attachment['cid'], + NET_DIME_TYPE_MEDIA); + } + $msg .= $dime->endMessage(); + + return $msg; + } + + function _decodeMimeMessage(&$data, &$headers, &$attachments) + { + global $SOAP_options; + + if (!isset($SOAP_options['Mime'])) { + $this->_raiseSoapFault('Mime Unsupported, install PEAR::Mail::Mime', '', '', 'Server'); + return; + } + + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + // Lame thing to have to do for decoding. + $decoder =& new Mail_mimeDecode($data); + $structure = $decoder->decode($params); + + if (isset($structure->body)) { + $data = $structure->body; + $headers = $structure->headers; + + return; + } elseif (isset($structure->parts)) { + $data = $structure->parts[0]->body; + $headers = array_merge($structure->headers, + $structure->parts[0]->headers); + if (count($structure->parts) > 1) { + $mime_parts = array_splice($structure->parts,1); + // Prepare the parts for the SOAP parser. + + $c = count($mime_parts); + for ($i = 0; $i < $c; $i++) { + $p =& $mime_parts[$i]; + if (isset($p->headers['content-location'])) { + // TODO: modify location per SwA note section 3 + // http://www.w3.org/TR/SOAP-attachments + $attachments[$p->headers['content-location']] = $p->body; + } else { + $cid = 'cid:' . substr($p->headers['content-id'], 1, -1); + $attachments[$cid] = $p->body; + } + } + } + + return; + } + + $this->_raiseSoapFault('Mime parsing error', '', '', 'Server'); + } + + function _decodeDIMEMessage(&$data, &$headers, &$attachments) + { + global $SOAP_options; + + if (!isset($SOAP_options['DIME'])) { + $this->_raiseSoapFault('DIME Unsupported, install PEAR::Net::DIME', '', '', 'Server'); + return; + } + + // This SHOULD be moved to the transport layer, e.g. PHP itself should + // handle parsing DIME ;) + $dime =& new Net_DIME_Message(); + $err = $dime->decodeData($data); + if (PEAR::isError($err)) { + $this->_raiseSoapFault('Failed to decode the DIME message!', '', '', 'Server'); + return; + } + if (strcasecmp($dime->parts[0]['type'], SOAP_ENVELOP) != 0) { + $this->_raiseSoapFault('DIME record 1 is not a SOAP envelop!', '', '', 'Server'); + return; + } + + $data = $dime->parts[0]['data']; + // Fake it for now. + $headers['content-type'] = 'text/xml'; + $c = count($dime->parts); + for ($i = 0; $i < $c; $i++) { + $part =& $dime->parts[$i]; + // We need to handle URI's better. + $id = strncmp($part['id'], 'cid:', 4) + ? 'cid:' . $part['id'] + : $part['id']; + $attachments[$id] = $part['data']; + } + } + + function __set_type_translation($type, $class = null) + { + $tq =& new QName($type); + if (!$class) { + $class = $tq->name; + } + $this->_type_translation[$type]=$class; + } + +} + +/** + * Class used to handle QNAME values in XML. + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + */ +class QName +{ + var $name = ''; + var $ns = ''; + var $namespace=''; + + function QName($name, $namespace = '') + { + if ($name && $name[0] == '{') { + preg_match('/\{(.*?)\}(.*)/', $name, $m); + $this->name = $m[2]; + $this->namespace = $m[1]; + } elseif (substr_count($name, ':') == 1) { + $s = explode(':', $name); + $s = array_reverse($s); + $this->name = $s[0]; + $this->ns = $s[1]; + $this->namespace = $namespace; + } else { + $this->name = $name; + $this->namespace = $namespace; + } + + // A little more magic than should be in a qname. + $p = strpos($this->name, '['); + if ($p) { + // TODO: Need to re-examine this logic later. + // Chop off []. + $this->arraySize = explode(',', substr($this->name, $p + 1, -$p - 2)); + $this->arrayInfo = substr($this->name, $p); + $this->name = substr($this->name, 0, $p); + } + } + + function fqn() + { + if ($this->namespace) { + return '{' . $this->namespace . '}' . $this->name; + } elseif ($this->ns) { + return $this->ns . ':' . $this->name; + } + return $this->name; + } + +} diff --git a/thirdparty/pear/SOAP/Disco.php b/thirdparty/pear/SOAP/Disco.php new file mode 100644 index 0000000..482efd6 --- /dev/null +++ b/thirdparty/pear/SOAP/Disco.php @@ -0,0 +1,384 @@ + + * @author Chuck Hagenbuch + * @author Jan Schneider + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; + +class SOAP_DISCO_Server extends SOAP_Base_Object { + + var $namespaces = array(SCHEMA_WSDL => 'wsdl', SCHEMA_SOAP => 'soap'); + var $import_ns = array(); + var $wsdl = ''; + var $disco = ''; + var $_wsdl = array(); + var $_disco = array(); + var $_service_name = ''; + var $_service_ns = ''; + var $_service_desc = ''; + var $_portname = ''; + var $_bindingname = ''; + var $soap_server = NULL; + + + function SOAP_DISCO_Server($soap_server, $service_name, $service_desc = '', + $import_ns = null) + { + parent::SOAP_Base_Object('Server'); + + if ( !is_object($soap_server) + || !get_class($soap_server) == 'soap_server') return; + + $this->_service_name = $service_name; + $this->_service_ns = "urn:$service_name"; + $this->_service_desc = $service_desc; + $this->import_ns = isset($import_ns) ? $import_ns : $this->import_ns; + $this->soap_server = $soap_server; + $this->host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost'; + } + + function getDISCO() + { + $this->_generate_DISCO(); + return $this->disco; + } + + function getWSDL() + { + $this->_generate_WSDL(); + return $this->wsdl; + } + + function _generate_DISCO() + { + // DISCO + $this->_disco['disco:discovery']['attr']['xmlns:disco'] = SCHEMA_DISCO; + $this->_disco['disco:discovery']['attr']['xmlns:scl'] = SCHEMA_DISCO_SCL; + $this->_disco['disco:discovery']['scl:contractRef']['attr']['ref'] = + (array_key_exists('HTTPS', $_SERVER) && $_SERVER['HTTPS'] == 'on') + ? 'https://' . $this->host . $_SERVER['PHP_SELF'] . '?wsdl' + : 'http://' . $this->host . $_SERVER['PHP_SELF'] . '?wsdl'; + + // generate disco xml + $this->_generate_DISCO_XML($this->_disco); + } + + function _generate_WSDL() + { + // WSDL + if (is_array($this->soap_server->_namespaces)) { + // need to get: typens, xsd & SOAP-ENC + $flipped = array_flip($this->soap_server->_namespaces); + $this->namespaces[$this->_service_ns] = 'tns'; + $this->namespaces[$flipped['xsd']] = 'xsd'; + $this->namespaces[$flipped['SOAP-ENC']] = 'SOAP-ENC'; + } + + // DEFINITIONS + $this->_wsdl['definitions']['attr']['name'] = $this->_service_name; + $this->_wsdl['definitions']['attr']['targetNamespace'] = $this->_service_ns; + foreach ($this->namespaces as $ns => $prefix) { + $this->_wsdl['definitions']['attr']['xmlns:' . $prefix] = $ns; + } + $this->_wsdl['definitions']['attr']['xmlns'] = SCHEMA_WSDL; + + // Import namespaces. Seems to not work yet: wsdl.exe fom .NET can't + // handle imported complete wsdl-definitions. + if (count($this->import_ns)) { + $i = 0; + foreach ($this->import_ns as $_ns => $_location) { + $this->_wsdl['definitions']['import'][$i]['attr']['location'] = $_location; + $this->_wsdl['definitions']['import'][$i]['attr']['namespace'] = $_ns; + $i++; + } + } + $this->_wsdl['definitions']['types']['attr']['xmlns']='http://schemas.xmlsoap.org/wsdl/'; + $this->_wsdl['definitions']['types']['schema']=array(); + + // Placeholder for messages + $this->_wsdl['definitions']['message'] = array(); + + // PORTTYPE-NAME + $this->_portname = $this->_service_name . 'Port'; + $this->_wsdl['definitions']['portType']['attr']['name'] = $this->_portname; + + // BINDING-NAME + $this->_bindingname = $this->_service_name . 'Binding'; + $this->_wsdl['definitions']['binding']['attr']['name'] = $this->_bindingname; + $this->_wsdl['definitions']['binding']['attr']['type'] = 'tns:' . $this->_portname; + $this->_wsdl['definitions']['binding']['soap:binding']['attr']['style'] = 'rpc'; + $this->_wsdl['definitions']['binding']['soap:binding']['attr']['transport'] = SCHEMA_SOAP_HTTP; + + // SERVICE + $this->_wsdl['definitions']['service']['attr']['name'] = $this->_service_name . 'Service'; + $this->_wsdl['definitions']['service']['documentation']['attr'] = ''; + $this->_wsdl['definitions']['service']['documentation'] = htmlentities($this->_service_desc); + $this->_wsdl['definitions']['service']['port']['attr']['name'] = $this->_portname; + $this->_wsdl['definitions']['service']['port']['attr']['binding'] = 'tns:' . $this->_bindingname; + $this->_wsdl['definitions']['service']['port']['soap:address']['attr']['location'] = + (array_key_exists('HTTPS', $_SERVER) && $_SERVER['HTTPS'] == 'on') + ? 'https://' . $this->host . $_SERVER['PHP_SELF'] + : 'http://' . $this->host . $_SERVER['PHP_SELF']; + + // + $dispatch_keys = array_keys($this->soap_server->dispatch_objects); + $dc = count($dispatch_keys); + for ($di = 0; $di < $dc; $di++) { + $namespace = $dispatch_keys[$di]; + $namespace_objects =& $this->soap_server->dispatch_objects[$namespace]; + $oc = count($namespace_objects); + for ($oi = 0; $oi < $oc; $oi++) { + $object = $namespace_objects[$oi]; + // types definitions + $this->addSchemaFromMap($object->__typedef); + // MESSAGES + $this->addMethodsFromMap($object->__dispatch_map, $namespace, get_class($object)); + } + } + if (isset($server->dispatch_map)) { + $this->addMethodsFromMap($server->dispatch_map, $namespace); + } + + // generate wsdl + $this->_generate_WSDL_XML(); + } + + function &_getSchema($namespace) + { + // SCHEMA + $c = count($this->_wsdl['definitions']['types']['schema']); + for($i = 0; $i < $c; $i++) { + if ($this->_wsdl['definitions']['types']['schema'][$i]['attr']['targetNamespace'] == $namespace) { + return $this->_wsdl['definitions']['types']['schema'][$i]; + } + } + + // don't have this namespace + $schema = array(); + $schema['attr'] = array(); + $schema['complexType'] = array(); + $schema['attr']['xmlns'] = array_search('xsd',$this->namespaces); + $schema['attr']['targetNamespace'] = $namespace; + $this->_wsdl['definitions']['types']['schema'][] =& $schema; + + return $schema; + } + + function addSchemaFromMap(&$map) + { + if (!$map) { + return; + } + + foreach ($map as $_type_name => $_type_def) { + list($typens,$type) = $this->_getTypeNs($_type_name); + if ($typens == 'xsd') { + // cannot add to xsd, lets use method_namespace + $typens = 'tns'; + } + $schema =& $this->_getSchema(array_search($typens, $this->namespaces)); + if (!$this->_ifComplexTypeExists($schema['complexType'], $type)) { + $ctype =& $schema['complexType'][]; + $ctype['attr']['name'] = $type; + foreach ($_type_def as $_varname => $_vartype) { + if (!is_int($_varname)) { + list($_vartypens,$_vartype) = $this->_getTypeNs($_vartype); + $ctype['all']['attr'] = ''; + $el =& $ctype['all']['element'][]; + $el['attr']['name'] = $_varname; + $el['attr']['type'] = $_vartypens . ':' . $_vartype; + } else { + $ctype['complexContent']['attr'] = ''; + $ctype['complexContent']['restriction']['attr']['base'] = 'SOAP-ENC:Array'; + foreach ($_vartype as $array_var => $array_type) { + list($_vartypens, $_vartype) = $this->_getTypeNs($array_type); + $ctype['complexContent']['restriction']['attribute']['attr']['ref'] = 'SOAP-ENC:arrayType'; + $ctype['complexContent']['restriction']['attribute']['attr']['wsdl:arrayType'] = $_vartypens . ':' . $_vartype . '[]'; + } + } + } + } + } + } + + function addMethodsFromMap(&$map, $namespace, $classname = null) + { + if (!$map) { + return; + } + + foreach ($map as $method_name => $method_types) { + if (array_key_exists('namespace', $method_types)) { + $method_namespace = $method_types['namespace']; + } else { + $method_namespace = $namespace; + } + // INPUT + if (isset($method_types['in']) && is_array($method_types['in'])) { + $input_message =& $this->_wsdl['definitions']['message'][]; + $input_message['attr']['name'] = $method_name . 'Request'; + foreach ($method_types['in'] as $name => $type) { + list($typens, $type) = $this->_getTypeNs($type); + $part =& $input_message['part'][]; + $part['attr']['name'] = $name; + $part['attr']['type'] = $typens . ':' . $type; + } + } + + // OUTPUT + if (isset($method_types['out']) && is_array($method_types['out'])) { + $output_message =& $this->_wsdl['definitions']['message'][]; + $output_message['attr']['name'] = $method_name . 'Response'; + foreach ($method_types['out'] as $name => $type) { + list($typens, $type) = $this->_getTypeNs($type); + $part =& $output_message['part'][]; + $part['attr']['name'] = $name; + $part['attr']['type'] = $typens . ':' . $type; + } + } + + // PORTTYPES + $operation =& $this->_wsdl['definitions']['portType']['operation'][]; + $operation['attr']['name'] = $method_name; + + // INPUT + $operation['input']['attr']['message'] = 'tns:' + . $input_message['attr']['name']; + + // OUTPUT + $operation['output']['attr']['message'] = 'tns:' + . $output_message['attr']['name']; + + // BINDING + $binding =& $this->_wsdl['definitions']['binding']['operation'][]; + $binding['attr']['name'] = $method_name; + $action = $method_namespace . '#' . ($classname ? $classname . '#' : '') . $method_name; + $binding['soap:operation']['attr']['soapAction'] = $action; + + // INPUT + $binding['input']['attr'] = ''; + $binding['input']['soap:body']['attr']['use'] = 'encoded'; + $binding['input']['soap:body']['attr']['namespace'] = $method_namespace; + $binding['input']['soap:body']['attr']['encodingStyle'] = SOAP_SCHEMA_ENCODING; + + // OUTPUT + $binding['output']['attr'] = ''; + $binding['output']['soap:body']['attr']['use'] = 'encoded'; + $binding['output']['soap:body']['attr']['namespace'] = $method_namespace; + $binding['output']['soap:body']['attr']['encodingStyle'] = SOAP_SCHEMA_ENCODING; + } + } + + function _generate_DISCO_XML($disco_array) + { + $disco = ''; + foreach ($disco_array as $key => $val) { + $disco .= $this->_arrayToNode($key,$val); + } + $this->disco = $disco; + } + + function _generate_WSDL_XML() + { + $wsdl = ''; + foreach ($this->_wsdl as $key => $val) { + $wsdl .= $this->_arrayToNode($key, $val); + } + $this->wsdl = $wsdl; + } + + function _arrayToNode($node_name = '', $array) + { + $return = ''; + if (is_array($array)) { + // we have a node if there's key 'attr' + if (array_key_exists('attr',$array)) { + $return .= "<$node_name"; + if (is_array($array['attr'])) { + foreach ($array['attr'] as $attr_name => $attr_value) { + $return .= " $attr_name=\"$attr_value\""; + } + } + + // unset 'attr' and proceed other childs... + unset($array['attr']); + + if (count($array) > 0) { + $i = 0; + foreach ($array as $child_node_name => $child_node_value) { + $return .= $i == 0 ? ">\n" : ''; + $return .= $this->_arrayToNode($child_node_name,$child_node_value); + $i++; + } + $return .= "\n"; + } else { + $return .= " />\n"; + } + } else { + // we have no 'attr' key in array - so it's list of nodes with + // the same name ... + foreach ($array as $child_node_name => $child_node_value) { + $return .= $this->_arrayToNode($node_name,$child_node_value); + } + } + } else { + // $array is not an array + if ($array !='') { + // and its not empty + $return .= "<$node_name>$array\n"; + } else { + // and its empty... + $return .= "<$node_name />\n"; + } + } + return $return; + } + + function _getTypeNs($type) + { + preg_match_all("'\{(.*)\}'sm", $type, $m); + if (isset($m[1][0]) && $m[1][0] != '') { + if (!array_key_exists($m[1][0],$this->namespaces)) { + $ns_pref = 'ns' . count($this->namespaces); + $this->namespaces[$m[1][0]] = $ns_pref; + $this->_wsdl['definitions']['attr']['xmlns:' . $ns_pref] = $m[1][0]; + } + $typens = $this->namespaces[$m[1][0]]; + $type = ereg_replace($m[0][0],'',$type); + } else { + $typens = 'xsd'; + } + return array($typens,$type); + } + + function _ifComplexTypeExists($typesArray, $type_name) + { + if (is_array($typesArray)) { + foreach ($typesArray as $index => $type_data) { + if ($typesArray[$index]['attr']['name'] == $type_name) { + return true; + } + } + } + return false; + } +} diff --git a/thirdparty/pear/SOAP/Fault.php b/thirdparty/pear/SOAP/Fault.php new file mode 100644 index 0000000..792b1ea --- /dev/null +++ b/thirdparty/pear/SOAP/Fault.php @@ -0,0 +1,136 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once('PEAR.php'); + +/** + * SOAP_Fault + * PEAR::Error wrapper used to match SOAP Faults to PEAR Errors + * + * @package SOAP + * @access public + * @author Shane Caraveo Port to PEAR and more + * @author Dietrich Ayala Original Author + */ +class SOAP_Fault extends PEAR_Error +{ + + /** + * Constructor + * + * @param string message string for fault + * @param mixed the faultcode + * @param mixed see PEAR::ERROR + * @param mixed see PEAR::ERROR + * @param array the userinfo array is used to pass in the + * SOAP actor and detail for the fault + */ + function SOAP_Fault($faultstring = 'unknown error', $faultcode = 'Client', $faultactor=NULL, $detail=NULL, $mode = null, $options = null) + { + parent::PEAR_Error($faultstring, $faultcode, $mode, $options, $detail); + if ($faultactor) $this->error_message_prefix = $faultactor; + } + + /** + * message + * + * returns a SOAP_Message class that can be sent as a server response + * + * @return SOAP_Message + * @access public + */ + function message() + { + $msg =& new SOAP_Base(); + $params = array(); + $params[] =& new SOAP_Value('faultcode', 'QName', 'SOAP-ENV:'.$this->code); + $params[] =& new SOAP_Value('faultstring', 'string', $this->message); + $params[] =& new SOAP_Value('faultactor', 'anyURI', $this->error_message_prefix); + if (isset($this->backtrace)) { + $params[] =& new SOAP_Value('detail', 'string', $this->backtrace); + } else { + $params[] =& new SOAP_Value('detail', 'string', $this->userinfo); + } + + $methodValue =& new SOAP_Value('{'.SOAP_ENVELOP.'}Fault', 'Struct', $params); + $headers = NULL; + return $msg->_makeEnvelope($methodValue, $headers); + } + + /** + * getFault + * + * returns a simple native php array containing the fault data + * + * @return array + * @access public + */ + function getFault() + { + global $SOAP_OBJECT_STRUCT; + if ($SOAP_OBJECT_STRUCT) { + $fault =& new stdClass(); + $fault->faultcode = $this->code; + $fault->faultstring = $this->message; + $fault->faultactor = $this->error_message_prefix; + $fault->detail = $this->userinfo; + return $fault; + } + return array( + 'faultcode' => $this->code, + 'faultstring' => $this->message, + 'faultactor' => $this->error_message_prefix, + 'detail' => $this->userinfo + ); + } + + /** + * getActor + * + * returns the SOAP actor for the fault + * + * @return string + * @access public + */ + function getActor() + { + return $this->error_message_prefix; + } + + /** + * getDetail + * + * returns the fault detail + * + * @return string + * @access public + */ + function getDetail() + { + return $this->userinfo; + } + +} +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/Parser.php b/thirdparty/pear/SOAP/Parser.php new file mode 100644 index 0000000..02aed73 --- /dev/null +++ b/thirdparty/pear/SOAP/Parser.php @@ -0,0 +1,518 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; +require_once 'SOAP/Value.php'; + +/** + * SOAP Parser + * + * This class is used by SOAP::Message and SOAP::Server to parse soap + * packets. Originally based on SOAPx4 by Dietrich Ayala + * http://dietrich.ganx4.com/soapx4 + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + * @author Dietrich Ayala Original Author + */ +class SOAP_Parser extends SOAP_Base +{ + var $status = ''; + var $position = 0; + var $pos_stat = 0; + var $depth = 0; + var $default_namespace = ''; + var $message = array(); + var $depth_array = array(); + var $previous_element = ''; + var $soapresponse = null; + var $soapheaders = null; + var $parent = 0; + var $root_struct_name = array(); + var $header_struct_name = array(); + var $curent_root_struct_name = ''; + var $entities = array ( '&' => '&', '<' => '<', '>' => '>', "'" => ''', '"' => '"' ); + var $root_struct = array(); + var $header_struct = array(); + var $curent_root_struct = 0; + var $references = array(); + var $need_references = array(); + var $XMLSchemaVersion; + var $bodyDepth; // used to handle non-root elements before root body element + + /** + * SOAP_Parser constructor + * + * @param string xml content + * @param string xml character encoding, defaults to 'UTF-8' + */ + function SOAP_Parser(&$xml, $encoding = SOAP_DEFAULT_ENCODING, $attachments = null) + { + parent::SOAP_Base('Parser'); + $this->_setSchemaVersion(SOAP_XML_SCHEMA_VERSION); + + $this->attachments = $attachments; + + // Check the xml tag for encoding. + if (preg_match('/<\?xml[^>]+encoding\s*?=\s*?(\'([^\']*)\'|"([^"]*)")[^>]*?[\?]>/', $xml, $m)) { + $encoding = strtoupper($m[2] ? $m[2] : $m[3]); + } + + // Determines where in the message we are + // (envelope,header,body,method). Check whether content has + // been read. + if (!empty($xml)) { + // Prepare the xml parser. + $parser = xml_parser_create($encoding); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($parser, $this); + xml_set_element_handler($parser, 'startElement', 'endElement'); + xml_set_character_data_handler($parser, 'characterData'); + + // Some lame soap implementations add null bytes at the + // end of the soap stream, and expat choaks on that. + if ($xml[strlen($xml) - 1] == 0) { + $xml = trim($xml); + } + + // Parse the XML file. + if (!xml_parse($parser, $xml, true)) { + $err = sprintf('XML error on line %d col %d byte %d %s', + xml_get_current_line_number($parser), + xml_get_current_column_number($parser), + xml_get_current_byte_index($parser), + xml_error_string(xml_get_error_code($parser))); + $this->_raiseSoapFault($err,htmlspecialchars($xml)); + } + xml_parser_free($parser); + } + } + + + /** + * domulti + * recurse to build a multi-dim array, used by buildResponse + * + * @access private + */ + function domulti($d, &$ar, &$r, &$v, $ad=0) + { + if ($d) { + $this->domulti($d-1, $ar, $r[$ar[$ad]], $v, $ad+1); + } else { + $r = $v; + } + } + + /** + * buildResponse + * loop through msg, building response structures + * + * @param int position + * @return SOAP_Value + * @access private + */ + function &buildResponse($pos) + { + $response = null; + + if (isset($this->message[$pos]['children'])) { + $children = explode('|', $this->message[$pos]['children']); + + foreach ($children as $c => $child_pos) { + if ($this->message[$child_pos]['type'] != null) { + $response[] =& $this->buildResponse($child_pos); + } + } + if (array_key_exists('arraySize', $this->message[$pos])) { + $ardepth = count($this->message[$pos]['arraySize']); + if ($ardepth > 1) { + $ar = array_pad(array(), $ardepth, 0); + if (array_key_exists('arrayOffset', $this->message[$pos])) { + for ($i = 0; $i < $ardepth; $i++) { + $ar[$i] += $this->message[$pos]['arrayOffset'][$i]; + } + } + $elc = count($response); + for ($i = 0; $i < $elc; $i++) { + // recurse to build a multi-dimensional array + $this->domulti($ardepth, $ar, $newresp, $response[$i]); + + // increment our array pointers + $ad = $ardepth - 1; + $ar[$ad]++; + while ($ad > 0 && $ar[$ad] >= $this->message[$pos]['arraySize'][$ad]) { + $ar[$ad] = 0; + $ad--; + $ar[$ad]++; + } + } + $response = $newresp; + } elseif (isset($this->message[$pos]['arrayOffset']) && + $this->message[$pos]['arrayOffset'][0] > 0) { + // check for padding + $pad = $this->message[$pos]['arrayOffset'][0] + count($response) * -1; + $response = array_pad($response, $pad, null); + } + } + } + + // Build attributes. + $attrs = array(); + foreach ($this->message[$pos]['attrs'] as $atn => $atv) { + if (!strstr($atn, 'xmlns') && + !strpos($atn, ':')) { + $attrs[$atn] = $atv; + } + } + + // Add current node's value. + if ($response) { + $nqn =& new Qname($this->message[$pos]['name'], $this->message[$pos]['namespace']); + $tqn =& new Qname($this->message[$pos]['type'], $this->message[$pos]['type_namespace']); + $response =& new SOAP_Value($nqn->fqn(), $tqn->fqn(), $response, $attrs); + if (isset($this->message[$pos]['arrayType'])) { + $response->arrayType = $this->message[$pos]['arrayType']; + } + } else { + $nqn =& new Qname($this->message[$pos]['name'], $this->message[$pos]['namespace']); + $tqn =& new Qname($this->message[$pos]['type'], $this->message[$pos]['type_namespace']); + $response =& new SOAP_Value($nqn->fqn(), $tqn->fqn(), $this->message[$pos]['cdata'], $attrs); + } + + // handle header attribute that we need + if (array_key_exists('actor', $this->message[$pos])) { + $response->actor = $this->message[$pos]['actor']; + } + if (array_key_exists('mustUnderstand', $this->message[$pos])) { + $response->mustunderstand = $this->message[$pos]['mustUnderstand']; + } + return $response; + } + + /** + * startElement + * start-element handler used with xml parser + * + * @access private + */ + function startElement($parser, $name, $attrs) + { + // position in a total number of elements, starting from 0 + // update class level pos + $pos = $this->position++; + + // and set mine + $this->message[$pos] = array(); + $this->message[$pos]['type'] = ''; + $this->message[$pos]['type_namespace'] = ''; + $this->message[$pos]['cdata'] = ''; + $this->message[$pos]['pos'] = $pos; + $this->message[$pos]['id'] = ''; + + // parent/child/depth determinations + + // 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) { + if (isset($this->message[$this->parent]['children'])) + $this->message[$this->parent]['children'] .= "|$pos"; + else + $this->message[$this->parent]['children'] = $pos; + } + + // set my parent + $this->message[$pos]['parent'] = $this->parent; + + // set self as current value for this depth + $this->depth_array[$this->depth] = $pos; + // set self as current parent + $this->parent = $pos; + $qname =& new QName($name); + // set status + if (strcasecmp('envelope', $qname->name) == 0) { + $this->status = 'envelope'; + } elseif (strcasecmp('header', $qname->name) == 0) { + $this->status = 'header'; + $this->header_struct_name[] = $this->curent_root_struct_name = $qname->name; + $this->header_struct[] = $this->curent_root_struct = $pos; + $this->message[$pos]['type'] = 'Struct'; + } elseif (strcasecmp('body', $qname->name) == 0) { + $this->status = 'body'; + $this->bodyDepth = $this->depth; + + // Set method + } elseif ($this->status == 'body') { + // Is this element allowed to be a root? + // XXX this needs to be optimized, we loop through attrs twice now. + $can_root = $this->depth == $this->bodyDepth + 1; + if ($can_root) { + foreach ($attrs as $key => $value) { + if (stristr($key, ':root') && !$value) { + $can_root = FALSE; + } + } + } + + if ($can_root) { + $this->status = 'method'; + $this->root_struct_name[] = $this->curent_root_struct_name = $qname->name; + $this->root_struct[] = $this->curent_root_struct = $pos; + $this->message[$pos]['type'] = 'Struct'; + } + } + + // Set my status. + $this->message[$pos]['status'] = $this->status; + + // Set name. + $this->message[$pos]['name'] = htmlspecialchars($qname->name); + + // Set attributes. + $this->message[$pos]['attrs'] = $attrs; + + // Loop through attributes, logging ns and type declarations. + foreach ($attrs as $key => $value) { + // If ns declarations, add to class level array of valid + // namespaces. + $kqn =& new QName($key); + if ($kqn->ns == 'xmlns') { + $prefix = $kqn->name; + + if (in_array($value, $this->_XMLSchema)) { + $this->_setSchemaVersion($value); + } + + $this->_namespaces[$value] = $prefix; + + // Set method namespace. + } elseif ($key == 'xmlns') { + $qname->ns = $this->_getNamespacePrefix($value); + $qname->namespace = $value; + } elseif ($kqn->name == 'actor') { + $this->message[$pos]['actor'] = $value; + } elseif ($kqn->name == 'mustUnderstand') { + $this->message[$pos]['mustUnderstand'] = $value; + + // If it's a type declaration, set type. + } elseif ($kqn->name == 'type') { + $vqn =& new QName($value); + $this->message[$pos]['type'] = $vqn->name; + $this->message[$pos]['type_namespace'] = $this->_getNamespaceForPrefix($vqn->ns); + // Should do something here with the namespace of + // specified type? + + } elseif ($kqn->name == 'arrayType') { + $vqn =& new QName($value); + $this->message[$pos]['type'] = 'Array'; + if (isset($vqn->arraySize)) { + $this->message[$pos]['arraySize'] = $vqn->arraySize; + } + $this->message[$pos]['arrayType'] = $vqn->name; + + } elseif ($kqn->name == 'offset') { + $this->message[$pos]['arrayOffset'] = split(',', substr($value, 1, strlen($value) - 2)); + + } elseif ($kqn->name == 'id') { + // Save id to reference array. + $this->references[$value] = $pos; + $this->message[$pos]['id'] = $value; + + } elseif ($kqn->name == 'href') { + if ($value[0] == '#') { + $ref = substr($value, 1); + if (isset($this->references[$ref])) { + // cdata, type, inval. + $ref_pos = $this->references[$ref]; + $this->message[$pos]['children'] = &$this->message[$ref_pos]['children']; + $this->message[$pos]['cdata'] = &$this->message[$ref_pos]['cdata']; + $this->message[$pos]['type'] = &$this->message[$ref_pos]['type']; + $this->message[$pos]['arraySize'] = &$this->message[$ref_pos]['arraySize']; + $this->message[$pos]['arrayType'] = &$this->message[$ref_pos]['arrayType']; + } else { + // Reverse reference, store in 'need reference'. + if (!isset($this->need_references[$ref])) { + $this->need_references[$ref] = array(); + } + $this->need_references[$ref][] = $pos; + } + } elseif (isset($this->attachments[$value])) { + $this->message[$pos]['cdata'] = $this->attachments[$value]; + } + } + } + // See if namespace is defined in tag. + if (array_key_exists('xmlns:' . $qname->ns, $attrs)) { + $namespace = $attrs['xmlns:' . $qname->ns]; + } elseif ($qname->ns && !$qname->namespace) { + $namespace = $this->_getNamespaceForPrefix($qname->ns); + } else { + // Get namespace. + $namespace = $qname->namespace ? $qname->namespace : $this->default_namespace; + } + $this->message[$pos]['namespace'] = $namespace; + $this->default_namespace = $namespace; + } + + /** + * endElement + * end-element handler used with xml parser + * + * @access private + */ + function endElement($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--; + $qname =& new QName($name); + + // Get type if not explicitly declared in an xsi:type attribute. + // XXX check on integrating wsdl validation here + if ($this->message[$pos]['type'] == '') { + if (isset($this->message[$pos]['children'])) { + /* this is slow, need to look at some faster method + $children = explode('|', $this->message[$pos]['children']); + if (count($children) > 2 && + $this->message[$children[1]]['name'] == $this->message[$children[2]]['name']) { + $this->message[$pos]['type'] = 'Array'; + } else { + $this->message[$pos]['type'] = 'Struct'; + }*/ + $this->message[$pos]['type'] = 'Struct'; + } else { + $parent = $this->message[$pos]['parent']; + if ($this->message[$parent]['type'] == 'Array' && + array_key_exists('arrayType', $this->message[$parent])) { + $this->message[$pos]['type'] = $this->message[$parent]['arrayType']; + } else { + $this->message[$pos]['type'] = 'string'; + } + } + } + + // If tag we are currently closing is the method wrapper. + if ($pos == $this->curent_root_struct) { + $this->status = 'body'; + } elseif ($qname->name == 'Body' || $qname->name == 'Header') { + $this->status = 'envelope'; + } + + // Set parent back to my parent. + $this->parent = $this->message[$pos]['parent']; + + // Handle any reverse references now. + $idref = $this->message[$pos]['id']; + + if ($idref != '' && array_key_exists($idref, $this->need_references)) { + foreach ($this->need_references[$idref] as $ref_pos) { + // XXX is this stuff there already? + $this->message[$ref_pos]['children'] = &$this->message[$pos]['children']; + $this->message[$ref_pos]['cdata'] = &$this->message[$pos]['cdata']; + $this->message[$ref_pos]['type'] = &$this->message[$pos]['type']; + $this->message[$ref_pos]['arraySize'] = &$this->message[$pos]['arraySize']; + $this->message[$ref_pos]['arrayType'] = &$this->message[$pos]['arrayType']; + } + } + } + + /** + * characterData + * element content handler used with xml parser + * + * @access private + */ + function characterData($parser, $data) + { + $pos = $this->depth_array[$this->depth]; + if (isset($this->message[$pos]['cdata'])) { + $this->message[$pos]['cdata'] .= $data; + } else { + $this->message[$pos]['cdata'] = $data; + } + } + + /** + * Returns an array of responses. + * + * After parsing a SOAP message, use this to get the response. + * + * @return array + * @access public + */ + function &getResponse() + { + if (isset($this->root_struct[0]) && + $this->root_struct[0]) { + $response =& $this->buildResponse($this->root_struct[0]); + } else { + $response =& $this->_raiseSoapFault("couldn't build response"); + } + return $response; + } + + /** + * Returns an array of header responses. + * + * After parsing a SOAP message, use this to get the response. + * + * @return array + * @access public + */ + function &getHeaders() + { + if (isset($this->header_struct[0]) && + $this->header_struct[0]) { + $response = &$this->buildResponse($this->header_struct[0]); + } else { + // We don't fault if there are no headers; that can be handled by + // the application if necessary. + $response = null; + } + return $response; + } + + /** + * decodeEntities + * + * removes entities from text + * + * @param string + * @return string + * @access private + */ + function decodeEntities($text) + { + $trans_tbl = array_flip($this->entities); + return strtr($text, $trans_tbl); + } + +} diff --git a/thirdparty/pear/SOAP/Server.php b/thirdparty/pear/SOAP/Server.php new file mode 100644 index 0000000..6796939 --- /dev/null +++ b/thirdparty/pear/SOAP/Server.php @@ -0,0 +1,797 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; +require_once 'SOAP/Fault.php'; +require_once 'SOAP/Parser.php'; +require_once 'SOAP/Value.php'; +require_once 'SOAP/WSDL.php'; + +/** + * SOAP Server Class + * + * Originaly based on SOAPx4 by Dietrich Ayala + * http://dietrich.ganx4.com/soapx4 + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + * @author Dietrich Ayala Original Author + */ +class SOAP_Server extends SOAP_Base +{ + /** + * + * @var array + */ + var $dispatch_map = array(); // create empty dispatch map + var $dispatch_objects = array(); + var $soapobject = null; + var $call_methodname = null; + var $callHandler = null; + var $callValidation = true; + + /** + * A list of headers that are going to be sent back to the client. + * + * @var array + */ + var $headers = array(); + + /** + * + * @var string + */ + var $request = ''; + + /** + * + * @var string XML-Encoding + */ + var $xml_encoding = SOAP_DEFAULT_ENCODING; + var $response_encoding = 'UTF-8'; + + var $result = 'successful'; // for logging interop results to db + + var $endpoint = ''; // the uri to ME! + + var $service = ''; //soapaction header + var $method_namespace = null; + var $__options = array('use' => 'encoded', + 'style' => 'rpc', + 'parameters' => 0, + 'http_status_success' => '200 OK', + 'http_status_fault' => '500 SOAP Fault'); + + function SOAP_Server($options = null) + { + ini_set('track_errors', 1); + parent::SOAP_Base('Server'); + + if (is_array($options)) { + if (isset($options['use'])) { + $this->__options['use'] = $options['use']; + } + if (isset($options['style'])) { + $this->__options['style'] = $options['style']; + } + if (isset($options['parameters'])) { + $this->__options['parameters'] = $options['parameters']; + } + } + // assume we encode with section 5 + $this->_section5 = true; + if ($this->__options['use']=='literal') { + $this->_section5 = false; + } + } + + /** + * Error handler for errors that happen in proxied methods. + * + * To always return a valid SOAP response even on errors that don't happen + * in this code, the errors are catched, transformed to a SOAP fault and + * immediately sent to the client. + * + * @see http://www.php.net/set_error_handler + */ + function _errorHandler($errno, $errmsg, $filename, $linenum, $vars) + { + /* The error handler should ignore '0' errors, eg. hidden by @ - see + * the set_error_handler manual page. (thanks to Alan Knowles). */ + if (!$errno || $errno == E_NOTICE || + (defined('E_STRICT') && $errno == constant('E_STRICT'))) { + return; + } + + $this->fault =& new SOAP_Fault($errmsg, 'Server', 'PHP', "Errno: $errno\nFilename: $filename\nLineno: $linenum\n"); + + $this->_sendResponse(); + exit; + } + + function _getContentEncoding($content_type) + { + /* Get the character encoding of the incoming request treat incoming + * data as UTF-8 if no encoding set. */ + $this->xml_encoding = 'UTF-8'; + if (strpos($content_type, '=')) { + $enc = strtoupper(str_replace('"', '', substr(strstr($content_type, '='), 1))); + if (!in_array($enc, $this->_encodings)) { + return false; + } + $this->xml_encoding = $enc; + } + + return true; + } + + + /** + * Parses request and posts response. + */ + function service($data, $endpoint = '', $test = false) + { + $response = null; + $attachments = array(); + $useEncoding = 'DIME'; + + /* Figure out our endpoint. */ + $this->endpoint = $endpoint; + if (!$test && !$this->endpoint) { + /* We'll try to build our endpoint. */ + $this->endpoint = 'http://' . $_SERVER['SERVER_NAME']; + if ($_SERVER['SERVER_PORT']) { + $this->endpoint .= ':' . $_SERVER['SERVER_PORT']; + } + $this->endpoint .= $_SERVER['SCRIPT_NAME']; + } + + /* Get the character encoding of the incoming request treat incoming + * data as UTF-8 if no encoding set. */ + if (isset($_SERVER['CONTENT_TYPE'])) { + if (strcasecmp($_SERVER['CONTENT_TYPE'], 'application/dime') == 0) { + $this->_decodeDIMEMessage($data, $headers, $attachments); + $useEncoding = 'DIME'; + } elseif (stristr($_SERVER['CONTENT_TYPE'], 'multipart/related')) { + /* This is a mime message, let's decode it. */ + $data = 'Content-Type: ' . + stripslashes($_SERVER['CONTENT_TYPE']) . + "\r\n\r\n" . $data; + $this->_decodeMimeMessage($data, $headers, $attachments); + $useEncoding = 'Mime'; + } + if (!isset($headers['content-type'])) { + $headers['content-type'] = stripslashes($_SERVER['CONTENT_TYPE']); + } + if (!$this->fault && + !$this->_getContentEncoding($headers['content-type'])) { + $this->xml_encoding = SOAP_DEFAULT_ENCODING; + /* Found encoding we don't understand; return a fault. */ + $this->_raiseSoapFault('Unsupported encoding, use one of ISO-8859-1, US-ASCII, UTF-8', '', '', 'Server'); + } + } + + /* If this is not a POST with Content-Type text/xml, try to return a + * WSDL file. */ + if (!$this->fault && !$test && + ($_SERVER['REQUEST_METHOD'] != 'POST' || + strncmp($headers['content-type'], 'text/xml', 8) != 0)) { + /* This is not possibly a valid SOAP request, try to return a WSDL + * file. */ + $this->_raiseSoapFault('Invalid SOAP request, must be POST with content-type: text/xml, got: ' . (isset($headers['content-type']) ? $headers['content-type'] : 'Nothing!'), '', '', 'Server'); + } + + if (!$this->fault) { + /* $response is a SOAP_Msg object. */ + $soap_msg = $this->parseRequest($data, $attachments); + + /* Handle Mime or DIME encoding. */ + /* TODO: DIME decoding should move to the transport, do it here + * for now and for ease of getting it done. */ + if (count($this->__attachments)) { + if ($useEncoding == 'Mime') { + $soap_msg = $this->_makeMimeMessage($soap_msg); + } else { + // default is dime + $soap_msg = $this->_makeDIMEMessage($soap_msg); + $this->headers['Content-Type'] = 'application/dime'; + } + if (PEAR::isError($soap_msg)) { + return $this->_raiseSoapFault($soap_msg); + } + } + + if (is_array($soap_msg)) { + $response = $soap_msg['body']; + if (count($soap_msg['headers'])) { + $this->headers = $soap_msg['headers']; + } + } else { + $response = $soap_msg; + } + } + + $this->_sendResponse($response); + } + + /** + * Sends the final HTTP response to the client, including the HTTP header + * and the HTTP body. + * + * If an error happened, it returns a SOAP fault instead of the response + * body. + * + * @param string $response The response body. + */ + function _sendResponse($response = '') + { + /* Make distinction between the different SAPIs, running PHP as CGI or + * as a module. */ + if (stristr(php_sapi_name(), 'cgi') === 0) { + $hdrs_type = 'Status:'; + } else { + $hdrs_type = 'HTTP/1.1'; + } + + if ($this->fault) { + $hdrs = $hdrs_type . ' ' . $this->__options['http_status_fault'] . "\r\n"; + $response = $this->fault->message(); + } else { + $hdrs = $hdrs_type . ' ' . $this->__options['http_status_success'] . "\r\n"; + } + header($hdrs); + + $this->headers['Server'] = SOAP_LIBRARY_NAME; + if (!isset($this->headers['Content-Type'])) { + $this->headers['Content-Type'] = 'text/xml; charset=' . + $this->response_encoding; + } + $this->headers['Content-Length'] = strlen($response); + + foreach ($this->headers as $k => $v) { + header("$k: $v"); + $hdrs .= "$k: $v\r\n"; + } + + $this->response = $hdrs . "\r\n" . $response; + print $response; + } + + function &callMethod($methodname, &$args) + { + if ($this->callHandler) { + + $ret = @call_user_func_array($this->callHandler, array($methodname, $args)); + + return $ret; + } + + set_error_handler(array($this, '_errorHandler')); + + if ($args) { + /* Call method with parameters. */ + if (isset($this->soapobject) && is_object($this->soapobject)) { + $ret = @call_user_func_array(array(&$this->soapobject, $methodname), $args); + } else { + $ret = @call_user_func_array($methodname, $args); + } + } else { + /* Call method withour parameters. */ + if (is_object($this->soapobject)) { + $ret = @call_user_func(array(&$this->soapobject, $methodname)); + } else { + $ret = @call_user_func($methodname); + } + } + + restore_error_handler(); + + return $ret; + } + + /** + * Creates SOAP_Value objects with return values from method. + * Uses method signature to determine type. + * + * @param mixed $method_response The result(s). + * @param array|string $type The type(s) of the return value(s). + * @param string $return_name The name of the return value. + * @param string $namespace The namespace of the return value. + * + * @return array List of SOAP_Value objects. + */ + function buildResult(&$method_response, &$return_type, + $return_name = 'return', $namespace = '') + { + if (is_a($method_response, 'SOAP_Value')) { + $return_val = array($method_response); + } else { + if (is_array($return_type) && is_array($method_response)) { + $i = 0; + + foreach ($return_type as $key => $type) { + if (is_numeric($key)) { + $key = 'item'; + } + if (is_a($method_response[$i], 'SOAP_Value')) { + $return_val[] =& $method_response[$i++]; + } else { + $qn =& new QName($key, $namespace); + $return_val[] =& new SOAP_Value($qn->fqn(), $type, $method_response[$i++]); + } + } + } else { + if (is_array($return_type)) { + $keys = array_keys($return_type); + if (!is_numeric($keys[0])) { + $return_name = $keys[0]; + } + $values = array_values($return_type); + $return_type = $values[0]; + } + $qn =& new QName($return_name, $namespace); + $return_val = array(new SOAP_Value($qn->fqn(), $return_type, $method_response)); + } + } + return $return_val; + } + + function parseRequest($data = '', $attachments = null) + { + /* Parse response, get SOAP_Parser object. */ + $parser =& new SOAP_Parser($data, $this->xml_encoding, $attachments); + /* If fault occurred during message parsing. */ + if ($parser->fault) { + $this->fault = $parser->fault; + return null; + } + + /* Handle message headers. */ + $request_headers = $parser->getHeaders(); + $header_results = array(); + + if ($request_headers) { + if (!is_a($request_headers, 'SOAP_Value')) { + $this->_raiseSoapFault('Parser did not return SOAP_Value object: ' . $request_headers, '', '', 'Server'); + return null; + } + if ($request_headers->value) { + /* Handle headers now. */ + foreach ($request_headers->value as $header_val) { + $f_exists = $this->validateMethod($header_val->name, $header_val->namespace); + + /* TODO: this does not take into account message routing + * yet. */ + $myactor = !$header_val->actor || + $header_val->actor == 'http://schemas.xmlsoap.org/soap/actor/next' || + $header_val->actor == $this->endpoint; + + if (!$f_exists && $header_val->mustunderstand && $myactor) { + $this->_raiseSoapFault('I don\'t understand header ' . $header_val->name, '', '', 'MustUnderstand'); + return null; + } + + /* We only handle the header if it's for us. */ + $isok = $f_exists && $myactor; + + if ($isok) { + /* Call our header now! */ + $header_method = $header_val->name; + $header_data = array($this->_decode($header_val)); + /* If there are parameters to pass. */ + $hr =& $this->callMethod($header_method, $header_data); + if (PEAR::isError($hr)) { + $this->_raiseSoapDefault($hr); + return null; + } + $results = $this->buildResult($hr, $this->return_type, $header_method, $header_val->namespace); + $header_results[] = $results[0]; + } + } + } + } + + /* Handle the method call. */ + /* Evaluate message, getting back a SOAP_Value object. */ + $this->call_methodname = $this->methodname = $parser->root_struct_name[0]; + + /* Figure out the method namespace. */ + $this->method_namespace = $parser->message[$parser->root_struct[0]]['namespace']; + + if ($this->_wsdl) { + $this->_setSchemaVersion($this->_wsdl->xsd); + $dataHandler = $this->_wsdl->getDataHandler($this->methodname, $this->method_namespace); + if ($dataHandler) + $this->call_methodname = $this->methodname = $dataHandler; + + $this->_portName = $this->_wsdl->getPortName($this->methodname); + if (PEAR::isError($this->_portName)) { + $this->_raiseSoapFault($this->_portName); + return null; + } + $opData = $this->_wsdl->getOperationData($this->_portName, $this->methodname); + if (PEAR::isError($opData)) { + $this->_raiseSoapFault($opData); + return null; + } + $this->__options['style'] = $opData['style']; + $this->__options['use'] = $opData['output']['use']; + $this->__options['parameters'] = $opData['parameters']; + } + + /* Does method exist? */ + if (!$this->methodname || + !$this->validateMethod($this->methodname, $this->method_namespace)) { + $this->_raiseSoapFault('method "' . $this->method_namespace . $this->methodname . '" not defined in service', '', '', 'Server'); + return null; + } + + if (!$request_val = $parser->getResponse()) { + return null; + } + if (!is_a($request_val, 'SOAP_Value')) { + $this->_raiseSoapFault('Parser did not return SOAP_Value object: ' . $request_val, '', '', 'Server'); + return null; + } + + /* Verify that SOAP_Value objects in request match the methods + * signature. */ + if (!$this->verifyMethod($request_val)) { + /* verifyMethod() creates the fault. */ + return null; + } + + /* Need to set special error detection inside the value class to + * differentiate between no params passed, and an error decoding. */ + $request_data = $this->__decodeRequest($request_val); + if (PEAR::isError($request_data)) { + $this->_raiseSoapFault($request_data); + return null; + } + $method_response =& $this->callMethod($this->call_methodname, $request_data); + if (PEAR::isError($method_response)) { + $this->_raiseSoapFault($method_response); + return null; + } + + if ($this->__options['parameters'] || + !$method_response || + $this->__options['style']=='rpc') { + /* Get the method result. */ + if (is_null($method_response)) { + $return_val = null; + } else { + $return_val = $this->buildResult($method_response, $this->return_type); + } + + $qn =& new QName($this->methodname . 'Response', $this->method_namespace); + $methodValue =& new SOAP_Value($qn->fqn(), 'Struct', $return_val); + } else { + $methodValue =& $method_response; + } + return $this->_makeEnvelope($methodValue, $header_results, $this->response_encoding); + } + + function &__decodeRequest($request, $shift = false) + { + if (!$request) { + $decoded = null; + return $decoded; + } + + /* Check for valid response. */ + if (PEAR::isError($request)) { + $fault = &$this->_raiseSoapFault($request); + return $fault; + } else if (!is_a($request, 'SOAP_Value')) { + $fault = &$this->_raiseSoapFault('Invalid data in server::__decodeRequest'); + return $fault; + } + + /* Decode to native php datatype. */ + $requestArray = $this->_decode($request); + /* Fault? */ + if (PEAR::isError($requestArray)) { + $fault = &$this->_raiseSoapFault($requestArray); + return $fault; + } + if (is_object($requestArray) && + get_class($requestArray) == 'stdClass') { + $requestArray = get_object_vars($requestArray); + } elseif ($this->__options['style'] == 'document') { + $requestArray = array($requestArray); + } + if (is_array($requestArray)) { + if (isset($requestArray['faultcode']) || + isset($requestArray['SOAP-ENV:faultcode'])) { + $faultcode = $faultstring = $faultdetail = $faultactor = ''; + foreach ($requestArray as $k => $v) { + if (stristr($k, 'faultcode')) { + $faultcode = $v; + } + if (stristr($k, 'faultstring')) { + $faultstring = $v; + } + if (stristr($k, 'detail')) { + $faultdetail = $v; + } + if (stristr($k, 'faultactor')) { + $faultactor = $v; + } + } + $fault = &$this->_raiseSoapFault($faultstring, $faultdetail, $faultactor, $faultcode); + return $fault; + } + /* Return array of return values. */ + if ($shift && count($requestArray) == 1) { + $decoded = array_shift($requestArray); + return $decoded; + } + return $requestArray; + } + return $requestArray; + } + + function verifyMethod($request) + { + if (!$this->callValidation) { + return true; + } + + $params = $request->value; + + /* Get the dispatch map if one exists. */ + $map = null; + if (array_key_exists($this->methodname, $this->dispatch_map)) { + $map = $this->dispatch_map[$this->methodname]; + } elseif (isset($this->soapobject)) { + if (method_exists($this->soapobject, '__dispatch')) { + $map = $this->soapobject->__dispatch($this->methodname); + } elseif (method_exists($this->soapobject, $this->methodname)) { + /* No map, all public functions are SOAP functions. */ + return true; + } + } + if (!$map) { + $this->_raiseSoapFault('SOAP request specified an unhandled method "' . $this->methodname . '"', '', '', 'Client'); + return false; + } + + /* If we aliased the SOAP method name to a PHP function, change + * call_methodname so we do the right thing. */ + if (array_key_exists('alias', $map) && !empty($map['alias'])) { + $this->call_methodname = $map['alias']; + } + + /* If there are input parameters required. */ + if ($sig = $map['in']) { + $this->input_value = count($sig); + $this->return_type = false; + if (is_array($map['out'])) { + $this->return_type = count($map['out']) > 1 + ? $map['out'] + : array_shift($map['out']); + } + if (is_array($params)) { + /* Validate the number of parameters. */ + if (count($params) == count($sig)) { + /* Make array of param types. */ + foreach ($params as $param) { + $p[] = strtolower($param->type); + } + $sig_t = array_values($sig); + /* Validate each param's type. */ + for ($i = 0; $i < count($p); $i++) { + /* If SOAP types do not match, it's still fine if the + * mapped php types match this allows using plain PHP + * variables to work (i.e. stuff like Decimal would + * fail otherwise). We consider this only error if the + * types exist in our type maps, and they differ. */ + if (strcasecmp($sig_t[$i], $p[$i]) != 0 && + isset($this->_typemap[SOAP_XML_SCHEMA_VERSION][$sig_t[$i]]) && + strcasecmp($this->_typemap[SOAP_XML_SCHEMA_VERSION][$sig_t[$i]], $this->_typemap[SOAP_XML_SCHEMA_VERSION][$p[$i]]) != 0) { + + $param = $params[$i]; + $this->_raiseSoapFault("SOAP request contained mismatching parameters of name $param->name had type [{$p[$i]}], which did not match signature's type: [{$sig_t[$i]}], matched? " . (strcasecmp($sig_t[$i], $p[$i])), '', '', 'Client'); + return false; + } + } + return true; + } else { + /* Wrong number of params. */ + $this->_raiseSoapFault('SOAP request contained incorrect number of parameters. method "' . $this->methodname . '" required ' . count($sig) . ' and request provided ' . count($params), '', '', 'Client'); + return false; + } + } else { + /* No params. */ + $this->_raiseSoapFault('SOAP request contained incorrect number of parameters. method "' . $this->methodname . '" requires ' . count($sig) . ' parameters, and request provided none.', '', '', 'Client'); + return false; + } + } + + /* We'll try it anyway. */ + return true; + } + + function validateMethod($methodname, $namespace = null) + { + unset($this->soapobject); + + if (!$this->callValidation) { + return true; + } + + /* No SOAP access to private functions. */ + if ($methodname[0] == '_') { + return false; + } + + /* if it's in our function list, ok */ + if (array_key_exists($methodname, $this->dispatch_map) && + (!$namespace || + !array_key_exists('namespace', $this->dispatch_map[$methodname]) || + $namespace == $this->dispatch_map[$methodname]['namespace'])) { + if (array_key_exists('namespace', $this->dispatch_map[$methodname])) + $this->method_namespace = $this->dispatch_map[$methodname]['namespace']; + return true; + } + + /* if it's in an object, it's ok */ + if (isset($this->dispatch_objects[$namespace])) { + $c = count($this->dispatch_objects[$namespace]); + for ($i = 0; $i < $c; $i++) { + $obj =& $this->dispatch_objects[$namespace][$i]; + /* If we have a dispatch map, and the function is not in the + * dispatch map, then it is not callable! */ + if (method_exists($obj, '__dispatch')) { + if ($obj->__dispatch($methodname)) { + $this->method_namespace = $namespace; + $this->soapobject =& $obj; + return true; + } + } elseif (method_exists($obj, $methodname)) { + $this->method_namespace = $namespace; + $this->soapobject =& $obj; + return true; + } + } + } + + return false; + } + + function addObjectMap(&$obj, $namespace = null, $service_name = 'Default', + $service_desc = '') + { + if (!$namespace) { + if (isset($obj->namespace)) { + // XXX a bit of backwards compatibility + $namespace = $obj->namespace; + } else { + $this->_raiseSoapFault('No namespace provided for class!', '', '', 'Server'); + return false; + } + } + if (!isset($this->dispatch_objects[$namespace])) { + $this->dispatch_objects[$namespace] = array(); + } + $this->dispatch_objects[$namespace][] =& $obj; + + // Create internal WSDL structures for object + + // XXX Because some internal workings of PEAR::SOAP decide whether to + // do certain things by the presence or absence of _wsdl, we should + // only create a _wsdl structure if we know we can fill it; if + // __dispatch_map or __typedef for the object is missing, we should + // avoid creating it. Later, when we are using PHP 5 introspection, we + // will be able to make the data for all objects without any extra + // information from the developers, and this condition should be + // dropped. + + // XXX Known issue: if imported WSDL (bindWSDL) or another WSDL source + // is used to add _wsdl structure information, then addObjectWSDL is + // used, there is a high possibility of _wsdl data corruption; + // therefore you should avoid using __dispatch_map/__typedef + // definitions AND other WSDL data sources in the same service. We + // exclude classes that don't have __typedefs to allow external WSDL + // files to be used with classes with no internal type definitions + // (the types are defined in the WSDL file). When addObjectWSDL is + // refactored to not cause corruption, this restriction can be + // relaxed. + + // In summary, if you add an object with both a dispatch map and type + // definitions, then previous WSDL file operation and type definitions + // will be overwritten. + if (isset($obj->__dispatch_map) && isset($obj->__typedef)) { + $this->addObjectWSDL($obj, $namespace, $service_name, $service_desc); + } + + return true; + } + + /** + * Adds a method to the dispatch map. + */ + function addToMap($methodname, $in, $out, $namespace = null, $alias = null) + { + if (!function_exists($methodname)) { + $this->_raiseSoapFault('Error mapping function', '', '', 'Server'); + return false; + } + + $this->dispatch_map[$methodname]['in'] = $in; + $this->dispatch_map[$methodname]['out'] = $out; + $this->dispatch_map[$methodname]['alias'] = $alias; + if ($namespace) { + $this->dispatch_map[$methodname]['namespace'] = $namespace; + } + + return true; + } + + function setCallHandler($callHandler, $validation = true) + { + $this->callHandler = $callHandler; + $this->callValidation = $validation; + } + + /** + * @deprecated use bindWSDL from now on + */ + function bind($wsdl_url) + { + $this->bindWSDL($wsdl_url); + } + + /** + * @param string a url to a WSDL resource + * @return void + */ + function bindWSDL($wsdl_url) + { + /* Instantiate WSDL class. */ + $this->_wsdl =& new SOAP_WSDL($wsdl_url); + if ($this->_wsdl->fault) { + $this->_raiseSoapFault($this->_wsdl->fault); + } + } + + /** + * @return void + */ + function addObjectWSDL(&$wsdl_obj, $targetNamespace, $service_name, + $service_desc = '') + { + if (!isset($this->_wsdl)) { + $this->_wsdl =& new SOAP_WSDL; + } + + $this->_wsdl->parseObject($wsdl_obj, $targetNamespace, $service_name, $service_desc); + + if ($this->_wsdl->fault) { + $this->_raiseSoapFault($this->_wsdl->fault); + } + } +} diff --git a/thirdparty/pear/SOAP/Server/Email.php b/thirdparty/pear/SOAP/Server/Email.php new file mode 100644 index 0000000..df40652 --- /dev/null +++ b/thirdparty/pear/SOAP/Server/Email.php @@ -0,0 +1,201 @@ + Port to PEAR and more + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Server.php'; +require_once 'SOAP/Client.php'; +require_once 'SOAP/Transport.php'; +require_once 'Mail/mimeDecode.php'; + +/** + * SOAP Server Class that implements an email SOAP server. + * http://www.pocketsoap.com/specs/smtpbinding/ + * + * This class overrides the default HTTP server, providing the ability to + * parse an email message and execute SOAP calls. This class DOES NOT pop the + * message; the message, complete with headers, must be passed in as a + * parameter to the service function call. + * + * @access public + * @package SOAP + * @author Shane Caraveo + */ +class SOAP_Server_Email extends SOAP_Server { + + var $headers = array(); + + function SOAP_Server_Email($send_response = true) + { + parent::SOAP_Server(); + $this->send_response = $send_response; + } + + /** + * Removes HTTP headers from response. + * + * TODO: use PEAR email classes + * + * @return boolean + * @access private + */ + function _parseEmail(&$data) + { + if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", $data, $match)) { + + if (preg_match_all('/^(.*?):\s+(.*)$/m', $match[1], $matches)) { + $hc = count($matches[0]); + for ($i = 0; $i < $hc; $i++) { + $this->headers[strtolower($matches[1][$i])] = trim($matches[2][$i]); + } + } + + if (!stristr($this->headers['content-type'], 'text/xml')) { + $this->_raiseSoapFault('Invalid Content Type', '', '', 'Client'); + return false; + } + + if (strcasecmp($this->headers['content-transfer-encoding'], 'base64')==0) { + /* Unfold lines. */ + $enctext = preg_replace("/[\r|\n]/", '', $match[2]); + $data = base64_decode($enctext); + } else { + $data = $match[2]; + } + + /* If no content, return false. */ + return strlen($this->request) > 0; + } + + $this->_raiseSoapFault('Invalid Email Format', '', '', 'Client'); + + return false; + } + + function client(&$data) + { + $attachments = array(); + + /* If neither matches, we'll just try it anyway. */ + if (stristr($data, 'Content-Type: application/dime')) { + $this->_decodeDIMEMessage($data, $this->headers, $attachments); + $useEncoding = 'DIME'; + } elseif (stristr($data, 'MIME-Version:')) { + /* This is a mime message, let's decode it. */ + $this->_decodeMimeMessage($data, $this->headers, $attachments); + $useEncoding = 'Mime'; + } else { + /* The old fallback, but decodeMimeMessage handles things fine. */ + $this->_parseEmail($data); + } + + /* Get the character encoding of the incoming request treat incoming + * data as UTF-8 if no encoding set. */ + if (!$this->soapfault && + !$this->_getContentEncoding($this->headers['content-type'])) { + $this->xml_encoding = SOAP_DEFAULT_ENCODING; + /* An encoding we don't understand, return a fault. */ + $this->_raiseSoapFault('Unsupported encoding, use one of ISO-8859-1, US-ASCII, UTF-8', '', '', 'Server'); + } + + if ($this->soapfault) { + return $this->soapfault->getFault(); + } + + $client =& new SOAP_Client(null); + + return $client->__parse($data, $this->xml_encoding, $this->attachments); + } + + function service(&$data, $endpoint = '', $send_response = true, + $dump = false) + { + $this->endpoint = $endpoint; + $attachments = array(); + $headers = array(); + + /* If neither matches, we'll just try it anyway. */ + if (stristr($data, 'Content-Type: application/dime')) { + $this->_decodeDIMEMessage($data, $this->headers, $attachments); + $useEncoding = 'DIME'; + } elseif (stristr($data, 'MIME-Version:')) { + /* This is a mime message, let's decode it. */ + $this->_decodeMimeMessage($data, $this->headers, $attachments); + $useEncoding = 'Mime'; + } else { + /* The old fallback, but decodeMimeMessage handles things fine. */ + $this->_parseEmail($data); + } + + /* Get the character encoding of the incoming request treat incoming + * data as UTF-8 if no encoding set. */ + if (!$response && + !$this->_getContentEncoding($this->headers['content-type'])) { + $this->xml_encoding = SOAP_DEFAULT_ENCODING; + /* An encoding we don't understand, return a fault. */ + $this->_raiseSoapFault('Unsupported encoding, use one of ISO-8859-1, US-ASCII, UTF-8', '', '', 'Server'); + $response = $this->getFaultMessage(); + } + + if ($this->soapfault) { + $response = $this->soapfault->message(); + } else { + $soap_msg = $this->parseRequest($data,$attachments); + + /* Handle Mime or DIME encoding. */ + /* TODO: DIME Encoding should move to the transport, do it here + * for now and for ease of getting it done. */ + if (count($this->__attachments)) { + if ($useEncoding == 'Mime') { + $soap_msg = $this->_makeMimeMessage($soap_msg); + } else { + /* Default is DIME. */ + $soap_msg = $this->_makeDIMEMessage($soap_msg); + $header['Content-Type'] = 'application/dime'; + } + if (PEAR::isError($soap_msg)) { + return $this->raiseSoapFault($soap_msg); + } + } + + if (is_array($soap_msg)) { + $response = $soap_msg['body']; + if (count($soap_msg['headers'])) { + $headers = $soap_msg['headers']; + } + } else { + $response = $soap_msg; + } + } + + if ($this->send_response) { + if ($dump) { + print $response; + } else { + $from = array_key_exists('reply-to', $this->headers) ? $this->headers['reply-to'] : $this->headers['from']; + + $soap_transport =& SOAP_Transport::getTransport('mailto:' . $from, $this->response_encoding); + $from = $this->endpoint ? $this->endpoint : $this->headers['to']; + $headers['In-Reply-To'] = $this->headers['message-id']; + $options = array('from' => $from, 'subject' => $this->headers['subject'], 'headers' => $headers); + $soap_transport->send($response, $options); + } + } + } +} diff --git a/thirdparty/pear/SOAP/Server/Email_Gateway.php b/thirdparty/pear/SOAP/Server/Email_Gateway.php new file mode 100644 index 0000000..d573633 --- /dev/null +++ b/thirdparty/pear/SOAP/Server/Email_Gateway.php @@ -0,0 +1,138 @@ + Port to PEAR and more + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Server/Email.php'; +require_once 'SOAP/Transport.php'; + +/** + * SOAP Server Class that implements an email SOAP server. + * http://www.pocketsoap.com/specs/smtpbinding/ + * + * This class overrides the default HTTP server, providing the ability to + * parse an email message and execute soap calls. This class DOES NOT pop the + * message; the message, complete with headers, must be passed in as a + * parameter to the service function call. + * + * This class calls a provided HTTP SOAP server, forwarding the email request, + * then sending the HTTP response out as an email. + * + * @access public + * @package SOAP + * @author Shane Caraveo + */ +class SOAP_Server_Email_Gateway extends SOAP_Server_Email { + + var $gateway = null; + var $dump = false; + + function SOAP_Server_Email_Gateway($gateway = '', $send_response = true, + $dump = false) + { + parent::SOAP_Server(); + $this->send_response = $send_response; + $this->gateway = $gateway; + $this->dump = $dump; + } + + function service(&$data, $gateway = '', $endpoint = '', + $send_response = true, $dump = false) + { + $this->endpoint = $endpoint; + $response = ''; + $useEncoding = 'Mime'; + $options = array(); + if (!$gateway) { + $gateway = $this->gateway; + } + + /* We have a full set of headers, need to find the first blank + * line. */ + $this->_parseEmail($data); + if ($this->fault) { + $response = $this->fault->message(); + } + if ($this->headers['content-type'] == 'application/dime') + $useEncoding = 'DIME'; + + /* Call the HTTP Server. */ + if (!$response) { + $soap_transport =& SOAP_Transport::getTransport($gateway, $this->xml_encoding); + if ($soap_transport->fault) { + $response = $soap_transport->fault->message(); + } + } + + /* Send the message. */ + if (!$response) { + $options['soapaction'] = $this->headers['soapaction']; + $options['headers']['Content-Type'] = $this->headers['content-type']; + + $response = $soap_transport->send($data, $options); + if (isset($this->headers['mime-version'])) + $options['headers']['MIME-Version'] = $this->headers['mime-version']; + + if ($soap_transport->fault) { + $response = $soap_transport->fault->message(); + } else { + foreach ($soap_transport->transport->attachments as $cid => $body) { + $this->attachments[] = array('body' => $body, 'cid' => $cid, 'encoding' => 'base64'); + } + if (count($this->__attachments)) { + if ($useEncoding == 'Mime') { + $soap_msg = $this->_makeMimeMessage($response); + $options['headers']['MIME-Version'] = '1.0'; + } else { + /* Default is DIME. */ + $soap_msg = $this->_makeDIMEMessage($response); + $options['headers']['Content-Type'] = 'application/dime'; + } + if (PEAR::isError($soap_msg)) { + return $this->_raiseSoapFault($soap_msg); + } + if (is_array($soap_msg)) { + $response = $soap_msg['body']; + if (count($soap_msg['headers'])) { + if (isset($options['headers'])) { + $options['headers'] = array_merge($options['headers'], $soap_msg['headers']); + } else { + $options['headers'] = $soap_msg['headers']; + } + } + } + } + } + } + + if ($this->send_response) { + if ($this->dump || $dump) { + print $response; + } else { + $from = array_key_exists('reply-to', $this->headers) ? $this->headers['reply-to'] : $this->headers['from']; + + $soap_transport =& SOAP_Transport::getTransport('mailto:' . $from, $this->response_encoding); + $from = $this->endpoint ? $this->endpoint : $this->headers['to']; + $headers = array('In-Reply-To' => $this->headers['message-id']); + $options = array('from' => $from, 'subject'=> $this->headers['subject'], 'headers' => $headers); + $soap_transport->send($response, $options); + } + } + } +} diff --git a/thirdparty/pear/SOAP/Server/TCP.php b/thirdparty/pear/SOAP/Server/TCP.php new file mode 100644 index 0000000..039a627 --- /dev/null +++ b/thirdparty/pear/SOAP/Server/TCP.php @@ -0,0 +1,106 @@ + Port to PEAR and more + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Server.php'; + +/** + * SOAP Server Class that implements a TCP SOAP Server. + * http://www.pocketsoap.com/specs/smtpbinding/ + * + * This class overrides the default HTTP server, providing the ability to + * accept socket connections and execute SOAP calls. + * + * TODO: + * use Net_Socket + * implement some security scheme + * implement support for attachments + * + * @access public + * @package SOAP + * @author Shane Caraveo + */ +class SOAP_Server_TCP extends SOAP_Server { + + var $headers = array(); + var $localaddr; + var $port; + var $listen; + var $reuse; + + function SOAP_Server_TCP($localaddr = '127.0.0.1', $port = 10000, + $listen = 5, $reuse = true) + { + parent::SOAP_Server(); + $this->localaddr = $localaddr; + $this->port = $port; + $this->listen = $listen; + $this->reuse = $reuse; + } + + function run() + { + if (($sock = socket_create(AF_INET, SOCK_STREAM, 0)) < 0) { + return $this->_raiseSoapFault('socket_create() failed. Reason: ' . socket_strerror($sock)); + } + if ($this->reuse && + !@socket_setopt($sock, SOL_SOCKET, SO_REUSEADDR, 1)) { + return $this->_raiseSoapFault('socket_setopt() failed. Reason: ' . socket_strerror(socket_last_error($sock))); + } + if (($ret = socket_bind($sock, $this->localaddr, $this->port)) < 0) { + return $this->_raiseSoapFault('socket_bind() failed. Reason: ' . socket_strerror($ret)); + } + if (($ret = socket_listen($sock, $this->listen)) < 0) { + return $this->_raiseSoapFault('socket_listen() failed. Reason: ' . socket_strerror($ret)); + } + + while (true) { + $data = null; + if (($msgsock = socket_accept($sock)) < 0) { + $this->_raiseSoapFault('socket_accept() failed. Reason: ' . socket_strerror($msgsock)); + break; + } + while ($buf = socket_read($msgsock, 8192)) { + if (!$buf = trim($buf)) { + continue; + } + $data .= $buf; + } + + if ($data) { + $response = $this->service($data); + /* Write to the socket. */ + if (!socket_write($msgsock, $response, strlen($response))) { + return $this->_raiseSoapFault('Error sending response data reason ' . socket_strerror()); + } + } + + socket_close ($msgsock); + } + + socket_close ($sock); + } + + function service(&$data) + { + /* TODO: we need to handle attachments somehow. */ + return $this->parseRequest($data, $attachments); + } +} diff --git a/thirdparty/pear/SOAP/Transport.php b/thirdparty/pear/SOAP/Transport.php new file mode 100644 index 0000000..e9dada5 --- /dev/null +++ b/thirdparty/pear/SOAP/Transport.php @@ -0,0 +1,71 @@ + + * @author Shane Caraveo + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; + +/** + * SOAP Transport Layer + * + * This layer can use different protocols dependant on the endpoint url provided + * no knowlege of the SOAP protocol is available at this level + * no knowlege of the transport protocols is available at this level + * + * @access public + * @package SOAP + * @author Shane Caraveo + */ +class SOAP_Transport +{ + function &getTransport($url, $encoding = SOAP_DEFAULT_ENCODING) + { + $urlparts = @parse_url($url); + + if (!$urlparts['scheme']) { + $fault = SOAP_Base_Object::_raiseSoapFault("Invalid transport URI: $url"); + return $fault; + } + + if (strcasecmp($urlparts['scheme'], 'mailto') == 0) { + $transport_type = 'SMTP'; + } elseif (strcasecmp($urlparts['scheme'], 'https') == 0) { + $transport_type = 'HTTP'; + } else { + /* handle other transport types */ + $transport_type = strtoupper($urlparts['scheme']); + } + $transport_include = 'SOAP/Transport/' . $transport_type . '.php'; + $res = @include_once($transport_include); + if (!$res && !in_array($transport_include, get_included_files())) { + $fault = SOAP_Base_Object::_raiseSoapFault("No Transport for {$urlparts['scheme']}"); + return $fault; + } + $transport_class = "SOAP_Transport_$transport_type"; + if (!class_exists($transport_class)) { + $fault = SOAP_Base_Object::_raiseSoapFault("No Transport class $transport_class"); + return $fault; + } + $t =& new $transport_class($url, $encoding); + + return $t; + } + +} diff --git a/thirdparty/pear/SOAP/Transport/HTTP.php b/thirdparty/pear/SOAP/Transport/HTTP.php new file mode 100644 index 0000000..db4b607 --- /dev/null +++ b/thirdparty/pear/SOAP/Transport/HTTP.php @@ -0,0 +1,625 @@ + + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +/** + * HTTP Transport class + * + * @package SOAP + * @category Web_Services + */ + +/** + * Needed Classes + */ +require_once 'SOAP/Base.php'; + +/** + * HTTP Transport for SOAP + * + * @access public + * @package SOAP + * @author Shane Caraveo + */ +class SOAP_Transport_HTTP extends SOAP_Base +{ + + /** + * Basic Auth string. + * + * @var array + */ + var $headers = array(); + + /** + * Cookies. + * + * @var array + */ + var $cookies; + + /** + * Connection timeout in seconds. 0 = none. + * + * @var integer + */ + var $timeout = 4; + + /** + * Array containing urlparts - parse_url(). + * + * @var mixed + */ + var $urlparts = null; + + /** + * Connection endpoint - URL. + * + * @var string + */ + var $url = ''; + + /** + * Incoming payload. + * + * @var string + */ + var $incoming_payload = ''; + + /** + * HTTP-Request User-Agent. + * + * @var string + */ + var $_userAgent = SOAP_LIBRARY_NAME; + + /** + * HTTP encoding. + * + * @var string + */ + var $encoding = SOAP_DEFAULT_ENCODING; + + /** + * HTTP-Response Content-Type encoding. + * We assume UTF-8 if no encoding is set. + * + * @var string + */ + var $result_encoding = 'UTF-8'; + + /** + * HTTP-Response Content-Type. + */ + var $result_content_type; + + var $result_headers = array(); + + var $result_cookies = array(); + + /** + * SOAP_Transport_HTTP Constructor + * + * @access public + * + * @param string $url HTTP url to SOAP endpoint. + * @param string $encoding Encoding to use. + */ + function SOAP_Transport_HTTP($url, $encoding = SOAP_DEFAULT_ENCODING) + { + parent::SOAP_Base('HTTP'); + $this->urlparts = @parse_url($url); + $this->url = $url; + $this->encoding = $encoding; + } + + /** + * Sends and receives SOAP data. + * + * @param string Outgoing POST data. + * @param array Options. + * + * @return string|SOAP_Fault + * @access public + */ + function send($msg, $options = null) + { + if (!$this->_validateUrl()) { + return $this->fault; + } + + if (isset($options['timeout'])) { + $this->timeout = (int)$options['timeout']; + } + + if (strcasecmp($this->urlparts['scheme'], 'HTTP') == 0) { + return $this->_sendHTTP($msg, $options); + } elseif (strcasecmp($this->urlparts['scheme'], 'HTTPS') == 0) { + return $this->_sendHTTPS($msg, $options); + } + + return $this->_raiseSoapFault('Invalid url scheme ' . $this->url); + } + + /** + * Sets data for HTTP authentication, creates authorization header. + * + * @param string $username Username. + * @param string $password Response data, minus HTTP headers. + * + * @access public + */ + function setCredentials($username, $password) + { + $this->headers['Authorization'] = 'Basic ' . base64_encode($username . ':' . $password); + } + + /** + * Adds a cookie. + * + * @access public + * @param string $name Cookie name. + * @param mixed $value Cookie value. + */ + function addCookie($name, $value) + { + $this->cookies[$name] = $value; + } + + /** + * Generates the correct headers for the cookies. + * + * @access private + */ + function _genCookieHeader() + { + foreach ($this->cookies as $name=>$value) { + $cookies = (isset($cookies) ? $cookies. '; ' : '') . + urlencode($name) . '=' . urlencode($value); + } + return $cookies; + } + + /** + * Validate url data passed to constructor. + * + * @access private + * @return boolean + */ + function _validateUrl() + { + if (!is_array($this->urlparts) ) { + $this->_raiseSoapFault('Unable to parse URL ' . $this->url); + return false; + } + if (!isset($this->urlparts['host'])) { + $this->_raiseSoapFault('No host in URL ' . $this->url); + return false; + } + if (!isset($this->urlparts['port'])) { + if (strcasecmp($this->urlparts['scheme'], 'HTTP') == 0) { + $this->urlparts['port'] = 80; + } elseif (strcasecmp($this->urlparts['scheme'], 'HTTPS') == 0) { + $this->urlparts['port'] = 443; + } + + } + if (isset($this->urlparts['user'])) { + $this->setCredentials(urldecode($this->urlparts['user']), + urldecode($this->urlparts['pass'])); + } + if (!isset($this->urlparts['path']) || !$this->urlparts['path']) { + $this->urlparts['path'] = '/'; + } + + return true; + } + + /** + * Finds out what the encoding is. + * Sets the object property accordingly. + * + * @access private + * @param array $headers Headers. + */ + function _parseEncoding($headers) + { + $h = stristr($headers, 'Content-Type'); + preg_match_all('/^Content-Type:\s*(.*)$/im', $h, $ct, PREG_SET_ORDER); + $n = count($ct); + $ct = $ct[$n - 1]; + + // Strip the string of \r. + $this->result_content_type = str_replace("\r", '', $ct[1]); + + if (preg_match('/(.*?)(?:;\s?charset=)(.*)/i', + $this->result_content_type, + $m)) { + $this->result_content_type = $m[1]; + if (count($m) > 2) { + $enc = strtoupper(str_replace('"', '', $m[2])); + if (in_array($enc, $this->_encodings)) { + $this->result_encoding = $enc; + } + } + } + + // Deal with broken servers that don't set content type on faults. + if (!$this->result_content_type) { + $this->result_content_type = 'text/xml'; + } + } + + /** + * Parses the headers. + * + * @param array $headers The headers. + */ + function _parseHeaders($headers) + { + /* Largely borrowed from HTTP_Request. */ + $this->result_headers = array(); + $headers = split("\r?\n", $headers); + foreach ($headers as $value) { + if (strpos($value,':') === false) { + $this->result_headers[0] = $value; + continue; + } + list($name, $value) = split(':', $value); + $headername = strtolower($name); + $headervalue = trim($value); + $this->result_headers[$headername] = $headervalue; + + if ($headername == 'set-cookie') { + // Parse a SetCookie header to fill _cookies array. + $cookie = array('expires' => null, + 'domain' => $this->urlparts['host'], + 'path' => null, + 'secure' => false); + + if (!strpos($headervalue, ';')) { + // Only a name=value pair. + list($cookie['name'], $cookie['value']) = array_map('trim', explode('=', $headervalue)); + $cookie['name'] = urldecode($cookie['name']); + $cookie['value'] = urldecode($cookie['value']); + + } else { + // Some optional parameters are supplied. + $elements = explode(';', $headervalue); + list($cookie['name'], $cookie['value']) = array_map('trim', explode('=', $elements[0])); + $cookie['name'] = urldecode($cookie['name']); + $cookie['value'] = urldecode($cookie['value']); + + for ($i = 1; $i < count($elements);$i++) { + list($elName, $elValue) = array_map('trim', explode('=', $elements[$i])); + if ('secure' == $elName) { + $cookie['secure'] = true; + } elseif ('expires' == $elName) { + $cookie['expires'] = str_replace('"', '', $elValue); + } elseif ('path' == $elName OR 'domain' == $elName) { + $cookie[$elName] = urldecode($elValue); + } else { + $cookie[$elName] = $elValue; + } + } + } + $this->result_cookies[] = $cookie; + } + } + } + + /** + * Removes HTTP headers from response. + * + * @return boolean + * @access private + */ + function _parseResponse() + { + if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", + $this->incoming_payload, + $match)) { + $this->response = $match[2]; + // Find the response error, some servers response with 500 for + // SOAP faults. + $this->_parseHeaders($match[1]); + + list($protocol, $code, $msg) = sscanf($this->result_headers[0], + '%s %s %s'); + unset($this->result_headers[0]); + + switch($code) { + case 100: // Continue + $this->incoming_payload = $match[2]; + return $this->_parseResponse(); + case 400: + $this->_raiseSoapFault("HTTP Response $code Bad Request"); + return false; + break; + case 401: + $this->_raiseSoapFault("HTTP Response $code Authentication Failed"); + return false; + break; + case 403: + $this->_raiseSoapFault("HTTP Response $code Forbidden"); + return false; + break; + case 404: + $this->_raiseSoapFault("HTTP Response $code Not Found"); + return false; + break; + case 407: + $this->_raiseSoapFault("HTTP Response $code Proxy Authentication Required"); + return false; + break; + case 408: + $this->_raiseSoapFault("HTTP Response $code Request Timeout"); + return false; + break; + case 410: + $this->_raiseSoapFault("HTTP Response $code Gone"); + return false; + break; + default: + if ($code >= 400 && $code < 500) { + $this->_raiseSoapFault("HTTP Response $code Not Found, Server message: $msg"); + return false; + } + } + + $this->_parseEncoding($match[1]); + + if ($this->result_content_type == 'application/dime') { + // XXX quick hack insertion of DIME + if (PEAR::isError($this->_decodeDIMEMessage($this->response,$this->headers,$this->attachments))) { + // _decodeDIMEMessage already raised $this->fault + return false; + } + $this->result_content_type = $this->headers['content-type']; + } elseif (stristr($this->result_content_type,'multipart/related')) { + $this->response = $this->incoming_payload; + if (PEAR::isError($this->_decodeMimeMessage($this->response,$this->headers,$this->attachments))) { + // _decodeMimeMessage already raised $this->fault + return false; + } + } elseif ($this->result_content_type != 'text/xml') { + $this->_raiseSoapFault($this->response); + return false; + } + // if no content, return false + return strlen($this->response) > 0; + } + $this->_raiseSoapFault('Invalid HTTP Response'); + return false; + } + + /** + * Creates HTTP request, including headers, for outgoing request. + * + * @param string $msg Outgoing SOAP package. + * @param array $options Options. + * @return string Outgoing payload. + * @access private + */ + function _getRequest($msg, $options) + { + $this->headers = array(); + + $action = isset($options['soapaction']) ? $options['soapaction'] : ''; + $fullpath = $this->urlparts['path']; + if (isset($this->urlparts['query'])) { + $fullpath .= '?' . $this->urlparts['query']; + } + if (isset($this->urlparts['fragment'])) { + $fullpath .= '#' . $this->urlparts['fragment']; + } + + if (isset($options['proxy_host'])) { + $fullpath = 'http://' . $this->urlparts['host'] . ':' . + $this->urlparts['port'] . $fullpath; + } + + if (isset($options['proxy_user'])) { + $this->headers['Proxy-Authorization'] = 'Basic ' . + base64_encode($options['proxy_user'] . ':' . + $options['proxy_pass']); + } + + if (isset($options['user'])) { + $this->setCredentials($options['user'], $options['pass']); + } + + $this->headers['User-Agent'] = $this->_userAgent; + $this->headers['Host'] = $this->urlparts['host']; + $this->headers['Content-Type'] = "text/xml; charset=$this->encoding"; + $this->headers['Content-Length'] = strlen($msg); + $this->headers['SOAPAction'] = '"' . $action . '"'; + if (isset($options['headers'])) { + $this->headers = array_merge($this->headers, $options['headers']); + } + + $this->cookies = array(); + if (!isset($options['nocookies']) || !$options['nocookies']) { + // Add the cookies we got from the last request. + if (isset($this->result_cookies)) { + foreach ($this->result_cookies as $cookie) { + if ($cookie['domain'] == $this->urlparts['host']) + $this->cookies[$cookie['name']] = $cookie['value']; + } + } + } + // Add cookies the user wants to set. + if (isset($options['cookies'])) { + foreach ($options['cookies'] as $cookie) { + if ($cookie['domain'] == $this->urlparts['host']) + $this->cookies[$cookie['name']] = $cookie['value']; + } + } + if (count($this->cookies)) { + $this->headers['Cookie'] = $this->_genCookieHeader(); + } + $headers = ''; + foreach ($this->headers as $k => $v) { + $headers .= "$k: $v\r\n"; + } + $this->outgoing_payload = "POST $fullpath HTTP/1.0\r\n" . $headers . + "\r\n" . $msg; + + return $this->outgoing_payload; + } + + /** + * Sends outgoing request, and read/parse response. + * + * @param string $msg Outgoing SOAP package. + * @param string $action SOAP Action. + * @return string Response data, minus HTTP headers. + * @access private + */ + function _sendHTTP($msg, $options) + { + $this->incoming_payload = ''; + $this->_getRequest($msg, $options); + $host = $this->urlparts['host']; + $port = $this->urlparts['port']; + if (isset($options['proxy_host'])) { + $host = $options['proxy_host']; + $port = isset($options['proxy_port']) ? $options['proxy_port'] : 8080; + } + // Send. + if ($this->timeout > 0) { + $fp = @fsockopen($host, $port, $this->errno, $this->errmsg, $this->timeout); + } else { + $fp = @fsockopen($host, $port, $this->errno, $this->errmsg); + } + if (!$fp) { + return $this->_raiseSoapFault("Connect Error to $host:$port"); + } + if ($this->timeout > 0) { + // some builds of PHP do not support this, silence the warning + @socket_set_timeout($fp, $this->timeout); + } + if (!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { + return $this->_raiseSoapFault("Error POSTing Data to $host"); + } + + // get reponse + // XXX time consumer + do { + $data = fread($fp, 4096); + $_tmp_status = socket_get_status($fp); + if ($_tmp_status['timed_out']) { + return $this->_raiseSoapFault("Timed out read from $host"); + } else { + $this->incoming_payload .= $data; + } + } while (!$_tmp_status['eof']); + + fclose($fp); + + if (!$this->_parseResponse()) { + return $this->fault; + } + return $this->response; + } + + /** + * Sends outgoing request, and read/parse response, via HTTPS. + * + * @param string $msg Outgoing SOAP package. + * @param string $action SOAP Action. + * @return string $response Response data, minus HTTP headers. + * @access private + */ + function _sendHTTPS($msg, $options) + { + /* NOTE This function uses the CURL functions + * Your php must be compiled with CURL + */ + if (!extension_loaded('curl')) { + return $this->_raiseSoapFault('CURL Extension is required for HTTPS'); + } + + $ch = curl_init(); + + if (isset($options['proxy_host'])) { + // $options['http_proxy'] == 'hostname:port' + $host = $options['proxy_host']; + $port = isset($options['proxy_port']) ? $options['proxy_port'] : 8080; + curl_setopt($ch, CURLOPT_PROXY, $host . ":" . $port); + } + + if (isset($options['proxy_user'])) { + // $options['http_proxy_userpw'] == 'username:password' + curl_setopt($ch, CURLOPT_PROXYUSERPWD, $options['proxy_user'] . ':' . $options['proxy_pass']); + } + + if (isset($options['user'])) { + curl_setopt($ch, CURLOPT_USERPWD, $options['user'] . ':' . $options['pass']); + } + + if (!isset($options['soapaction'])) { + $options['soapaction'] = ''; + } + curl_setopt($ch, CURLOPT_HTTPHEADER , array('Content-Type: text/xml;charset=' . $this->encoding, 'SOAPAction: "'.$options['soapaction'].'"')); + curl_setopt($ch, CURLOPT_USERAGENT , $this->_userAgent); + + if ($this->timeout) { + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); //times out after 4s + } + + curl_setopt($ch, CURLOPT_POSTFIELDS, $msg); + curl_setopt($ch, CURLOPT_URL, $this->url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_FAILONERROR, 0); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HEADER, 1); + if (defined('CURLOPT_HTTP_VERSION')) { + curl_setopt($ch, CURLOPT_HTTP_VERSION, 1); + } + + if (isset($options['curl'])) { + foreach ($options['curl'] as $key => $val) { + curl_setopt($ch, $key, $val); + } + } + + // Save the outgoing XML. This doesn't quite match _sendHTTP as CURL + // generates the headers, but having the XML is usually the most + // important part for tracing/debugging. + $this->outgoing_payload = $msg; + + $this->incoming_payload = curl_exec($ch); + if (!$this->incoming_payload) { + $m = 'curl_exec error ' . curl_errno($ch) . ' ' . curl_error($ch); + curl_close($ch); + return $this->_raiseSoapFault($m); + } + curl_close($ch); + + if (!$this->_parseResponse()) { + return $this->fault; + } + + return $this->response; + } + +} diff --git a/thirdparty/pear/SOAP/Transport/SMTP.php b/thirdparty/pear/SOAP/Transport/SMTP.php new file mode 100644 index 0000000..64dd045 --- /dev/null +++ b/thirdparty/pear/SOAP/Transport/SMTP.php @@ -0,0 +1,209 @@ + + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; +require_once 'Mail/smtp.php'; + +/** + * SMTP Transport for SOAP + * + * implements SOAP-SMTP as defined at + * http://www.pocketsoap.com/specs/smtpbinding/ + * + * TODO: use PEAR smtp and Mime classes + * + * @access public + * @package SOAP + * @author Shane Caraveo + */ +class SOAP_Transport_SMTP extends SOAP_Base +{ + + var $credentials = ''; + var $timeout = 4; // connect timeout + var $urlparts = NULL; + var $url = ''; + var $incoming_payload = ''; + var $_userAgent = SOAP_LIBRARY_NAME; + var $encoding = SOAP_DEFAULT_ENCODING; + var $host = '127.0.0.1'; + var $port = 25; + var $auth = NULL; + /** + * SOAP_Transport_SMTP Constructor + * + * @param string $URL mailto:address + * + * @access public + */ + function SOAP_Transport_SMTP($URL, $encoding='US-ASCII') + { + parent::SOAP_Base('SMTP'); + $this->encoding = $encoding; + $this->urlparts = @parse_url($URL); + $this->url = $URL; + } + + /** + * Sends and receives SOAP data. + * + * @param string $msg Outgoing POST data. + * @param string $action SOAP Action header data. + * @param integer $timeout Socket timeout, defaults to 0 or off. + * + * @return string Response data, minus HTTP headers. + * @access public + */ + function send($msg, $options = array()) + { + $this->incoming_payload = ''; + $this->outgoing_payload = $msg; + if (!$this->_validateUrl()) { + return $this->fault; + } + if (!$options || !isset($options['from'])) { + return $this->_raiseSoapFault('No From: address to send message with'); + } + + if (isset($options['host'])) $this->host = $options['host']; + if (isset($options['port'])) $this->port = $options['port']; + if (isset($options['auth'])) $this->auth = $options['auth']; + if (isset($options['username'])) $this->username = $options['username']; + if (isset($options['password'])) $this->password = $options['password']; + + $headers = array(); + $headers['From'] = $options['from']; + $headers['X-Mailer'] = $this->_userAgent; + $headers['MIME-Version'] = '1.0'; + $headers['Message-ID'] = md5(time()) . '.soap@' . $this->host; + $headers['To'] = $this->urlparts['path']; + if (isset($options['soapaction'])) { + $headers['Soapaction'] = "\"{$options['soapaction']}\""; + } + + if (isset($options['headers'])) + $headers = array_merge($headers, $options['headers']); + + // If the content type is already set, we assume that MIME encoding is + // already done. + if (isset($headers['Content-Type'])) { + $out = $msg; + } else { + // Do a simple inline MIME encoding. + $headers['Content-Disposition'] = 'inline'; + $headers['Content-Type'] = "text/xml; charset=\"$this->encoding\""; + if (isset($options['transfer-encoding'])) { + if (strcasecmp($options['transfer-encoding'], 'quoted-printable') == 0) { + $headers['Content-Transfer-Encoding'] = $options['transfer-encoding']; + $out = $msg; + } elseif (strcasecmp($options['transfer-encoding'],'base64') == 0) { + $headers['Content-Transfer-Encoding'] = 'base64'; + $out = chunk_split(base64_encode($msg), 76, "\n"); + } else { + return $this->_raiseSoapFault("Invalid Transfer Encoding: {$options['transfer-encoding']}"); + } + } else { + // Default to base64. + $headers['Content-Transfer-Encoding'] = 'base64'; + $out = chunk_split(base64_encode($msg)); + } + } + + $headers['Subject'] = isset($options['subject']) ? $options['subject'] : 'SOAP Message'; + + foreach ($headers as $key => $value) { + $header_text .= "$key: $value\n"; + } + $this->outgoing_payload = $header_text . "\r\n" . $this->outgoing_payload; + + $mailer_params = array( + 'host' => $this->host, + 'port' => $this->port, + 'username' => $this->username, + 'password' => $this->password, + 'auth' => $this->auth + ); + $mailer =& new Mail_smtp($mailer_params); + $result = $mailer->send($this->urlparts['path'], $headers, $out); + if (!PEAR::isError($result)) { + $val =& new SOAP_Value('Message-ID', 'string', $headers['Message-ID']); + } else { + $sval[] =& new SOAP_Value('faultcode', 'QName', 'SOAP-ENV:Client'); + $sval[] =& new SOAP_Value('faultstring', 'string', "couldn't send SMTP message to {$this->urlparts['path']}"); + $val =& new SOAP_Value('Fault', 'Struct', $sval); + } + + $mqname =& new QName($method, $namespace); + $methodValue =& new SOAP_Value('Response', 'Struct', array($val)); + + $this->incoming_payload = $this->_makeEnvelope($methodValue, + $this->headers, + $this->encoding); + + return $this->incoming_payload; + } + + /** + * Sets data for HTTP authentication, creates Authorization header. + * + * @param string $username Username. + * @param string $password Response data, minus HTTP headers. + * + * @access public + */ + function setCredentials($username, $password) + { + $this->username = $username; + $this->password = $password; + } + + /** + * Validates url data passed to constructor. + * + * @return boolean + * @access private + */ + function _validateUrl() + { + if (!is_array($this->urlparts)) { + $this->_raiseSoapFault("Unable to parse URL $url"); + return false; + } + if (!isset($this->urlparts['scheme']) || + strcasecmp($this->urlparts['scheme'], 'mailto') != 0) { + $this->_raiseSoapFault("Unable to parse URL $url"); + return false; + } + if (!isset($this->urlparts['path'])) { + $this->_raiseSoapFault("Unable to parse URL $url"); + return false; + } + return true; + } + +} diff --git a/thirdparty/pear/SOAP/Transport/TCP.php b/thirdparty/pear/SOAP/Transport/TCP.php new file mode 100644 index 0000000..a4813eb --- /dev/null +++ b/thirdparty/pear/SOAP/Transport/TCP.php @@ -0,0 +1,159 @@ + + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; + +/** + * TCP transport for SOAP. + * + * @todo use Net_Socket; implement some security scheme; implement support + * for attachments + * @access public + * @package SOAP + * @author Shane Hanna + */ +class SOAP_Transport_TCP extends SOAP_Base_Object +{ + + var $headers = array(); + var $urlparts = null; + var $url = ''; + var $incoming_payload = ''; + var $_userAgent = SOAP_LIBRARY_NAME; + var $encoding = SOAP_DEFAULT_ENCODING; + var $result_encoding = 'UTF-8'; + var $result_content_type; + + /** + * socket + */ + var $socket = null; + + /** + * Constructor. + * + * @param string $url HTTP url to SOAP endpoint. + * + * @access public + */ + function SOAP_Transport_TCP($url, $encoding = SOAP_DEFAULT_ENCODING) + { + parent::SOAP_Base_Object('TCP'); + $this->urlparts = @parse_url($url); + $this->url = $url; + $this->encoding = $encoding; + } + + function _socket_ping() + { + // XXX how do we restart after socket_shutdown? + //if (!$this->socket) { + // Create socket resource. + $this->socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if ($this->socket < 0) { + return 0; + } + + // Connect. + $result = socket_connect($this->socket, $this->urlparts['host'], + $this->urlparts['port']); + if ($result < 0) { + return 0; + } + //} + return 1; + } + + /** + * Sends and receives SOAP data. + * + * @param string $msg Outgoing POST data. + * @param string $action SOAP Action header data. + * + * @return string|SOAP_Fault + * @access public + */ + function send($msg, $options = NULL) + { + $this->incoming_payload = ''; + $this->outgoing_payload = $msg; + if (!$this->_validateUrl()) { + return $this->fault; + } + + // Check for TCP scheme. + if (strcasecmp($this->urlparts['scheme'], 'TCP') == 0) { + // Check connection. + if (!$this->_socket_ping()) { + return $this->_raiseSoapFault('Error connecting to ' . $this->url . '; reason: ' . socket_strerror(socket_last_error($this->socket))); + } + + // Write to the socket. + if (!@socket_write($this->socket, $this->outgoing_payload, + strlen($this->outgoing_payload))) { + return $this->_raiseSoapFault('Error sending data to ' . $this->url . '; reason: ' . socket_strerror(socket_last_error($this->socket))); + } + + // Shutdown writing. + if(!socket_shutdown($this->socket, 1)) { + return $this->_raiseSoapFault('Cannot change socket mode to read.'); + } + + // Read everything we can. + while ($buf = @socket_read($this->socket, 1024, PHP_BINARY_READ)) { + $this->incoming_payload .= $buf; + } + + // Return payload or die. + if ($this->incoming_payload) { + return $this->incoming_payload; + } + + return $this->_raiseSoapFault('Error reveiving data from ' . $this->url); + } + + return $this->_raiseSoapFault('Invalid url scheme ' . $this->url); + } + + /** + * Validates the url data passed to the constructor. + * + * @return boolean + * @access private + */ + function _validateUrl() + { + if (!is_array($this->urlparts) ) { + $this->_raiseSoapFault("Unable to parse URL $url"); + return false; + } + if (!isset($this->urlparts['host'])) { + $this->_raiseSoapFault("No host in URL $url"); + return false; + } + if (!isset($this->urlparts['path']) || !$this->urlparts['path']) { + $this->urlparts['path'] = '/'; + } + + return true; + } + +} diff --git a/thirdparty/pear/SOAP/Type/dateTime.php b/thirdparty/pear/SOAP/Type/dateTime.php new file mode 100644 index 0000000..942cd02 --- /dev/null +++ b/thirdparty/pear/SOAP/Type/dateTime.php @@ -0,0 +1,238 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +/** + * This class converts from and to unix timestamps and ISO 8601 date/time. + * + * @access public + * @package SOAP + * @author Dietrich Ayala Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Jan Schneider Maintenance + */ +class SOAP_Type_dateTime +{ + var $_iso8601 = + '# 1: centuries & years CCYY- + (-?[0-9]{4})- + # 2: months MM- + ([0-9]{2})- + # 3: days DD + ([0-9]{2}) + # 4: separator T + T + # 5: hours hh: + ([0-9]{2}): + # 6: minutes mm: + ([0-9]{2}): + # 7: seconds ss.ss... + ([0-9]{2})(\.[0-9]*)? + # 8: Z to indicate UTC, -+HH:MM:SS.SS... for local zones + (Z|[+\-][0-9]{4}|[+\-][0-9]{2}:[0-9]{2})?'; + + var $timestamp = -1; + + /** + * Constructor. + * + * @param string|integer $date The timestamp or ISO 8601 formatted + * date and time this object is going to + * represent. + */ + function SOAP_Type_dateTime($date = -1) + { + if ($date == -1) { + $this->timestamp = time(); + } elseif (is_int($date)) { + $this->timestamp = $date; + } else { + $this->timestamp = $this->toUnixtime($date); + } + } + + /** + * Alias of {@link SOAP_Type_dateTime::toUTC}. + */ + function toSOAP($date = NULL) + { + return $this->toUTC($date); + } + + /** + * Converts this object or a timestamp to an ISO 8601 date/time string. + * + * @param integer $timestamp A unix timestamp + * + * @return string An ISO 8601 formatted date/time string. + */ + function toString($timestamp = 0) + { + if (!$timestamp) { + $timestamp = $this->timestamp; + } + if ($timestamp < 0) { + return 0; + } + + return date('Y-m-d\TH:i:sO', $timestamp); + } + + /** + * Splits a date/time into its components. + * + * @param string|integer $datestr A unix timestamp or ISO 8601 date/time + * string. If empty, this object is used. + * + * @return boolean|array An array with the date and time components or + * false on failure. + */ + function _split($datestr) + { + if (!$datestr) { + $datestr = $this->toString(); + } elseif (is_int($datestr)) { + $datestr = $this->toString($datestr); + } + + if (preg_match('/' . $this->_iso8601 . '/x', $datestr, $regs)) { + if (empty($regs[8])) { + $timestamp = strtotime(sprintf('%04d-%02d-%02d %02d:%02d:%02d', + $regs[1], + $regs[2], + $regs[3], + $regs[4], + $regs[5], + $regs[6])); + $regs[8] = date('O', $timestamp); + } + if ($regs[8] != 'Z') { + $op = substr($regs[8], 0, 1); + $h = substr($regs[8], 1, 2); + if (strstr($regs[8], ':')) { + $m = substr($regs[8], 4, 2); + } else { + $m = substr($regs[8], 3, 2); + } + if ($op == '+') { + $regs[4] = $regs[4] - $h; + if ($regs[4] < 0) { + $regs[4] += 24; + } + $regs[5] = $regs[5] - $m; + if ($regs[5] < 0) { + $regs[5] += 60; + } + } else { + $regs[4] = $regs[4] + $h; + if ($regs[4] > 23) { + $regs[4] -= 24; + } + $regs[5] = $regs[5] + $m; + if ($regs[5] > 59) { + $regs[5] -= 60; + } + } + } + return $regs; + } + + return false; + } + + /** + * Returns an ISO 8601 formatted UTC date/time string. + * + * @param string|integer $datestr @see SOAP_Type_dateTime::_split + * + * @return string The ISO 8601 formatted UTC date/time string. + */ + function toUTC($datestr = null) + { + $regs = $this->_split($datestr); + + if ($regs) { + return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', + $regs[1], + $regs[2], + $regs[3], + $regs[4], + $regs[5], + $regs[6]); + } + + return ''; + } + + /** + * Returns a unix timestamp. + * + * @param string|integer $datestr @see SOAP_Type_dateTime::_split + * + * @return integer The unix timestamp. + */ + function toUnixtime($datestr = null) + { + $regs = $this->_split($datestr); + if ($regs) { + return strtotime(sprintf('%04d-%02d-%02d %02d:%02d:%02dZ', + $regs[1], + $regs[2], + $regs[3], + $regs[4], + $regs[5], + $regs[6])); + } + return -1; + } + + /** + * Compares two dates or this object with a second date. + * + * @param string|integer $date1 A unix timestamp or ISO 8601 date/time + * string. + * @param string|integer $date2 A unix timestamp or ISO 8601 date/time + * string. If empty, this object is used. + * + * @return integer The difference between the first and the second date. + */ + function compare($date1, $date2 = null) + { + if (is_null($date2)) { + $date2 = $date1; + $date1 = $this->timestamp; + } + if (!is_int($date1)) { + $date1 = $this->toUnixtime($date1); + } + if (!is_int($date2)) { + $date2 = $this->toUnixtime($date2); + } + + if ($date1 != -1 && $date2 != -1) { + return $date1 - $date2; + } + + return -1; + } + +} diff --git a/thirdparty/pear/SOAP/Type/duration.php b/thirdparty/pear/SOAP/Type/duration.php new file mode 100644 index 0000000..078e4a4 --- /dev/null +++ b/thirdparty/pear/SOAP/Type/duration.php @@ -0,0 +1,165 @@ + \ No newline at end of file diff --git a/thirdparty/pear/SOAP/Type/hexBinary.php b/thirdparty/pear/SOAP/Type/hexBinary.php new file mode 100644 index 0000000..150e45d --- /dev/null +++ b/thirdparty/pear/SOAP/Type/hexBinary.php @@ -0,0 +1,46 @@ + Port to PEAR and more | +// | Authors: Dietrich Ayala Original Author | +// +----------------------------------------------------------------------+ +// +// $Id: hexBinary.php,v 1.6 2005/03/10 23:16:39 yunosh Exp $ +// +class SOAP_Type_hexBinary +{ + function to_bin($value) + { + $len = strlen($value); + return pack('H' . $len, $value); + } + function to_hex($value) + { + return bin2hex($value); + } + function is_hexbin($value) + { + # first see if there are any invalid chars + $l = strlen($value); + + if ($l < 1 || strspn($value, '0123456789ABCDEFabcdef') != $l) return FALSE; + + $bin = SOAP_Type_hexBinary::to_bin($value); + $hex = SOAP_Type_hexBinary::to_hex($bin); + return strcasecmp($value, $hex) == 0; + } +} + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/Value.php b/thirdparty/pear/SOAP/Value.php new file mode 100644 index 0000000..5bf468b --- /dev/null +++ b/thirdparty/pear/SOAP/Value.php @@ -0,0 +1,243 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; + +/** + * SOAP::Value + * + * This class converts values between PHP and SOAP. + * + * Originally based on SOAPx4 by Dietrich Ayala + * http://dietrich.ganx4.com/soapx4 + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + * @author Dietrich Ayala Original Author + */ +class SOAP_Value +{ + /** + * @var string + */ + var $value = null; + + /** + * @var string + */ + var $name = ''; + + /** + * @var string + */ + var $type = ''; + + /** + * Namespace + * + * @var string + */ + var $namespace = ''; + var $type_namespace = ''; + + var $attributes = array(); + + /** + * @var string + */ + var $arrayType = ''; + + var $options = array(); + + var $nqn; + var $tqn; + + /** + * Constructor. + * + * @param string $name Name of the SOAP value {namespace}name. + * @param mixed $type SOAP value {namespace}type. Determined + * automatically if not set. + * @param mixed $value Value to set. + * @param array $attributes Attributes. + */ + function SOAP_Value($name = '', $type = false, $value = null, + $attributes = array()) + { + // Detect type if not passed. + $this->nqn =& new QName($name); + $this->name = $this->nqn->name; + $this->namespace = $this->nqn->namespace; + $this->tqn =& new QName($type); + $this->type = $this->tqn->name; + $this->type_prefix = $this->tqn->ns; + $this->type_namespace = $this->tqn->namespace; + $this->value =& $value; + $this->attributes = $attributes; + } + + /** + * Serializes this value. + * + * @param SOAP_Base $serializer A SOAP_Base instance or subclass to + * serialize with. + * + * @return string XML representation of $this. + */ + function serialize(&$serializer) + { + return $serializer->_serializeValue($this->value, + $this->name, + $this->type, + $this->namespace, + $this->type_namespace, + $this->options, + $this->attributes, + $this->arrayType); + } + +} + +/** + * This class converts values between PHP and SOAP. It is a simple wrapper + * around SOAP_Value, adding support for SOAP actor and mustunderstand + * parameters. + * + * Originally based on SOAPx4 by Dietrich Ayala + * http://dietrich.ganx4.com/soapx4 + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + * @author Dietrich Ayala Original Author + */ +class SOAP_Header extends SOAP_Value +{ + /** + * Constructor + * + * @param string $name Name of the SOAP value {namespace}name. + * @param mixed $type SOAP value {namespace}type. Determined + * automatically if not set. + * @param mixed $value Value to set + * @param integer $mustunderstand Zero or one. + * @param mixed $attributes Attributes. + */ + function SOAP_Header($name = '', $type, $value, $mustunderstand = 0, + $attributes = array()) + { + if (!is_array($attributes)) { + $actor = $attributes; + $attributes = array(); + } + + parent::SOAP_Value($name, $type, $value, $attributes); + + if (isset($actor)) { + $this->attributes['SOAP-ENV:actor'] = $actor; + } elseif (!isset($this->attributes['SOAP-ENV:actor'])) { + $this->attributes['SOAP-ENV:actor'] = 'http://schemas.xmlsoap.org/soap/actor/next'; + } + $this->attributes['SOAP-ENV:mustUnderstand'] = (int)$mustunderstand; + } + +} + +/** + * This class handles MIME attachements per W3C's Note on Soap Attachements at + * http://www.w3.org/TR/SOAP-attachments + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + */ +class SOAP_Attachment extends SOAP_Value +{ + /** + * Constructor. + * + * @param string $name Name of the SOAP value + * @param string $type The attachment's MIME type. + * @param string $filename The attachment's file name. Ignored if $file + * is provide. + * @param string $file The attachment data. + */ + function SOAP_Attachment($name = '', $type = 'application/octet-stream', + $filename, $file = null) + { + parent::SOAP_Value($name, null, null); + + if (!isset($GLOBALS['SOAP_options']['Mime'])) { + $this->options['attachment'] = PEAR::raiseError('Mail_mime is not installed, unable to support SOAP Attachements'); + return; + } + + $filedata = ($file === null) ? $this->_file2str($filename) : $file; + $filename = basename($filename); + if (PEAR::isError($filedata)) { + $this->options['attachment'] = $filedata; + return; + } + + $cid = md5(uniqid(time())); + + $this->attributes['href'] = 'cid:' . $cid; + + $this->options['attachment'] = array('body' => $filedata, + 'disposition' => $filename, + 'content_type' => $type, + 'encoding' => 'base64', + 'cid' => $cid); + } + + /** + * Returns the contents of the given file name as string. + * + * @access private + * + * @param string $file_name The file location. + * + * @return string The file data or a PEAR_Error. + */ + function _file2str($file_name) + { + if (!is_readable($file_name)) { + return PEAR::raiseError('File is not readable: ' . $file_name); + } + + if (function_exists('file_get_contents')) { + return file_get_contents($file_name); + } + + if (!$fd = fopen($file_name, 'rb')) { + return PEAR::raiseError('Could not open ' . $file_name); + } + $cont = fread($fd, filesize($file_name)); + fclose($fd); + + return $cont; + } + +} diff --git a/thirdparty/pear/SOAP/WSDL.php b/thirdparty/pear/SOAP/WSDL.php new file mode 100644 index 0000000..db8b907 --- /dev/null +++ b/thirdparty/pear/SOAP/WSDL.php @@ -0,0 +1,2183 @@ + Original Author + * @author Shane Caraveo Port to PEAR and more + * @author Chuck Hagenbuch Maintenance + * @author Jan Schneider Maintenance + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require_once 'SOAP/Base.php'; +require_once 'SOAP/Fault.php'; +require_once 'HTTP/Request.php'; + +define('WSDL_CACHE_MAX_AGE', 43200); +define('WSDL_CACHE_USE', 0); // set to zero to turn off caching + +/** + * This class parses WSDL files, and can be used by SOAP::Client to properly + * register soap values for services. + * + * Originally based on SOAPx4 by Dietrich Ayala + * http://dietrich.ganx4.com/soapx4 + * + * @todo + * - add wsdl caching + * - refactor namespace handling ($namespace/$ns) + * - implement IDL type syntax declaration so we can generate WSDL + * + * @access public + * @package SOAP + * @author Shane Caraveo Conversion to PEAR and updates + * @author Dietrich Ayala Original Author + */ +class SOAP_WSDL extends SOAP_Base +{ + var $tns = null; + var $definition = array(); + var $namespaces = array(); + var $ns = array(); + var $xsd = SOAP_XML_SCHEMA_VERSION; + var $complexTypes = array(); + var $elements = array(); + var $messages = array(); + var $portTypes = array(); + var $bindings = array(); + var $imports = array(); + var $services = array(); + var $service = ''; + var $uri = ''; + var $docs = false; + + /** + * Proxy parameters + * + * @var array + */ + var $proxy = null; + + var $trace = 0; + + /** + * Use WSDL cache. + * + * @var boolean + */ + var $cacheUse = null; + + /** + * Cache max lifetime (in seconds). + * + * @var integer + */ + var $cacheMaxAge = null; + + /** + * Class to use for WSDL parsing. Can be overridden for special cases, + * subclasses, etc. + * + * @var string + */ + var $wsdlParserClass = 'SOAP_WSDL_Parser'; + + /** + * SOAP_WSDL constructor. + * + * @param string $wsdl_uri URL to WSDL file. + * @param array $proxy Contains options for HTTP_Request class + * @see HTTP_Request. + * @param boolean $cacheUse Use WSDL caching. Defaults to false. + * @param integer $cacheMaxAge Cache max lifetime (in seconds). + * @param boolean $docs Parse documentation in the WSDL? Defaults + * to false. + * + * @access public + */ + function SOAP_WSDL($wsdl_uri = false, + $proxy = array(), + $cacheUse = WSDL_CACHE_USE, + $cacheMaxAge = WSDL_CACHE_MAX_AGE, + $docs = false) + { + parent::SOAP_Base('WSDL'); + $this->uri = $wsdl_uri; + $this->proxy = $proxy; + $this->cacheUse = $cacheUse; + $this->cacheMaxAge = $cacheMaxAge; + $this->docs = $docs; + + if ($wsdl_uri) { + if (!PEAR::isError($this->parseURL($wsdl_uri))) { + reset($this->services); + $this->service = key($this->services); + } + } + } + + function set_service($service) + { + if (array_key_exists($service, $this->services)) { + $this->service = $service; + } + } + + /** + * @deprecated use parseURL instead + */ + function parse($wsdl_uri, $proxy = array()) + { + $this->parseURL($wsdl_uri, $proxy); + } + + /** + * Fills the WSDL array tree with data from a WSDL file. + * + * @param string $wsdl_uri URL to WSDL file. + * @param array $proxy Contains options for HTTP_Request class + * @see HTTP_Request. + */ + function parseURL($wsdl_uri, $proxy = array()) + { + $parser =& new $this->wsdlParserClass($wsdl_uri, $this, $this->docs); + + if ($parser->fault) { + $this->_raiseSoapFault($parser->fault); + } + } + + /** + * Fills the WSDL array tree with data from one or more PHP class objects. + * + * @param mixed $wsdl_obj An object or array of objects to add to + * the internal WSDL tree. + * @param string $targetNamespace The target namespace of schema types + * etc. + * @param string $service_name Name of the WSDL service. + * @param string $service_desc Optional description of the WSDL + * service. + */ + function parseObject(&$wsdl_obj, $targetNamespace, $service_name, + $service_desc = '') + { + $parser =& new SOAP_WSDL_ObjectParser($wsdl_obj, $this, + $targetNamespace, $service_name, + $service_desc); + + if ($parser->fault) { + $this->_raiseSoapFault($parser->fault); + } + } + + function getEndpoint($portName) + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + return (isset($this->services[$this->service]['ports'][$portName]['address']['location'])) + ? $this->services[$this->service]['ports'][$portName]['address']['location'] + : $this->_raiseSoapFault("No endpoint for port for $portName", $this->uri); + } + + function _getPortName($operation, $service) + { + if (isset($this->services[$service]['ports'])) { + $ports = $this->services[$service]['ports']; + foreach ($ports as $port => $portAttrs) { + $type = $ports[$port]['type']; + if ($type == 'soap' && + isset($this->bindings[$portAttrs['binding']]['operations'][$operation])) { + return $port; + } + } + } + return null; + } + + /** + * Finds the name of the first port that contains an operation of name + * $operation. Always returns a SOAP portName. + */ + function getPortName($operation, $service = null) + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + if (!$service) { + $service = $this->service; + } + if (isset($this->services[$service]['ports'])) { + if ($portName = $this->_getPortName($operation, $service)) { + return $portName; + } + } + // Try any service in the WSDL. + foreach ($this->services as $serviceName => $service) { + if (isset($this->services[$serviceName]['ports'])) { + if ($portName = $this->_getPortName($operation, $serviceName)) { + $this->service = $serviceName; + return $portName; + } + } + } + return $this->_raiseSoapFault("No operation $operation in WSDL.", $this->uri); + } + + function getOperationData($portName, $operation) + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + if (!isset($this->services[$this->service]['ports'][$portName]['binding']) || + !($binding = $this->services[$this->service]['ports'][$portName]['binding'])) { + return $this->_raiseSoapFault("No binding for port $portName in WSDL.", $this->uri); + } + + // Get operation data from binding. + if (is_array($this->bindings[$binding]['operations'][$operation])) { + $opData = $this->bindings[$binding]['operations'][$operation]; + } + // get operation data from porttype + $portType = $this->bindings[$binding]['type']; + if (!$portType) { + return $this->_raiseSoapFault("No port type for binding $binding in WSDL.", $this->uri); + } + if (is_array($type = $this->portTypes[$portType][$operation])) { + if (isset($type['parameterOrder'])) { + $opData['parameterOrder'] = $type['parameterOrder']; + } + $opData['input'] = array_merge($opData['input'], $type['input']); + $opData['output'] = array_merge($opData['output'], $type['output']); + } + if (!$opData) + return $this->_raiseSoapFault("No operation $operation for port $portName in WSDL.", $this->uri); + $opData['parameters'] = false; + if (isset($this->bindings[$binding]['operations'][$operation]['input']['namespace'])) + $opData['namespace'] = $this->bindings[$binding]['operations'][$operation]['input']['namespace']; + // Message data from messages. + $inputMsg = $opData['input']['message']; + if (is_array($this->messages[$inputMsg])) { + foreach ($this->messages[$inputMsg] as $pname => $pattrs) { + if ($opData['style'] == 'document' && + $opData['input']['use'] == 'literal' && + $pname == 'parameters') { + $opData['parameters'] = true; + $opData['namespace'] = $this->namespaces[$pattrs['namespace']]; + $el = $this->elements[$pattrs['namespace']][$pattrs['type']]; + if (isset($el['elements'])) { + foreach ($el['elements'] as $elname => $elattrs) { + $opData['input']['parts'][$elname] = $elattrs; + } + } + } else { + $opData['input']['parts'][$pname] = $pattrs; + } + } + } + $outputMsg = $opData['output']['message']; + if (is_array($this->messages[$outputMsg])) { + foreach ($this->messages[$outputMsg] as $pname => $pattrs) { + if ($opData['style'] == 'document' && + $opData['output']['use'] == 'literal' && + $pname == 'parameters') { + + $el = $this->elements[$pattrs['namespace']][$pattrs['type']]; + if (isset($el['elements'])) { + foreach ($el['elements'] as $elname => $elattrs) { + $opData['output']['parts'][$elname] = $elattrs; + } + } + } else { + $opData['output']['parts'][$pname] = $pattrs; + } + } + } + return $opData; + } + + function matchMethod(&$operation) + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + // Overloading lowercases function names :( + foreach ($this->services[$this->service]['ports'] as $port => $portAttrs) { + foreach (array_keys($this->bindings[$portAttrs['binding']]['operations']) as $op) { + if (strcasecmp($op, $operation) == 0) { + $operation = $op; + } + } + } + } + + /** + * Given a datatype, what function handles the processing? + * + * This is used for doc/literal requests where we receive a datatype, and + * we need to pass it to a method in out server class. + * + * @param string $datatype + * @param string $namespace + * @return string + * @access public + */ + function getDataHandler($datatype, $namespace) + { + // See if we have an element by this name. + if (isset($this->namespaces[$namespace])) { + $namespace = $this->namespaces[$namespace]; + } + + if (isset($this->ns[$namespace])) { + $nsp = $this->ns[$namespace]; + //if (!isset($this->elements[$nsp])) + // $nsp = $this->namespaces[$nsp]; + if (isset($this->elements[$nsp][$datatype])) { + $checkmessages = array(); + // Find what messages use this datatype. + foreach ($this->messages as $messagename => $message) { + foreach ($message as $partname => $part) { + if ($part['type'] == $datatype) { + $checkmessages[] = $messagename; + break; + } + } + } + // Find the operation that uses this message. + $dataHandler = null; + foreach($this->portTypes as $portname => $porttype) { + foreach ($porttype as $opname => $opinfo) { + foreach ($checkmessages as $messagename) { + if ($opinfo['input']['message'] == $messagename) { + return $opname; + } + } + } + } + } + } + + return null; + } + + function getSoapAction($portName, $operation) + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + if (!empty($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction'])) { + return $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction']; + } + + return false; + } + + function getNamespace($portName, $operation) + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + if (!empty($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'])) { + return $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace']; + } + + return false; + } + + function getNamespaceAttributeName($namespace) + { + /* If it doesn't exist at first, flip the array and check again. */ + if (empty($this->ns[$namespace])) { + $this->ns = array_flip($this->namespaces); + } + + /* If it doesn't exist now, add it. */ + if (empty($this->ns[$namespace])) { + return $this->addNamespace($namespace); + } + + return $this->ns[$namespace]; + } + + function addNamespace($namespace) + { + if (!empty($this->ns[$namespace])) { + return $this->ns[$namespace]; + } + + $n = count($this->ns); + $attr = 'ns' . $n; + $this->namespaces['ns' . $n] = $namespace; + $this->ns[$namespace] = $attr; + + return $attr; + } + + function _validateString($string) + { + return preg_match('/^[\w_:#\/]+$/', $string); + } + + function _addArg(&$args, &$argarray, $argname) + { + if ($args) { + $args .= ', '; + } + $args .= '$' . $argname; + if (!$this->_validateString($argname)) { + return; + } + if ($argarray) { + $argarray .= ', '; + } + $argarray .= "'$argname' => $" . $argname; + } + + function _elementArg(&$args, &$argarray, &$_argtype, $_argname) + { + $comments = ''; + $el = $this->elements[$_argtype['namespace']][$_argtype['type']]; + $tns = isset($this->ns[$el['namespace']]) + ? $this->ns[$el['namespace']] + : $_argtype['namespace']; + + if (!empty($el['complex']) || + (isset($el['type']) && + isset($this->complexTypes[$tns][$el['type']]))) { + // The element is a complex type. + $comments .= " // {$_argtype['type']} is a ComplexType, refer to the WSDL for more info.\n"; + $attrname = "{$_argtype['type']}_attr"; + if (isset($el['type']) && + isset($this->complexTypes[$tns][$el['type']]['attribute'])) { + $comments .= " // {$_argtype['type']} may require attributes, refer to the WSDL for more info.\n"; + } + $comments .= " \${$attrname}['xmlns'] = '{$this->namespaces[$_argtype['namespace']]}';\n"; + $comments .= " \${$_argtype['type']} =& new SOAP_Value('{$_argtype['type']}', false, \${$_argtype['type']}, \$$attrname);\n"; + $this->_addArg($args, $argarray, $_argtype['type']); + if (isset($el['type']) && + isset($this->complexTypes[$tns][$el['type']]['attribute'])) { + if ($args) { + $args .= ', '; + } + $args .= '$' . $attrname; + } + } elseif (isset($el['elements'])) { + foreach ($el['elements'] as $ename => $element) { + $comments .= " \$$ename =& new SOAP_Value('{{$this->namespaces[$element['namespace']]}}$ename', '" . + (isset($element['type']) ? $element['type'] : false) . + "', \$$ename);\n"; + $this->_addArg($args, $argarray, $ename); + } + } else { + $comments .= " \$$_argname =& new SOAP_Value('{{$this->namespaces[$tns]}}$_argname', '{$el['type']}', \$$_argname);\n"; + $this->_addArg($args, $argarray, $_argname); + } + + return $comments; + } + + function _complexTypeArg(&$args, &$argarray, &$_argtype, $_argname) + { + $comments = ''; + if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']])) { + $comments = " // $_argname is a ComplexType {$_argtype['type']},\n" . + " // refer to wsdl for more info\n"; + if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']]['attribute'])) { + $comments .= " // $_argname may require attributes, refer to wsdl for more info\n"; + } + $wrapname = '{' . $this->namespaces[$_argtype['namespace']].'}' . $_argtype['type']; + $comments .= " \$$_argname =& new SOAP_Value('$_argname', '$wrapname', \$$_argname);\n"; + } + + $this->_addArg($args, $argarray, $_argname); + + return $comments; + } + + /** + * Generates stub code from the WSDL that can be saved to a file or eval'd + * into existence. + */ + function generateProxyCode($port = '', $classname = '') + { + if ($this->__isfault()) { + return $this->__getfault(); + } + + $multiport = count($this->services[$this->service]['ports']) > 1; + if (!$port) { + reset($this->services[$this->service]['ports']); + $port = current($this->services[$this->service]['ports']); + } + // XXX currently do not support HTTP ports + if ($port['type'] != 'soap') { + return null; + } + + // XXX currentPort is BAD + $clienturl = $port['address']['location']; + if (!$classname) { + if ($multiport || $port) { + $classname = 'WebService_' . $this->service . '_' . $port['name']; + } else { + $classname = 'WebService_' . $this->service; + } + $classname = preg_replace('/[ .\-\(\)]+/', '_', $classname); + } + + if (!$this->_validateString($classname)) { + return null; + } + + if (is_array($this->proxy) && count($this->proxy)) { + $class = "class $classname extends SOAP_Client\n{\n" . + " function $classname(\$path = '$clienturl')\n {\n" . + " \$this->SOAP_Client(\$path, 0, 0,\n" . + ' array('; + + foreach ($this->proxy as $key => $val) { + if (is_array($val)) { + $class .= "'$key' => array("; + foreach ($val as $key2 => $val2) { + $class .= "'$key2' => '$val2', "; + } + $class .= ')'; + } else { + $class .= "'$key' => '$val', "; + } + } + $class .= "));\n }\n"; + $class = str_replace(', ))', '))', $class); + } else { + $class = "class $classname extends SOAP_Client\n{\n" . + " function $classname(\$path = '$clienturl')\n {\n" . + " \$this->SOAP_Client(\$path, 0);\n" . + " }\n"; + } + + // Get the binding, from that get the port type. + $primaryBinding = $port['binding']; + $primaryBinding = preg_replace("/^(.*:)/", '', $primaryBinding); + $portType = $this->bindings[$primaryBinding]['type']; + $portType = preg_replace("/^(.*:)/", '', $portType); + $style = $this->bindings[$primaryBinding]['style']; + + // XXX currentPortType is BAD + foreach ($this->portTypes[$portType] as $opname => $operation) { + $binding = $this->bindings[$primaryBinding]['operations'][$opname]; + if (isset($binding['soapAction'])) { + $soapaction = $binding['soapAction']; + } else { + $soapaction = null; + } + if (isset($binding['style'])) { + $opstyle = $binding['style']; + } else { + $opstyle = $style; + } + $use = $binding['input']['use']; + if ($use == 'encoded') { + $namespace = $binding['input']['namespace']; + } else { + $bindingType = $this->bindings[$primaryBinding]['type']; + $ns = $this->portTypes[$bindingType][$opname]['input']['namespace']; + $namespace = $this->namespaces[$ns]; + } + + $args = ''; + $argarray = ''; + $comments = ''; + $wrappers = ''; + foreach ($operation['input'] as $argname => $argtype) { + if ($argname == 'message') { + foreach ($this->messages[$argtype] as $_argname => $_argtype) { + if ($opstyle == 'document' && $use == 'literal' && + $_argtype['name'] == 'parameters') { + // The type or element refered to is used for + // parameters. + $elattrs = null; + $element = $_argtype['element']; + $el = $this->elements[$_argtype['namespace']][$_argtype['type']]; + + if ($el['complex']) { + $namespace = $this->namespaces[$_argtype['namespace']]; + // XXX need to wrap the parameters in a + // SOAP_Value. + } + if (isset($el['elements'])) { + foreach ($el['elements'] as $elname => $elattrs) { + // Is the element a complex type? + if (isset($this->complexTypes[$elattrs['namespace']][$elname])) { + $comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname); + } else { + $this->_addArg($args, $argarray, $elname); + } + } + } + if ($el['complex'] && $argarray) { + $wrapname = '{' . $this->namespaces[$_argtype['namespace']].'}' . $el['name']; + $comments .= " \${$el['name']} =& new SOAP_Value('$wrapname', false, \$v = array($argarray));\n"; + $argarray = "'{$el['name']}' => \${$el['name']}"; + } + } else { + if (isset($_argtype['element'])) { + // Element argument. + $comments .= $this->_elementArg($args, $argarray, $_argtype, $_argtype['type']); + } else { + // Complex type argument. + $comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname); + } + } + } + } + } + + // Validate entries. + + // Operation names are function names, so try to make sure it's + // legal. This could potentially cause collisions, but let's try + // to make everything callable and see how many problems that + // causes. + $opname_php = preg_replace('/[ .\-\(\)]+/', '_', $opname); + if (!$this->_validateString($opname_php)) { + return null; + } + + if ($argarray) { + $argarray = "array($argarray)"; + } else { + $argarray = 'null'; + } + + $class .= " function &$opname_php($args)\n {\n$comments$wrappers" . + " \$result = \$this->call('$opname',\n" . + " \$v = $argarray,\n" . + " array('namespace' => '$namespace',\n" . + " 'soapaction' => '$soapaction',\n" . + " 'style' => '$opstyle',\n" . + " 'use' => '$use'" . + ($this->trace?",\n 'trace' => 1" : '') . "));\n" . + " return \$result;\n" . + " }\n"; + } + + $class .= "}\n"; + + return $class; + } + + function generateAllProxies() + { + $proxycode = ''; + foreach (array_keys($this->services[$this->service]['ports']) as $key) { + $port =& $this->services[$this->service]['ports'][$key]; + $proxycode .= $this->generateProxyCode($port); + } + return $proxycode; + } + + function &getProxy($port = '', $name = '') + { + if ($this->__isfault()) { + $fault =& $this->__getfault(); + return $fault; + } + + $multiport = count($this->services[$this->service]['ports']) > 1; + + if (!$port) { + reset($this->services[$this->service]['ports']); + $port = current($this->services[$this->service]['ports']); + } + + if ($multiport || $port) { + $classname = 'WebService_' . $this->service . '_' . $port['name']; + } else { + $classname = 'WebService_' . $this->service; + } + + if ($name) { + $classname = $name . '_' . $classname; + } + + $classname = preg_replace('/[ .\-\(\)]+/', '_', $classname); + if (!class_exists($classname)) { + $proxy = $this->generateProxyCode($port, $classname); + require_once 'SOAP/Client.php'; + eval($proxy); + } + $proxy =& new $classname; + + return $proxy; + } + + function &_getComplexTypeForElement($name, $namespace) + { + $t = null; + if (isset($this->ns[$namespace]) && + isset($this->elements[$this->ns[$namespace]][$name]['type'])) { + + $type = $this->elements[$this->ns[$namespace]][$name]['type']; + $ns = $this->elements[$this->ns[$namespace]][$name]['namespace']; + + if (isset($this->complexTypes[$ns][$type])) { + $t = $this->complexTypes[$ns][$type]; + } + } + return $t; + } + + function getComplexTypeNameForElement($name, $namespace) + { + $t = $this->_getComplexTypeForElement($name, $namespace); + if ($t) { + return $t['name']; + } + return null; + } + + function getComplexTypeChildType($ns, $name, $child_ns, $child_name) + { + // is the type an element? + $t = $this->_getComplexTypeForElement($name, $ns); + if ($t) { + // no, get it from complex types directly + if (isset($t['elements'][$child_name]['type'])) + return $t['elements'][$child_name]['type']; + } + return null; + } + + function getSchemaType($type, $name, $type_namespace) + { + // see if it's a complex type so we can deal properly with + // SOAPENC:arrayType. + if ($name && $type) { + // XXX TODO: + // look up the name in the wsdl and validate the type. + foreach ($this->complexTypes as $ns => $types) { + if (array_key_exists($type, $types)) { + if (array_key_exists('type', $types[$type])) { + list($arraytype_ns, $arraytype, $array_depth) = isset($types[$type]['arrayType'])? + $this->_getDeepestArrayType($types[$type]['namespace'], $types[$type]['arrayType']) + : array($this->namespaces[$types[$type]['namespace']], null, 0); + return array($types[$type]['type'], $arraytype, $arraytype_ns, $array_depth); + } + if (array_key_exists('arrayType', $types[$type])) { + list($arraytype_ns, $arraytype, $array_depth) = + $this->_getDeepestArrayType($types[$type]['namespace'], $types[$type]['arrayType']); + return array('Array', $arraytype, $arraytype_ns, $array_depth); + } + if (array_key_exists('elements', $types[$type]) && + array_key_exists($name, $types[$type]['elements'])) { + $type = $types[$type]['elements']['type']; + return array($type, null, $this->namespaces[$types[$type]['namespace']], null); + } + } + } + } + if ($type && $type_namespace) { + $arrayType = null; + // XXX TODO: + // this code currently handles only one way of encoding array types in wsdl + // need to do a generalized function to figure out complex types + $p = $this->ns[$type_namespace]; + if ($p && + array_key_exists($p, $this->complexTypes) && + array_key_exists($type, $this->complexTypes[$p])) { + if ($arrayType = $this->complexTypes[$p][$type]['arrayType']) { + $type = 'Array'; + } elseif ($this->complexTypes[$p][$type]['order']=='sequence' && + array_key_exists('elements', $this->complexTypes[$p][$type])) { + reset($this->complexTypes[$p][$type]['elements']); + // assume an array + if (count($this->complexTypes[$p][$type]['elements']) == 1) { + $arg = current($this->complexTypes[$p][$type]['elements']); + $arrayType = $arg['type']; + $type = 'Array'; + } else { + foreach ($this->complexTypes[$p][$type]['elements'] as $element) { + if ($element['name'] == $type) { + $arrayType = $element['type']; + $type = $element['type']; + } + } + } + } else { + $type = 'Struct'; + } + return array($type, $arrayType, $type_namespace, null); + } + } + return array(null, null, null, null); + } + + /** + * Recurse through the WSDL structure looking for the innermost array type + * of multi-dimensional arrays. + * + * Takes a namespace prefix and a type, which can be in the form 'type' or + * 'type[]', and returns the full namespace URI, the type of the most + * deeply nested array type found, and the number of levels of nesting. + * + * @access private + * @return mixed array or nothing + */ + function _getDeepestArrayType($nsPrefix, $arrayType) + { + static $trail = array(); + + $arrayType = ereg_replace('\[\]$', '', $arrayType); + + // Protect against circular references XXX We really need to remove + // trail from this altogether (it's very inefficient and in the wrong + // place!) and put circular reference checking in when the WSDL info + // is generated in the first place + if (array_search($nsPrefix . ':' . $arrayType, $trail)) { + return array(null, null, -count($trail)); + } + + if (array_key_exists($nsPrefix, $this->complexTypes) && + array_key_exists($arrayType, $this->complexTypes[$nsPrefix]) && + array_key_exists('arrayType', $this->complexTypes[$nsPrefix][$arrayType])) { + $trail[] = $nsPrefix . ':' . $arrayType; + $result = $this->_getDeepestArrayType($this->complexTypes[$nsPrefix][$arrayType]['namespace'], + $this->complexTypes[$nsPrefix][$arrayType]['arrayType']); + return array($result[0], $result[1], $result[2] + 1); + } + return array($this->namespaces[$nsPrefix], $arrayType, 0); + } + +} + +class SOAP_WSDL_Cache extends SOAP_Base +{ + // Cache settings + + /** + * Use WSDL cache + * + * @var boolean + */ + var $_cacheUse = null; + + /** + * Cache max lifetime (in seconds) + * + * @var int + */ + var $_cacheMaxAge = null; + + /** + * SOAP_WSDL_Cache constructor + * + * @param boolean use caching + * @param int cache max lifetime (in seconds) + * @access public + */ + function SOAP_WSDL_Cache($cacheUse = WSDL_CACHE_USE, + $cacheMaxAge = WSDL_CACHE_MAX_AGE) + { + parent::SOAP_Base('WSDLCACHE'); + $this->_cacheUse = $cacheUse; + $this->_cacheMaxAge = $cacheMaxAge; + } + + /** + * _cacheDir + * return the path to the cache, if it doesn't exist, make it + */ + function _cacheDir() + { + $dir = getenv("WSDLCACHE"); + if (!$dir) $dir = " ./wsdlcache"; + @mkdir($dir, 0700); + return $dir; + } + + /** + * Retrieves a file from cache if it exists, otherwise retreive from net, + * add to cache, and return from cache. + * + * @param string URL to WSDL + * @param array proxy parameters + * @param int expected MD5 of WSDL URL + * @access public + * @return string data + */ + function get($wsdl_fname, $proxy_params = array(), $cache = 0) + { + $cachename = $md5_wsdl = $file_data = ''; + if ($this->_cacheUse) { + // Try to retrieve WSDL from cache + $cachename = SOAP_WSDL_Cache::_cacheDir() . '/' . md5($wsdl_fname). ' .wsdl'; + if (file_exists($cachename)) { + $wf = fopen($cachename, 'rb'); + if ($wf) { + // Reading cached file + $file_data = fread($wf, filesize($cachename)); + $md5_wsdl = md5($file_data); + fclose($wf); + } + if ($cache) { + if ($cache != $md5_wsdl) { + return $this->_raiseSoapFault('WSDL Checksum error!', $wsdl_fname); + } + } else { + $fi = stat($cachename); + $cache_mtime = $fi[8]; + //print cache_mtime, time() + if ($cache_mtime + $this->_cacheMaxAge < time()) { + // expired + $md5_wsdl = ''; // refetch + } + } + } + } + + if (!$md5_wsdl) { + // Not cached or not using cache. Retrieve WSDL from URL + + // is it a local file? + // this section should be replace by curl at some point + if (!preg_match('/^(https?|file):\/\//', $wsdl_fname)) { + if (!file_exists($wsdl_fname)) { + return $this->_raiseSoapFault("Unable to read local WSDL $wsdl_fname", $wsdl_fname); + } + if (function_exists('file_get_contents')) { + $file_data = file_get_contents($wsdl_fname); + } else { + $file_data = implode('',file($wsdl_fname)); + } + } else { + $uri = explode('?', $wsdl_fname); + $rq =& new HTTP_Request($uri[0], $proxy_params); + // the user agent HTTP_Request uses fouls things up + if (isset($uri[1])) { + $rq->addRawQueryString($uri[1]); + } + + if (isset($proxy_params['proxy_host']) && + isset($proxy_params['proxy_port']) && + isset($proxy_params['proxy_user']) && + isset($proxy_params['proxy_pass'])) { + $rq->setProxy($proxy_params['proxy_host'], $proxy_params['proxy_port'], + $proxy_params['proxy_user'], $proxy_params['proxy_pass']); + } elseif (isset($proxy_params['proxy_host']) && + isset($proxy_params['proxy_port'])) { + $rq->setProxy($proxy_params['proxy_host'], $proxy_params['proxy_port']); + } + + $result = $rq->sendRequest(); + if (PEAR::isError($result)) { + return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname," . $rq->getResponseCode(), $wsdl_fname); + } + $file_data = $rq->getResponseBody(); + if (!$file_data) { + return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname, no http body", $wsdl_fname); + } + } + + $md5_wsdl = md5($file_data); + + if ($this->_cacheUse) { + $fp = fopen($cachename, "wb"); + fwrite($fp, $file_data); + fclose($fp); + } + } + if ($this->_cacheUse && $cache && $cache != $md5_wsdl) { + return $this->_raiseSoapFault("WSDL Checksum error!", $wsdl_fname); + } + return $file_data; + } + +} + +class SOAP_WSDL_Parser extends SOAP_Base +{ + + /** + * Define internal arrays of bindings, ports, operations, + * messages, etc. + */ + var $currentMessage; + var $currentOperation; + var $currentPortType; + var $currentBinding; + var $currentPort; + + /** + * Parser vars. + */ + var $cache; + + var $tns = null; + var $soapns = array('soap'); + var $uri = ''; + var $wsdl = null; + + var $status = ''; + var $element_stack = array(); + var $parentElement = ''; + + var $schema = ''; + var $schemaStatus = ''; + var $schema_stack = array(); + var $currentComplexType; + var $schema_element_stack = array(); + var $currentElement; + + /** + * constructor + */ + function SOAP_WSDL_Parser($uri, &$wsdl, $docs = false) + { + parent::SOAP_Base('WSDLPARSER'); + $this->cache =& new SOAP_WSDL_Cache($wsdl->cacheUse, $wsdl->cacheMaxAge); + $this->uri = $uri; + $this->wsdl = &$wsdl; + $this->docs = $docs; + $this->parse($uri); + } + + function parse($uri) + { + // Check whether content has been read. + $fd = $this->cache->get($uri, $this->wsdl->proxy); + if (PEAR::isError($fd)) { + return $this->_raiseSoapFault($fd); + } + + // Create an XML parser. + $parser = xml_parser_create(); + xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); + xml_set_object($parser, $this); + xml_set_element_handler($parser, 'startElement', 'endElement'); + if ($this->docs) { + xml_set_character_data_handler($parser, 'characterData'); + } + + if (!xml_parse($parser, $fd, true)) { + $detail = sprintf('XML error on line %d: %s', + xml_get_current_line_number($parser), + xml_error_string(xml_get_error_code($parser))); + return $this->_raiseSoapFault("Unable to parse WSDL file $uri\n$detail"); + } + xml_parser_free($parser); + return true; + } + + /** + * start-element handler + */ + function startElement($parser, $name, $attrs) + { + // Get element prefix. + $qname =& new QName($name); + if ($qname->ns) { + $ns = $qname->ns; + if ($ns && ((!$this->tns && strcasecmp($qname->name, 'definitions') == 0) || $ns == $this->tns)) { + $name = $qname->name; + } + } + $this->currentTag = $qname->name; + $this->parentElement = ''; + $stack_size = count($this->element_stack); + if ($stack_size) { + $this->parentElement = $this->element_stack[$stack_size - 1]; + } + $this->element_stack[] = $this->currentTag; + + // Find status, register data. + switch ($this->status) { + case 'types': + // sect 2.2 wsdl:types + // children: xsd:schema + $parent_tag = ''; + $stack_size = count($this->schema_stack); + if ($stack_size) { + $parent_tag = $this->schema_stack[$stack_size - 1]; + } + + switch ($qname->name) { + case 'schema': + // No parent should be in the stack. + if (!$parent_tag || $parent_tag == 'types') { + if (array_key_exists('targetNamespace', $attrs)) { + $this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']); + } else { + $this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns); + } + $this->wsdl->complexTypes[$this->schema] = array(); + $this->wsdl->elements[$this->schema] = array(); + } + break; + + case 'complexType': + if ($parent_tag == 'schema') { + $this->currentComplexType = $attrs['name']; + if (!isset($attrs['namespace'])) { + $attrs['namespace'] = $this->schema; + } + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType] = $attrs; + if (array_key_exists('base', $attrs)) { + $qn =& new QName($attrs['base']); + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name; + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $qn->ns; + } else { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct'; + } + $this->schemaStatus = 'complexType'; + } else { + $this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = true; + } + break; + + case 'element': + if (isset($attrs['type'])) { + $qn =& new QName($attrs['type']); + $attrs['type'] = $qn->name; + if ($qn->ns && array_key_exists($qn->ns, $this->wsdl->namespaces)) { + $attrs['namespace'] = $qn->ns; + } + } + + $parentElement = ''; + $stack_size = count($this->schema_element_stack); + if ($stack_size > 0) { + $parentElement = $this->schema_element_stack[$stack_size - 1]; + } + + if (isset($attrs['ref'])) { + $qn =& new QName($attrs['ref']); + $this->currentElement = $qn->name; + } else { + $this->currentElement = $attrs['name']; + } + $this->schema_element_stack[] = $this->currentElement; + if (!isset($attrs['namespace'])) { + $attrs['namespace'] = $this->schema; + } + + if ($parent_tag == 'schema') { + $this->wsdl->elements[$this->schema][$this->currentElement] = $attrs; + $this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = false; + $this->schemaStatus = 'element'; + } elseif ($this->currentComplexType) { + // we're inside a complexType + if ((isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order']) && + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] == 'sequence') + && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array') { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['arrayType'] = isset($attrs['type']) ? $attrs['type'] : null; + } + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement] = $attrs; + } else { + $this->wsdl->elements[$this->schema][$parentElement]['elements'][$this->currentElement] = $attrs; + } + break; + + case 'complexContent': + case 'simpleContent': + break; + + case 'extension': + case 'restriction': + if ($this->schemaStatus == 'complexType') { + if (!empty($attrs['base'])) { + $qn =& new QName($attrs['base']); + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name; + + // Types that extend from other types aren't + // *of* those types. Reflect this by denoting + // which type they extend. I'm leaving the + // 'type' setting here since I'm not sure what + // removing it might break at the moment. + if ($qname->name == 'extension') { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['extends'] = $qn->name; + } + } else { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct'; + } + } + break; + + case 'sequence': + if ($this->schemaStatus == 'complexType') { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name; + if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array'; + } + } + break; + + case 'all': + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name; + if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct'; + } + break; + + case 'choice': + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name; + if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array'; + } + + case 'attribute': + if ($this->schemaStatus == 'complexType') { + if (isset($attrs['name'])) { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['attribute'][$attrs['name']] = $attrs; + } else { + if (isset($attrs['ref'])) { + $q =& new QName($attrs['ref']); + foreach ($attrs as $k => $v) { + if ($k != 'ref' && strstr($k, $q->name)) { + $vq =& new QName($v); + if ($q->name == 'arrayType') { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name. $vq->arrayInfo; + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array'; + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $vq->ns; + } else { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name; + } + } + } + } + } + } + break; + } + + $this->schema_stack[] = $qname->name; + break; + + case 'message': + // sect 2.3 wsdl:message child wsdl:part + switch ($qname->name) { + case 'part': + $qn = null; + if (isset($attrs['type'])) { + $qn =& new QName($attrs['type']); + } elseif (isset($attrs['element'])) { + $qn =& new QName($attrs['element']); + } + if ($qn) { + $attrs['type'] = $qn->name; + $attrs['namespace'] = $qn->ns; + } + $this->wsdl->messages[$this->currentMessage][$attrs['name']] = $attrs; + // error in wsdl + + case 'documentation': + break; + + default: + break; + } + break; + + case 'portType': + // sect 2.4 + switch ($qname->name) { + case 'operation': + // attributes: name + // children: wsdl:input wsdl:output wsdl:fault + $this->currentOperation = $attrs['name']; + $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation] = $attrs; + break; + + case 'input': + case 'output': + case 'fault': + // wsdl:input wsdl:output wsdl:fault + // attributes: name message parameterOrder(optional) + if ($this->currentOperation) { + if (isset($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name])) { + $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = array_merge($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name], $attrs); + } else { + $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = $attrs; + } + if (array_key_exists('message', $attrs)) { + $qn =& new QName($attrs['message']); + $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['message'] = $qn->name; + $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['namespace'] = $qn->ns; + } + } + break; + + case 'documentation': + break; + + default: + break; + } + break; + + case 'binding': + $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL; + switch ($ns) { + case SCHEMA_SOAP: + // this deals with wsdl section 3 soap binding + switch ($qname->name) { + case 'binding': + // sect 3.3 + // soap:binding, attributes: transport(required), style(optional, default = document) + // if style is missing, it is assumed to be 'document' + if (!isset($attrs['style'])) { + $attrs['style'] = 'document'; + } + $this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding], $attrs); + break; + + case 'operation': + // sect 3.4 + // soap:operation, attributes: soapAction(required), style(optional, default = soap:binding:style) + if (!isset($attrs['style'])) { + $attrs['style'] = $this->wsdl->bindings[$this->currentBinding]['style']; + } + if (isset($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation])) { + $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = array_merge($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation], $attrs); + } else { + $this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = $attrs; + } + break; + + case 'body': + // sect 3.5 + // soap:body attributes: + // part - optional. listed parts must appear in body, missing means all parts appear in body + // use - required. encoded|literal + // encodingStyle - optional. space seperated list of encodings (uri's) + $this->wsdl->bindings[$this->currentBinding] + ['operations'][$this->currentOperation][$this->opStatus] = $attrs; + break; + + case 'fault': + // sect 3.6 + // soap:fault attributes: name use encodingStyle namespace + $this->wsdl->bindings[$this->currentBinding] + ['operations'][$this->currentOperation][$this->opStatus] = $attrs; + break; + + case 'header': + // sect 3.7 + // soap:header attributes: message part use encodingStyle namespace + $this->wsdl->bindings[$this->currentBinding] + ['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; + break; + + case 'headerfault': + // sect 3.7 + // soap:header attributes: message part use encodingStyle namespace + $header = count($this->wsdl->bindings[$this->currentBinding] + ['operations'][$this->currentOperation][$this->opStatus]['headers'])-1; + $this->wsdl->bindings[$this->currentBinding] + ['operations'][$this->currentOperation][$this->opStatus]['headers'][$header]['fault'] = $attrs; + break; + + case 'documentation': + break; + + default: + // error! not a valid element inside binding + break; + } + break; + + case SCHEMA_WSDL: + // XXX verify correct namespace + // for now, default is the 'wsdl' namespace + // other possible namespaces include smtp, http, etc. for alternate bindings + switch ($qname->name) { + case 'operation': + // sect 2.5 + // wsdl:operation attributes: name + $this->currentOperation = $attrs['name']; + break; + + case 'output': + case 'input': + case 'fault': + // sect 2.5 + // wsdl:input attributes: name + $this->opStatus = $qname->name; + break; + + case 'documentation': + break; + + default: + break; + } + break; + + case SCHEMA_WSDL_HTTP: + switch ($qname->name) { + case 'binding': + // sect 4.4 + // http:binding attributes: verb + // parent: wsdl:binding + $this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding], $attrs); + break; + + case 'operation': + // sect 4.5 + // http:operation attributes: location + // parent: wsdl:operation + $this->wsdl->bindings[$this->currentBinding]['operations'] + [$this->currentOperation] = $attrs; + break; + + case 'urlEncoded': + // sect 4.6 + // http:urlEncoded attributes: location + // parent: wsdl:input wsdl:output etc. + $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus] + [$this->currentOperation]['uri'] = 'urlEncoded'; + break; + + case 'urlReplacement': + // sect 4.7 + // http:urlReplacement attributes: location + // parent: wsdl:input wsdl:output etc. + $this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus] + [$this->currentOperation]['uri'] = 'urlReplacement'; + break; + + case 'documentation': + break; + + default: + // error + break; + } + + case SCHEMA_MIME: + // sect 5 + // all mime parts are children of wsdl:input, wsdl:output, etc. + // unsuported as of yet + switch ($qname->name) { + case 'content': + // sect 5.3 mime:content + // + // part attribute only required if content is child of multipart related, + // it contains the name of the part + // type attribute contains the mime type + case 'multipartRelated': + // sect 5.4 mime:multipartRelated + case 'part': + case 'mimeXml': + // sect 5.6 mime:mimeXml + // + // + case 'documentation': + break; + + default: + // error + break; + } + + case SCHEMA_DIME: + // DIME is defined in: + // http://gotdotnet.com/team/xml_wsspecs/dime/WSDL-Extension-for-DIME.htm + // all DIME parts are children of wsdl:input, wsdl:output, etc. + // unsuported as of yet + switch ($qname->name) { + case 'message': + // sect 4.1 dime:message + // appears in binding section + $this->wsdl->bindings[$this->currentBinding]['dime'] = $attrs; + break; + + default: + break; + } + + default: + break; + } + break; + + case 'service': + $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL; + + switch ($qname->name) { + case 'port': + // sect 2.6 wsdl:port attributes: name binding + $this->currentPort = $attrs['name']; + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort] = $attrs; + // XXX hack to deal with binding namespaces + $qn =& new QName($attrs['binding']); + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['binding'] = $qn->name; + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['namespace'] = $qn->ns; + break; + + case 'address': + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['address'] = $attrs; + // what TYPE of port is it? SOAP or HTTP? + $ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL; + switch ($ns) { + case SCHEMA_WSDL_HTTP: + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='http'; + break; + + case SCHEMA_SOAP: + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap'; + break; + + default: + // Shouldn't happen, we'll assume SOAP. + $this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap'; + } + + break; + + case 'documentation': + break; + + default: + break; + } + } + + // Top level elements found under wsdl:definitions. + switch ($qname->name) { + case 'import': + // sect 2.1.1 wsdl:import attributes: namespace location + if ((isset($attrs['location']) || isset($attrs['schemaLocation'])) && + !isset($this->wsdl->imports[$attrs['namespace']])) { + $uri = isset($attrs['location']) ? $attrs['location'] : $attrs['schemaLocation']; + $location = @parse_url($uri); + if (!isset($location['scheme'])) { + $base = @parse_url($this->uri); + $uri = $this->mergeUrl($base, $uri); + } + + $this->wsdl->imports[$attrs['namespace']] = $attrs; + $import_parser_class = get_class($this); + $import_parser =& new $import_parser_class($uri, $this->wsdl, $this->docs); + if ($import_parser->fault) { + unset($this->wsdl->imports[$attrs['namespace']]); + return false; + } + $this->currentImport = $attrs['namespace']; + } + // Continue on to the 'types' case - lack of break; is + // intentional. + + case 'types': + // sect 2.2 wsdl:types + $this->status = 'types'; + break; + + case 'schema': + // We can hit this at the top level if we've been asked to + // import an XSD file. + if (!empty($attrs['targetNamespace'])) { + $this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']); + } else { + $this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns); + } + $this->wsdl->complexTypes[$this->schema] = array(); + $this->wsdl->elements[$this->schema] = array(); + $this->schema_stack[] = $qname->name; + $this->status = 'types'; + break; + + case 'message': + // sect 2.3 wsdl:message attributes: name children:wsdl:part + $this->status = 'message'; + if (isset($attrs['name'])) { + $this->currentMessage = $attrs['name']; + $this->wsdl->messages[$this->currentMessage] = array(); + } + break; + + case 'portType': + // sect 2.4 wsdl:portType + // attributes: name + // children: wsdl:operation + $this->status = 'portType'; + $this->currentPortType = $attrs['name']; + $this->wsdl->portTypes[$this->currentPortType] = array(); + break; + + case 'binding': + // sect 2.5 wsdl:binding attributes: name type + // children: wsdl:operation soap:binding http:binding + if ($qname->ns && $qname->ns != $this->tns) { + break; + } + $this->status = 'binding'; + $this->currentBinding = $attrs['name']; + $qn =& new QName($attrs['type']); + $this->wsdl->bindings[$this->currentBinding]['type'] = $qn->name; + $this->wsdl->bindings[$this->currentBinding]['namespace'] = $qn->ns; + break; + + case 'service': + // sect 2.7 wsdl:service attributes: name children: ports + $this->currentService = $attrs['name']; + $this->wsdl->services[$this->currentService]['ports'] = array(); + $this->status = 'service'; + break; + + case 'definitions': + // sec 2.1 wsdl:definitions + // attributes: name targetNamespace xmlns:* + // children: wsdl:import wsdl:types wsdl:message wsdl:portType wsdl:binding wsdl:service + $this->wsdl->definition = $attrs; + foreach ($attrs as $key => $value) { + if (strstr($key, 'xmlns:') !== false) { + $qn =& new QName($key); + // XXX need to refactor ns handling. + $this->wsdl->namespaces[$qn->name] = $value; + $this->wsdl->ns[$value] = $qn->name; + if ($key == 'targetNamespace' || + strcasecmp($value,SOAP_SCHEMA) == 0) { + $this->soapns[] = $qn->name; + } else { + if (in_array($value, $this->_XMLSchema)) { + $this->wsdl->xsd = $value; + } + } + } + } + if (isset($ns) && $ns) { + $namespace = 'xmlns:' . $ns; + if (!$this->wsdl->definition[$namespace]) { + return $this->_raiseSoapFault("parse error, no namespace for $namespace", $this->uri); + } + $this->tns = $ns; + } + break; + } + } + + /** + * end-element handler. + */ + function endElement($parser, $name) + { + $stacksize = count($this->element_stack); + if ($stacksize) { + if ($this->element_stack[$stacksize - 1] == 'definitions') { + $this->status = ''; + } + array_pop($this->element_stack); + } + + if (stristr($name, 'schema')) { + array_pop($this->schema_stack); + $this->schema = ''; + } + + if ($this->schema) { + array_pop($this->schema_stack); + if (count($this->schema_stack) <= 1) { + /* Correct the type for sequences with multiple + * elements. */ + if (isset($this->currentComplexType) && isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type']) + && $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array' + && array_key_exists('elements', $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]) + && count($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements']) > 1) { + $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct'; + } + } + if (stristr($name, 'complexType')) { + $this->currentComplexType = ''; + if (count($this->schema_element_stack)) { + $this->currentElement = array_pop($this->schema_element_stack); + } else { + $this->currentElement = ''; + } + } elseif (stristr($name, 'element')) { + if (count($this->schema_element_stack)) { + $this->currentElement = array_pop($this->schema_element_stack); + } else { + $this->currentElement = ''; + } + } + } + } + + /** + * Element content handler. + */ + function characterData($parser, $data) + { + // Store the documentation in the WSDL file. + if ($this->currentTag == 'documentation') { + $data = trim(preg_replace('/\s+/', ' ', $data)); + if (!strlen($data)) { + return; + } + + switch ($this->status) { + case 'service': + $ptr =& $this->wsdl->services[$this->currentService]; + break; + + case 'portType': + $ptr =& $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation]; + break; + + case 'binding': + $ptr =& $this->wsdl->bindings[$this->currentBinding]; + break; + + case 'message': + $ptr =& $this->wsdl->messages[$this->currentMessage]; + break; + + case 'operation': + break; + + case 'types': + if (isset($this->currentComplexType) && + isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) { + if ($this->currentElement) { + $ptr =& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement]; + } else { + $ptr =& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]; + } + } + break; + } + + if (isset($ptr)) { + if (!isset($ptr['documentation'])) { + $ptr['documentation'] = ''; + } else { + $ptr['documentation'] .= ' '; + } + $ptr['documentation'] .= $data; + } + } + } + + /** + * $parsed is an array returned by parse_url(). + * + * @access private + */ + function mergeUrl($parsed, $path) + { + if (!is_array($parsed)) { + return false; + } + + $uri = ''; + if (!empty($parsed['scheme'])) { + $sep = (strtolower($parsed['scheme']) == 'mailto' ? ':' : '://'); + $uri = $parsed['scheme'] . $sep; + } + + if (isset($parsed['pass'])) { + $uri .= "$parsed[user]:$parsed[pass]@"; + } elseif (isset($parsed['user'])) { + $uri .= "$parsed[user]@"; + } + + if (isset($parsed['host'])) { + $uri .= $parsed['host']; + } + if (isset($parsed['port'])) { + $uri .= ":$parsed[port]"; + } + if ($path[0] != '/' && isset($parsed['path'])) { + if ($parsed['path'][strlen($parsed['path']) - 1] != '/') { + $path = dirname($parsed['path']) . '/' . $path; + } else { + $path = $parsed['path'] . $path; + } + $path = $this->_normalize($path); + } + $sep = $path[0] == '/' ? '' : '/'; + $uri .= $sep . $path; + + return $uri; + } + + function _normalize($path_str) + { + $pwd = ''; + $strArr = preg_split('/(\/)/', $path_str, -1, PREG_SPLIT_NO_EMPTY); + $pwdArr = ''; + $j = 0; + for ($i = 0; $i < count($strArr); $i++) { + if ($strArr[$i] != ' ..') { + if ($strArr[$i] != ' .') { + $pwdArr[$j] = $strArr[$i]; + $j++; + } + } else { + array_pop($pwdArr); + $j--; + } + } + $pStr = implode('/', $pwdArr); + $pwd = (strlen($pStr) > 0) ? ('/' . $pStr) : '/'; + return $pwd; + } + +} + +/** + * Parses the types and methods used in web service objects into the internal + * data structures used by SOAP_WSDL. + * + * Assumes the SOAP_WSDL class is unpopulated to start with. + * + * @author Chris Coe + */ +class SOAP_WSDL_ObjectParser extends SOAP_Base +{ + /** + * Target namespace for the WSDL document will have the following + * prefix. + */ + var $tnsPrefix = 'tns'; + + /** + * Reference to the SOAP_WSDL object to populate. + */ + var $wsdl = null; + + /** Constructor + * + * @param $objects Reference to the object or array of objects to parse + * @param $wsdl Reference to the SOAP_WSDL object to populate + * @param $targetNamespace The target namespace of schema types etc. + * @param $service_name Name of the WSDL + * @param $service_desc Optional description of the WSDL + */ + function SOAP_WSDL_ObjectParser(&$objects, &$wsdl, $targetNamespace, $service_name, $service_desc = '') + { + parent::SOAP_Base('WSDLOBJECTPARSER'); + + $this->wsdl = &$wsdl; + + // Set up the SOAP_WSDL object + $this->_initialise($service_name); + + // Parse each web service object + $wsdl_ref = (is_array($objects)? $objects : array(&$objects)); + + foreach ($wsdl_ref as $ref_item) { + if (!is_object($ref_item)) + return $this->_raiseSoapFault('Invalid web service object passed to object parser', 'urn:' . get_class($object)); + + if ($this->_parse($ref_item, $targetNamespace, $service_name) != true) + break; + } + + // Build bindings from abstract data. + if ($this->fault == null) { + $this->_generateBindingsAndServices($targetNamespace, $service_name, $service_desc); + } + } + + /** + * Initialise the SOAP_WSDL tree (destructive). + * + * If the object has already been initialised, the only effect + * will be to change the tns namespace to the new service name. + * + * @param $service_name Name of the WSDL + * @access private + */ + function _initialise($service_name) + { + // Set up the basic namespaces that all WSDL definitions use. + $this->wsdl->namespaces['wsdl'] = SCHEMA_WSDL; // WSDL language + $this->wsdl->namespaces['soap'] = SCHEMA_SOAP; // WSDL SOAP bindings + $this->wsdl->namespaces[$this->tnsPrefix] = 'urn:' . $service_name; // Target namespace + $this->wsdl->namespaces['xsd'] = array_search('xsd', $this->_namespaces); // XML Schema + $this->wsdl->namespaces['SOAP-ENC'] = array_search('SOAP-ENC', $this->_namespaces); // SOAP types + + // XXX Refactor $namespace/$ns for Shane :-) + unset($this->wsdl->ns['urn:' . $service_name]); + $this->wsdl->ns += array_flip($this->wsdl->namespaces); + + // Imports are not implemented in WSDL generation from classes. + // *** *** + } + + /** + * Parser - takes a single object to add to tree + * (non-destructive). + * + * @param $object Reference to the object to parse + * @param $service_name Name of the WSDL + * @access private + */ + function _parse(&$object, $schemaNamespace, $service_name) + { + // Create namespace prefix for the schema + // XXX not very elegant :-( + + list($schPrefix, $foo) = $this->_getTypeNs('{' . $schemaNamespace.'}'); + unset($foo); + + // Parse all the types defined by the object in whatever + // schema language we are using (currently __typedef arrays) + // *** *** + + foreach ($object->__typedef as $typeName => $typeValue) { + // Get/create namespace definition + + list($nsPrefix, $typeName) = $this->_getTypeNs($typeName); + + // Create type definition + + $this->wsdl->complexTypes[$schPrefix][$typeName] = array('name' => $typeName); + $thisType =& $this->wsdl->complexTypes[$schPrefix][$typeName]; + + // According to Dmitri's documentation, __typedef comes in two + // flavors: + // Array = array(array("item" => "value")) + // Struct = array("item1" => "value1", "item2" => "value2", ...) + + if (is_array($typeValue)) { + if (is_array(current($typeValue)) && count($typeValue) == 1 + && count(current($typeValue)) == 1) { + // It's an array + + $thisType['type'] = 'Array'; + list($nsPrefix, $typeName) = $this->_getTypeNs(current(current($typeValue))); + $thisType['namespace'] = $nsPrefix; + $thisType['arrayType'] = $typeName . '[]'; + } elseif (!is_array(current($typeValue))) { + // It's a struct + + $thisType['type'] = 'Struct'; + $thisType['order'] = 'all'; + $thisType['namespace'] = $nsPrefix; + $thisType['elements'] = array(); + + foreach ($typeValue as $elementName => $elementType) { + list($nsPrefix, $typeName) = $this->_getTypeNs($elementType); + $thisType['elements'][$elementName]['name'] = $elementName; + $thisType['elements'][$elementName]['type'] = $typeName; + $thisType['elements'][$elementName]['namespace'] = $nsPrefix; + } + } else { + // It's erroneous + return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object)); + } + } else { + // It's erroneous + return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object)); + } + } + + // Create an empty element array with the target namespace + // prefix, to match the results of WSDL parsing. + + $this->wsdl->elements[$schPrefix] = array(); + + // Populate tree with message information + // *** *** + + foreach ($object->__dispatch_map as $operationName => $messages) { + foreach ($messages as $messageType => $messageParts) { + unset($thisMessage); + + switch ($messageType) { + case 'in': + $this->wsdl->messages[$operationName . 'Request'] = array(); + $thisMessage =& $this->wsdl->messages[$operationName . 'Request']; + break; + + case 'out': + $this->wsdl->messages[$operationName . 'Response'] = array(); + $thisMessage =& $this->wsdl->messages[$operationName . 'Response']; + break; + + case 'alias': + // Do nothing + break; + + default: + // Error condition + break; + } + + if (isset($thisMessage)) { + foreach ($messageParts as $partName => $partType) { + list ($nsPrefix, $typeName) = $this->_getTypeNs($partType); + + $thisMessage[$partName] = array( + 'name' => $partName, + 'type' => $typeName, + 'namespace' => $nsPrefix + ); + } + } + } + } + + // Populate tree with portType information + // XXX Current implementation only supports one portType that + // encompasses all of the operations available. + // *** *** + + if (!isset($this->wsdl->portTypes[$service_name . 'Port'])) { + $this->wsdl->portTypes[$service_name . 'Port'] = array(); + } + $thisPortType =& $this->wsdl->portTypes[$service_name . 'Port']; + + foreach ($object->__dispatch_map as $operationName => $messages) { + $thisPortType[$operationName] = array('name' => $operationName); + + foreach ($messages as $messageType => $messageParts) { + switch ($messageType) { + case 'in': + $thisPortType[$operationName]['input'] = array( + 'message' => $operationName . 'Request', + 'namespace' => $this->tnsPrefix); + break; + + case 'out': + $thisPortType[$operationName]['output'] = array( + 'message' => $operationName . 'Response', + 'namespace' => $this->tnsPrefix); + break; + } + } + } + + return true; + } + + /** + * Take all the abstract WSDL data and build concrete bindings and + * services (destructive). + * + * XXX Current implementation discards $service_desc. + * + * @param $schemaNamespace Namespace for types etc. + * @param $service_name Name of the WSDL + * @param $service_desc Optional description of the WSDL + * @access private + */ + function _generateBindingsAndServices($schemaNamespace, $service_name, $service_desc = '') + { + // Populate tree with bindings information + // XXX Current implementation only supports one binding that + // matches the single portType and all of its operations. + // XXX Is this the correct use of $schemaNamespace here? + // *** *** + + $this->wsdl->bindings[$service_name . 'Binding'] = array( + 'type' => $service_name . 'Port', + 'namespace' => $this->tnsPrefix, + 'style' => 'rpc', + 'transport' => SCHEMA_SOAP_HTTP, + 'operations' => array()); + $thisBinding =& $this->wsdl->bindings[$service_name . 'Binding']; + + foreach ($this->wsdl->portTypes[$service_name . 'Port'] as $operationName => $operationData) { + $thisBinding['operations'][$operationName] = array( + 'soapAction' => $schemaNamespace . '#' . $operationName, + 'style' => $thisBinding['style']); + + foreach (array('input', 'output') as $messageType) + if (isset($operationData[$messageType])) { + $thisBinding['operations'][$operationName][$messageType] = array( + 'use' => 'encoded', + 'namespace' => $schemaNamespace, + 'encodingStyle' => SOAP_SCHEMA_ENCODING); + } + } + + // Populate tree with service information + // XXX Current implementation supports one service which groups + // all of the ports together, one port per binding + // XXX What about https? + // *** *** + + $this->wsdl->services[$service_name . 'Service'] = array('ports' => array()); + $thisService =& $this->wsdl->services[$service_name . 'Service']['ports']; + + foreach ($this->wsdl->bindings as $bindingName => $bindingData) { + $thisService[$bindingData['type']] = array( + 'name' => $bindingData['type'], + 'binding' => $bindingName, + 'namespace' => $this->tnsPrefix, + 'address' => array('location' => + 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] . + (isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')), + 'type' => 'soap'); + } + + // Set service + $this->wsdl->set_service($service_name . 'Service'); + $this->wsdl->uri = $this->wsdl->namespaces[$this->tnsPrefix]; + + // Create WSDL definition + // *** *** + + $this->wsdl->definition = array( + 'name' => $service_name, + 'targetNamespace' => $this->wsdl->namespaces[$this->tnsPrefix], + 'xmlns' => SCHEMA_WSDL); + + foreach ($this->wsdl->namespaces as $nsPrefix => $namespace) { + $this->wsdl->definition['xmlns:' . $nsPrefix] = $namespace; + } + } + + /** + * This function is adapted from Dmitri V's implementation of + * DISCO/WSDL generation. It separates namespace from type name in + * a __typedef key and creates a new namespace entry in the WSDL + * structure if the namespace has not been used before. The + * namespace prefix and type name are returned. If no namespace is + * specified, xsd is assumed. + * + * We will not need this function anymore once __typedef is + * eliminated. + */ + function _getTypeNs($type) + { + preg_match_all("'\{(.*)\}'sm", $type, $m); + if (isset($m[1][0]) && $m[1][0] != '') { + if (!array_key_exists($m[1][0], $this->wsdl->ns)) { + $ns_pref = 'ns' . count($this->wsdl->namespaces); + $this->wsdl->ns[$m[1][0]] = $ns_pref; + $this->wsdl->namespaces[$ns_pref] = $m[1][0]; + } + $typens = $this->wsdl->ns[$m[1][0]]; + $type = ereg_replace($m[0][0], '', $type); + } else { + $typens = 'xsd'; + } + + return array($typens, $type); + } + +} diff --git a/thirdparty/pear/SOAP/example/attachment.php b/thirdparty/pear/SOAP/example/attachment.php new file mode 100644 index 0000000..16533b0 --- /dev/null +++ b/thirdparty/pear/SOAP/example/attachment.php @@ -0,0 +1,26 @@ +call('echoMimeAttachment',array($v), + array('attachments'=>'Mime', + 'namespace'=>'http://soapinterop.org/', + 'from'=>'user@domain.com', + 'host'=>'smtp.domain.com')); +print $client->wire."\n\n\n"; +print_r($resp); + +# calling with DIME +$resp = $client->call('echoMimeAttachment',array($v)); +# DIME has null spaces, change them so we can see the wire +$wire = str_replace("\0",'*',$client->wire); +print $wire."\n\n\n"; +print_r($resp); +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/client.php b/thirdparty/pear/SOAP/example/client.php new file mode 100644 index 0000000..06965ec --- /dev/null +++ b/thirdparty/pear/SOAP/example/client.php @@ -0,0 +1,101 @@ + Port to PEAR and more + * @copyright 2003-2005 The PHP Group + * @license http://www.php.net/license/2_02.txt PHP License 2.02 + * @link http://pear.php.net/package/SOAP + */ + +require 'SOAP/Client.php'; + +/** + * This client runs against the example server in SOAP/example/server.php. It + * does not use WSDL to run these requests, but that can be changed easily by + * simply adding '?wsdl' to the end of the url. + */ +$soapclient = new SOAP_Client('http://localhost/SOAP/example/server.php'); +// This namespace is the same as declared in server.php. +$options = array('namespace' => 'urn:SOAP_Example_Server', + 'trace' => 1); + +$ret = $soapclient->call('echoStringSimple', + $params = array('inputStringSimple' => 'this is a test string'), + $options); +// print $soapclient->__get_wire(); +print_r($ret); +echo "
\n"; + +$ret = $soapclient->call('echoString', + $params = array('inputString' => 'this is a test string'), + $options); +print_r($ret); +echo "
\n"; + +$ret = $soapclient->call('divide', + $params = array('dividend' => 22, 'divisor' => 7), + $options); +// print $soapclient->__get_wire(); +if (PEAR::isError($ret)) { + echo 'Error: ' . $ret->getMessage() . "
\n"; +} else { + echo 'Quotient is ' . $ret . "
\n"; +} + +$ret = $soapclient->call('divide', + $params = array('dividend' => 22, 'divisor' => 0), + $options); +if (PEAR::isError($ret)) { + echo 'Error: ' . $ret->getMessage() . "
\n"; +} else { + echo 'Quotient is ' . $ret . "
\n"; +} + + +// SOAPStruct is defined in the following file. +require_once 'example_types.php'; + +$struct = new SOAPStruct('test string', 123, 123.123); + +/* Send an object, get an object back. Tell the client to translate to classes + * we provide if possible. */ +$soapclient->_auto_translation = true; +/* You can explicitly set the translation for a specific + * class. auto_translation works for all cases, but opens ANY class in the + * script to be used as a data type, and may not be desireable. Both can be + * used on client or server. */ +$soapclient->__set_type_translation('{http://soapinterop.org/xsd}SOAPStruct', + 'SOAPStruct'); +$ret = $soapclient->call('echoStruct', + $p = array('inputStruct' => $struct->__to_soap()), + $options); +// print $soapclient->__get_wire(); +print_r($ret); + +/** + * PHP doesn't support multiple OUT parameters in function calls, so we must + * do a little work to make it happen here. This requires knowledge on the + * developers part to figure out how they want to deal with it. + */ +$ret = $soapclient->call('echoStructAsSimpleTypes', + $p = array('inputStruct' => $struct->__to_soap()), + $options); +if (PEAR::isError($ret)) { + echo 'Error: ' . $ret->getMessage() . "
\n"; +} else { + list($string, $int, $float) = array_values($ret); + echo "varString: $string
\nvarInt: $int
\nvarFloat: $float
\n"; +} diff --git a/thirdparty/pear/SOAP/example/com_client.php b/thirdparty/pear/SOAP/example/com_client.php new file mode 100644 index 0000000..d511f0a --- /dev/null +++ b/thirdparty/pear/SOAP/example/com_client.php @@ -0,0 +1,57 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: com_client.php,v 1.3 2005/03/10 23:16:40 yunosh Exp $ +// +// SOAPStruct is defined in the following file +require_once 'example_types.php'; + +/* just a simple example of using MS SOAP on win32 as a client + to the php server. */ + +//load COM SOAP client object +$soapclient = new COM("MSSOAP.SoapClient30"); + +//connect to web service +$soapclient->mssoapinit("http://localhost/SOAP/example/server.php?wsdl"); + +//obtain result from web service method +$ret = $soapclient->echoString("This is a test!"); +print("$ret\n"); + +$ret = $soapclient->echoStringSimple("This is another test!"); +print("$ret\n"); + +# the following causes an exception in the COM extension + +#$ret = $soapclient->divide(22,7); +#print $soapclient->faultcode; +#print $soapclient->faultstring; +#print("22/7=$ret\n"); +#print_r($ret); +#$ret = $soapclient->divide(22,0); +#print("22/0=$ret\n"); + +#$struct = new SOAPStruct('test string',123,123.123); +#$ret = $soapclient->echoStruct($struct); +#print_r($ret); + +#$ret = $soapclient->echoStructAsSimpleTypes($struct); +#print_r($ret); + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/disco_server.php b/thirdparty/pear/SOAP/example/disco_server.php new file mode 100644 index 0000000..6dc8581 --- /dev/null +++ b/thirdparty/pear/SOAP/example/disco_server.php @@ -0,0 +1,238 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: disco_server.php,v 1.5 2005/03/10 23:16:40 yunosh Exp $ + +/* + This example shows how to mark up a server object so that + wsdl files may be dynamicaly generated by the soap + server. This also provides access to a generated DISCO document. + The fact that this example has an MP3 class is in no way + related to DISCO. ;) + + DISCO: http://msdn.microsoft.com/msdnmag/issues/02/02/xml/default.aspx + + A url accessing this server would look like: + + http://localhost/disco_server.php?wsdl (generate WSDL file) + http://localhost/disco_server.php (GET request generates DISCO) + http://localhost/disco_server.php (POST for normal soap requests) +*/ + +error_reporting(E_ALL); +require_once 'SOAP/Server.php'; + +class MP3DB_Class { + var $__dispatch_map = array(); + var $__typedef = array(); + + function MP3DB_Class () { + /** + * the only way to describe all methods in WSDL (messages, + * PortType-operations and bindings) is to use __dispatch_map + * to describe every method (even methods using simple data + * types in 'in' and 'out' parameters...) + */ + + $this->__dispatch_map['SayHallo'] = + array( + 'in' => array('input' => 'string'), + 'out' => array('return' => 'string') + ); + + $this->__dispatch_map['SayThisNTimes'] = + array( + 'in' => array('SayThis'=>'string','NTimes' => 'int'), + 'out' => array('return' => '{urn:MP3DB}ArrayOfStrings') + ); + + $this->__dispatch_map['GetMP3Tracks'] = + array( + 'in' => array('query' => 'string'), + 'out' => array('return' => '{urn:MP3DB}GetMP3TracksResult') + ); + + $this->__dispatch_map['AddMP3Track'] = + array( + 'in' => array('MP3Track' => '{urn:MP3DB}MP3Track'), + 'out' => array('return' => '{urn:MP3DB}AddMP3TrackResult') + ); + + /** + * I use __typedef to describe userdefined Types in WSDL. + * Structs and one-dimensional arrays are supported: + * Struct example: $this->__typedef['TypeName'] = array('VarName' => 'xsdType', ... ); + * or $this->__typedef['TypeName'] = array('VarName' => '{namespace}SomeOtherType'); + * Array example: $this->__typedef['TypeName'] = array(array('item' => 'xsdType')); + * or $this->__typedef['TypeName'] = array(array('item' => '{namespace}SomeOtherType')); + */ + + /** + * Struct 'MP3Track' + */ + $this->__typedef['MP3Track'] = + array( + 'Title' => 'string', + 'Artist' => 'string', + 'Album' => 'string', + 'Year' => 'int', + 'Genre' => 'int', + 'Comment' => 'string', + 'Composer' => 'string', + 'Orig_Artist' => 'string', + 'URL' => 'string', + 'Encoded_by' => 'string' + ); + + + + /** + * MP3TracksArray - array of 'MP3Track' structs + */ + $this->__typedef['MP3TracksArray'] = + array( + array( + 'item' => '{urn:MP3DB}MP3Track' + ) + ); + + /** + * Struct 'MethodDebug' + */ + $this->__typedef['MethodDebug'] = + array( + 'rc' => 'boolean', + 'ErrNo' => 'int', + 'Error' => 'string' + ); + + /** + * return Struct of method GetMP3Tracks + */ + $this->__typedef['GetMP3TracksResult'] = + array( + 'MethodDebug' => '{urn:MP3DB}MethodDebug', + 'MP3Tracks' => '{urn:MP3DB}MP3TracksArray' + ); + + /** + * return Struct of method AddMP3Track + */ + $this->__typedef['AddMP3TrackResult'] = + array( + 'MethodDebug' => '{urn:MP3DB}MethodDebug' + ); + + /** + * Array of strings + */ + $this->__typedef['ArrayOfStrings'] = + array( + array('item'=>'string') + ); + + } + + + function SayHallo($name) { + return "Hallo, " . $name; + } + + + function SayThisNTimes($SayThis,$NTimes) { + for ($i = 0; $i < $NTimes; $i++) { + $return[$i] = $SayThis . " $i"; + } + return new SOAP_Value('return','{urn:MP3DB}ArrayOfStrings',$return); + } + + + function GetMP3Tracks($query = "") { + for($i = 0; $i < 5; $i++) { + $this->MP3Tracks[$i] = new SOAP_Value( + 'item', + '{urn:MP3DB}MP3Track', + array( + "Title" => new SOAP_Value("Title","string","some track $i"), + "Artist" => new SOAP_Value("Artist","string","some artist $i"), + "Album" => new SOAP_Value("Album","string","some album $i"), + "Year" => new SOAP_Value("Year","int",(integer)1999), + "Genre" => new SOAP_Value("Genre","int",(integer)100), + "Comment" => new SOAP_Value("Comment","string","blabla $i"), + "Composer" => new SOAP_Value("Composer","string",""), + "Orig_Artist" => new SOAP_Value("Orig_Artist","string",""), + "URL" => new SOAP_Value("URL","string",""), + "Encoded_by" => new SOAP_Value("Encoded_by","string","") + ) + ); + } + + $MethodDebug["rc"] = new SOAP_Value("rc","boolean",true); + $MethodDebug["ErrNo"] = new SOAP_Value("ErrNo","int",(integer)0); + $MethodDebug["Error"] = new SOAP_Value("Error","string",""); + + return new SOAP_Value('return','{urn:MP3DB}GetMP3TracksResult',array( + "MethodDebug" => new SOAP_Value('MethodDebug','{urn:MP3DB}MethodDebug',$MethodDebug), + "MP3Tracks" => new SOAP_Value('MP3Tracks','{urn:MP3DB}MP3TracksArray',$this->MP3Tracks) + ) + ); + } + + + function AddMP3Track($MP3Track) { + # well, lets imagine here some code for adding given mp3track to db or whatever... + $MethodDebug["rc"] = new SOAP_Value("rc","boolean",true); + $MethodDebug["ErrNo"] = new SOAP_Value("ErrNo","int",(integer)0); + $MethodDebug["Error"] = new SOAP_Value("Error","string",""); + + return new SOAP_Value('return','{urn:MP3DB}AddMP3TrackResult',array( + "MethodDebug" => new SOAP_Value('MethodDebug','{urn:MP3DB}MethodDebug',$MethodDebug) + ) + ); + } + + + function __dispatch($methodname) { + if (isset($this->__dispatch_map[$methodname])) + return $this->__dispatch_map[$methodname]; + return NULL; + } +} + +$server = new SOAP_Server; +$server->_auto_translation = true; +$MP3DB_Class = new MP3DB_Class(); +$server->addObjectMap($MP3DB_Class,'urn:MP3DB'); + + +if (isset($_SERVER['REQUEST_METHOD']) && + $_SERVER['REQUEST_METHOD']=='POST') { + $server->service($HTTP_RAW_POST_DATA); +} else { + require_once 'SOAP/Disco.php'; + $disco = new SOAP_DISCO_Server($server,"MP3DB"); + header("Content-type: text/xml"); + if (isset($_SERVER['QUERY_STRING']) && + strcasecmp($_SERVER['QUERY_STRING'],'wsdl')==0) { + echo $disco->getWSDL(); + } else { + echo $disco->getDISCO(); + } + exit; +} +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/email_client.php b/thirdparty/pear/SOAP/example/email_client.php new file mode 100644 index 0000000..40d0d18 --- /dev/null +++ b/thirdparty/pear/SOAP/example/email_client.php @@ -0,0 +1,50 @@ + Port to PEAR and more | +// +----------------------------------------------------------------------+ +// +// $Id: email_client.php,v 1.4 2005/03/10 23:16:40 yunosh Exp $ +// + +/* +This reads a message from stdin, and calls the soap server defined + +You can use this from qmail by creating a .qmail-soaptest file with: + | /usr/bin/php /path/to/email_server.php +*/ + +# include the email server class +require_once 'SOAP/Server/Email.php'; + +$server = new SOAP_Server_Email; + +# read stdin +$fin = fopen('php://stdin','rb'); +if (!$fin) exit(0); + +$email = ''; +while (!feof($fin) && $data = fread($fin, 8096)) { + $email .= $data; +} + +fclose($fin); + + +$response = $server->client($email); + +print_r($response); + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/email_gateway.php b/thirdparty/pear/SOAP/example/email_gateway.php new file mode 100644 index 0000000..2e14a85 --- /dev/null +++ b/thirdparty/pear/SOAP/example/email_gateway.php @@ -0,0 +1,48 @@ + Port to PEAR and more | +// +----------------------------------------------------------------------+ +// +// $Id: email_gateway.php,v 1.5 2005/03/10 23:16:40 yunosh Exp $ +// + +/* +This reads a message from stdin, and passes the request to +a soap server residing on a web server, sends the response +out as an email + +You can use this from qmail by creating a .qmail-soapgateway file with: + | /usr/bin/php /path/to/email_server.php +*/ + +# include the email server class +require_once 'SOAP/Server/Email_Gateway.php'; + +# read stdin +$fin = fopen('php://stdin','rb'); +if (!$fin) exit(0); + +$email = ''; +while (!feof($fin) && $data = fread($fin, 8096)) { + $email .= $data; +} + +fclose($fin); + +# doit! +$server = new SOAP_Server_Email_Gateway(); +$server->service($data, 'http://localhost/soap/example/server.php'); +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/email_pop_gateway.php b/thirdparty/pear/SOAP/example/email_pop_gateway.php new file mode 100644 index 0000000..a998466 --- /dev/null +++ b/thirdparty/pear/SOAP/example/email_pop_gateway.php @@ -0,0 +1,70 @@ + Port to PEAR and more | +// +----------------------------------------------------------------------+ +// +// $Id: email_pop_gateway.php,v 1.6 2005/03/10 23:16:40 yunosh Exp $ +// + +/* include the Email server class, which knows how to + parse a standard email as a soap message */ + +require_once 'SOAP/Server/Email_Gateway.php'; + +/* include a class to access POP3 */ + +require_once 'Net/POP3.php'; + +/* create the SOAP Server object */ + +$server = new SOAP_Server_Email_Gateway('http://localhost/soap_interop/server_round2.php'); + +/* tell server to translate to classes we provide if possible */ +$server->_auto_translation = true; + +require_once 'example_server.php'; + +$soapclass = new SOAP_Example_Server(); +$server->addObjectMap($soapclass,'urn:SOAP_Example_Server'); + + +/* Connect to a POP3 server and read the messages */ + +$pop3 =& new Net_POP3(); +if ($pop3->connect('localhost', 110)) { + if ($pop3->login('username', 'password')) { + $listing = $pop3->getListing(); + + /* now loop through each message, and call the + SOAP server with that message */ + + foreach ($listing as $msg) { + + $email = $pop3->getMsg($msg['msg_id']); + + /* this is where we actually handle the SOAP + response. The SOAP::Server::Email class we + are using will send the SOAP response to + the sender via email. */ + + if ($email) $server->service($email); + + #$pop3->deleteMsg($msg['msg_id']); + } + } + $pop3->disconnect(); +} +?> diff --git a/thirdparty/pear/SOAP/example/email_pop_server.php b/thirdparty/pear/SOAP/example/email_pop_server.php new file mode 100644 index 0000000..2a12b56 --- /dev/null +++ b/thirdparty/pear/SOAP/example/email_pop_server.php @@ -0,0 +1,72 @@ + Port to PEAR and more | +// +----------------------------------------------------------------------+ +// +// $Id: email_pop_server.php,v 1.6 2005/03/10 23:16:40 yunosh Exp $ +// + +/* include the Email server class, which knows how to + parse a standard email as a soap message */ + +require_once 'SOAP/Server/Email.php'; + +/* include a class to access POP3 */ + +require_once 'Net/POP3.php'; + +/* create the SOAP Server object */ + +$server = new SOAP_Server_Email; + +/* tell server to translate to classes we provide if possible */ +$server->_auto_translation = true; + +require_once 'example_server.php'; + +$soapclass = new SOAP_Example_Server(); +$server->addObjectMap($soapclass,'urn:SOAP_Example_Server'); + + +/* Connect to a POP3 server and read the messages */ + +$pop3 =& new Net_POP3(); +if ($pop3->connect('localhost', 110)) { + if ($pop3->login('username', 'password')) { + $listing = $pop3->getListing(); + + /* now loop through each message, and call the + SOAP server with that message */ + + foreach ($listing as $msg) { + + $email = $pop3->getMsg($msg['msg_id']); + + /* this is where we actually handle the SOAP + response. The SOAP::Server::Email class we + are using will send the SOAP response to + the sender via email. */ + + if ($email) { + $server->client($email); + + $pop3->deleteMsg($msg['msg_id']); + } + } + } + $pop3->disconnect(); +} +?> diff --git a/thirdparty/pear/SOAP/example/email_server.php b/thirdparty/pear/SOAP/example/email_server.php new file mode 100644 index 0000000..f4477c4 --- /dev/null +++ b/thirdparty/pear/SOAP/example/email_server.php @@ -0,0 +1,56 @@ + Port to PEAR and more | +// +----------------------------------------------------------------------+ +// +// $Id: email_server.php,v 1.5 2005/03/10 23:16:40 yunosh Exp $ +// + +/* +This reads a message from stdin, and calls the soap server defined + +You can use this from qmail by creating a .qmail-soaptest file with: + | /usr/bin/php /path/to/email_server.php +*/ + +# include the email server class +require_once 'SOAP/Server/Email.php'; + +$server = new SOAP_Server_Email; + +/* tell server to translate to classes we provide if possible */ +$server->_auto_translation = true; + +require_once 'example_server.php'; + +$soapclass = new SOAP_Example_Server(); +$server->addObjectMap($soapclass,'urn:SOAP_Example_Server'); + +# read stdin +$fin = fopen('php://stdin','rb'); +if (!$fin) exit(0); + +$email = ''; +while (!feof($fin) && $data = fread($fin, 8096)) { + $email .= $data; +} + +fclose($fin); + +# doit! +$server->service($email); + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/example_server.php b/thirdparty/pear/SOAP/example/example_server.php new file mode 100644 index 0000000..7e59d49 --- /dev/null +++ b/thirdparty/pear/SOAP/example/example_server.php @@ -0,0 +1,162 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: example_server.php,v 1.5 2005/03/10 23:16:40 yunosh Exp $ +// + +// first, include the SOAP/Server class +require_once 'SOAP/Value.php'; +require_once 'SOAP/Fault.php'; + +// SOAPStruct is defined in the following file +require_once 'example_types.php'; + +// create a class for your soap functions +class SOAP_Example_Server { + /** + * The dispactch map does not need to be used, but aids + * the server class in knowing what parameters are used + * with the functions. This is the ONLY way to have + * multiple OUT parameters. If you use a dispatch map, you + * MUST add ALL functions you wish to allow be called. If + * you do not use a dispatch map, then any public function + * can be called from soap (in php4, we consider this to be + * any function in the class unless it starts with underscore, + * php5 support is not complete yet in this regard). + * if you do not define in/out parameters, the function can be + * called with parameters, but no validation on parameters will + * occure. + */ + var $__dispatch_map = array(); + + function SOAP_Example_Server() { + /** + * when generating wsdl for a server, you have to define + * any special complex types that you use (ie classes). + * using a namespace id before the type will create an + * xml schema with the targetNamespace for the type + * multiple types with the same namespace will appear + * in the same schema section. types with different + * namespaces will be in seperate schema sections. + * the following SOAPStruct typedef cooresponds to the + * SOAPStruct class above. + */ + $this->__typedef['{http://soapinterop.org/xsd}SOAPStruct'] = + array( + 'varString' => 'string', + 'varInt' => 'int', + 'varFloat' => 'float' + ); + + // an aliased function with multiple out parameters + $this->__dispatch_map['echoStructAsSimpleTypes'] = + array('in' => array('inputStruct' => '{http://soapinterop.org/xsd}SOAPStruct'), + 'out' => array('outputString' => 'string', 'outputInteger' => 'int', 'outputFloat' => 'float'), + 'alias' => 'myEchoStructAsSimpleTypes' + ); + $this->__dispatch_map['echoStringSimple'] = + array('in' => array('inputStringSimple' => 'string'), + 'out' => array('outputStringSimple' => 'string'), + ); + $this->__dispatch_map['echoString'] = + array('in' => array('inputString' => 'string'), + 'out' => array('outputString' => 'string'), + ); + $this->__dispatch_map['divide'] = + array('in' => array('dividend' => 'int', 'divisor' => 'int'), + 'out' => array('outputFloat' => 'float'), + ); + $this->__dispatch_map['echoStruct'] = + array('in' => array('inputStruct' => '{http://soapinterop.org/xsd}SOAPStruct'), + 'out' => array('outputStruct' => '{http://soapinterop.org/xsd}SOAPStruct'), + ); + + $this->__dispatch_map['echoMimeAttachment'] = array(); + } + + /* this private function is called on by SOAP_Server to determine any + special dispatch information that might be necessary. This, for example, + can be used to set up a dispatch map for functions that return multiple + OUT parameters */ + function __dispatch($methodname) { + if (isset($this->__dispatch_map[$methodname])) + return $this->__dispatch_map[$methodname]; + return NULL; + } + + // a simple echoString function + function echoStringSimple($inputString) + { + return $inputString; + } + + // an explicit echostring function + function echoString($inputString) + { + return new SOAP_Value('outputString','string',$inputString); + } + + function divide($dividend, $divisor) + { + // the soap server would normally catch errors like this + // and return a fault, but this is how you do it yourself. + if ($divisor == 0) + return new SOAP_Fault('You cannot divide by zero', 'Client'); + else + return $dividend / $divisor; + } + + function echoStruct($inputStruct) + { + return $inputStruct->__to_soap('outputStruct'); + #return new SOAP_Value('outputStruct','{http://soapinterop.org/xsd}SOAPStruct',$inputStruct); + } + + /** + * echoStructAsSimpleTypes + * takes a SOAPStruct as input, and returns each of its elements + * as OUT parameters + * + * this function is also aliased so you have to call it with + * echoStructAsSimpleTypes + * + * SOAPStruct is defined as: + * + * struct SOAPStruct: + * string varString + * integer varInt + * float varFloat + * + */ + function myEchoStructAsSimpleTypes($struct) + { + # convert a SOAPStruct to an array + return array( + new SOAP_Value('outputString','string',$struct->varString), + new SOAP_Value('outputInteger','int',$struct->varInt), + new SOAP_Value('outputFloat','float',$struct->varFloat) + ); + } + + function echoMimeAttachment($stuff) + { + return new SOAP_Attachment('return','application/octet-stream',NULL,$stuff); + } +} + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/example_types.php b/thirdparty/pear/SOAP/example/example_types.php new file mode 100644 index 0000000..fee55ac --- /dev/null +++ b/thirdparty/pear/SOAP/example/example_types.php @@ -0,0 +1,43 @@ +varString = $s; + $this->varInt = $i; + $this->varFloat = $f; + } + + function &__to_soap($name = 'inputStruct', $header = false, + $mustUnderstand = 0, + $actor = 'http://schemas.xmlsoap.org/soap/actor/next') + { + $inner[] =& new SOAP_Value('varString', 'string', $this->varString); + $inner[] =& new SOAP_Value('varInt', 'int', $this->varInt); + $inner[] =& new SOAP_Value('varFloat', 'float', $this->varFloat); + + if ($header) { + $value =& new SOAP_Header($name,'{http://soapinterop.org/xsd}SOAPStruct',$inner,$mustUnderstand,$actor); + } else { + $value =& new SOAP_Value($name,'{http://soapinterop.org/xsd}SOAPStruct',$inner); + } + + return $value; + } +} diff --git a/thirdparty/pear/SOAP/example/server.php b/thirdparty/pear/SOAP/example/server.php new file mode 100644 index 0000000..1990072 --- /dev/null +++ b/thirdparty/pear/SOAP/example/server.php @@ -0,0 +1,49 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: server.php,v 1.10 2005/03/10 23:16:40 yunosh Exp $ +// + +// first, include the SOAP/Server class +require_once 'SOAP/Server.php'; + +$server = new SOAP_Server; +/* tell server to translate to classes we provide if possible */ +$server->_auto_translation = true; + +require_once 'example_server.php'; + +$soapclass = new SOAP_Example_Server(); +$server->addObjectMap($soapclass,'urn:SOAP_Example_Server'); + +if (isset($_SERVER['REQUEST_METHOD']) && + $_SERVER['REQUEST_METHOD']=='POST') { + $server->service($HTTP_RAW_POST_DATA); +} else { + require_once 'SOAP/Disco.php'; + $disco = new SOAP_DISCO_Server($server,'ServerExample'); + header("Content-type: text/xml"); + if (isset($_SERVER['QUERY_STRING']) && + strcasecmp($_SERVER['QUERY_STRING'],'wsdl')==0) { + echo $disco->getWSDL(); + } else { + echo $disco->getDISCO(); + } + exit; +} +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/server2.php b/thirdparty/pear/SOAP/example/server2.php new file mode 100644 index 0000000..2d64446 --- /dev/null +++ b/thirdparty/pear/SOAP/example/server2.php @@ -0,0 +1,64 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: server2.php,v 1.3 2005/03/10 23:16:40 yunosh Exp $ +// + +// first, include the SOAP/Server class +require_once 'SOAP/Server.php'; + +$server = new SOAP_Server; +/* tell server to translate to classes we provide if possible */ +$server->_auto_translation = true; + +/* This is a simple example of implementing a custom + call handler. If you do this, the soap server will ignore + objects or functions added to it, and will call your handler + for **ALL** soap calls the server receives, wether the call + is defined in your WSDL or not. The handler receives two + arguments, the method name being called, and the arguments + sent for that call. +*/ +function myCallHandler($methodname, $args) +{ + global $soapclass; + return @call_user_func_array(array($soapclass, $methodname),$args); +} +$server->setCallHandler('myCallHandler',false); + +require_once 'example_server.php'; + +$soapclass = new SOAP_Example_Server(); +$server->addObjectMap($soapclass,'urn:SOAP_Example_Server'); + +if (isset($_SERVER['REQUEST_METHOD']) && + $_SERVER['REQUEST_METHOD']=='POST') { + $server->service($HTTP_RAW_POST_DATA); +} else { + require_once 'SOAP/Disco.php'; + $disco = new SOAP_DISCO_Server($server,'ServerExample'); + header("Content-type: text/xml"); + if (isset($_SERVER['QUERY_STRING']) && + strcasecmp($_SERVER['QUERY_STRING'],'wsdl')==0) { + echo $disco->getWSDL(); + } else { + echo $disco->getDISCO(); + } + exit; +} +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/smtp.php b/thirdparty/pear/SOAP/example/smtp.php new file mode 100644 index 0000000..a7814da --- /dev/null +++ b/thirdparty/pear/SOAP/example/smtp.php @@ -0,0 +1,32 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: smtp.php,v 1.5 2005/03/10 23:16:40 yunosh Exp $ +// +// include soap client class +include("SOAP/Client.php"); + +$soapclient = new SOAP_Client("mailto:user@domain.com"); +$options = array('namespace'=>'http://soapinterop.org/','from'=>'user@domain.com','host'=>'localhost'); +$return = $soapclient->call("echoString",array("inputString"=>"this is a test"), $options); +$return = $soapclient->call("echoStringArray",array('inputStringArray' => array('good','bad','ugly')), $options); +// don't expect much of a result! +print_r($return); +print "
\n".$soapclient->wire; +?> + diff --git a/thirdparty/pear/SOAP/example/stockquote.php b/thirdparty/pear/SOAP/example/stockquote.php new file mode 100644 index 0000000..0305032 --- /dev/null +++ b/thirdparty/pear/SOAP/example/stockquote.php @@ -0,0 +1,55 @@ + + Port to PEAR and more | +// | Authors: Dietrich Ayala Original Author | +// +----------------------------------------------------------------------+ +// +// $Id: stockquote.php,v 1.7 2005/03/10 23:16:40 yunosh Exp $ +// +// include soap client class +include("SOAP/Client.php"); + +print "
\nwsdl:"; +$wsdl = new SOAP_WSDL("http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl"); +$soapclient = $wsdl->getProxy(); +print_r($soapclient->getQuote("ibm")); +print "\n\n"; + +if (extension_loaded('overload')) { + print "\n
overloaded:"; + $ret = $soapclient->getQuote("ibm"); + print_r($ret); + print "\n\n"; +} +unset($soapclient); + +print "\n
non wsdl:"; +$soapclient = new SOAP_Client("http://services.xmethods.net:80/soap"); +$namespace = "urn:xmethods-delayed-quotes"; +/** + * some soap servers require a Soapaction http header. PEAR::SOAP does + * not use them in any way, other to send them if you supply them. + * soapaction is deprecated in later SOAP versions. + */ +$soapaction = "urn:xmethods-delayed-quotes#getQuote"; +$ret = $soapclient->call("getQuote",array("symbol"=>"ibm"),$namespace,$soapaction); +print_r($ret); +print "\n\n"; +unset($soapclient); + +?> + diff --git a/thirdparty/pear/SOAP/example/tcp_client.php b/thirdparty/pear/SOAP/example/tcp_client.php new file mode 100644 index 0000000..b3f04d7 --- /dev/null +++ b/thirdparty/pear/SOAP/example/tcp_client.php @@ -0,0 +1,44 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: tcp_client.php,v 1.3 2005/03/10 23:16:40 yunosh Exp $ +// + +require_once('SOAP/Client.php'); + +# client +$soapclient = new SOAP_Client("tcp://127.0.0.1:82"); + +# namespace +$options = array('namespace' => 'urn:SOAP_Example_Server', 'trace' => 1); + +# one +$params = array("string" => "this is string 1"); +$ret1 = $soapclient->call("echoString", $params, $options); +# echo "WIRE: \n".$soapclient->__get_wire(); +print_r($ret1); +echo "
\n"; + +# two +$params = array("string" => "this is string 2"); +$ret2 = $soapclient->call("echoString", $params, $options); +# echo "WIRE: \n".$soapclient->__get_wire(); +print_r($ret2); +echo "
\n"; + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/tcp_daemon.pl b/thirdparty/pear/SOAP/example/tcp_daemon.pl new file mode 100644 index 0000000..3633f4c --- /dev/null +++ b/thirdparty/pear/SOAP/example/tcp_daemon.pl @@ -0,0 +1,74 @@ +#!/usr/bin/perl -w +use strict; + +=head1 Simple SOAP TCP Server + + Simple SOAP TCP Server with test class (just to check things are working) + + Before you run this test server you will need some perl classes, namely: + SOAP::Lite + Hook::LexWrap (if you want to see some debugging) + + Flee off to the CPAN if you need them :) + + To run type 'perl ' and if you dont get any errors, it's time + to go write some code to connect. +=cut + +use SOAP::Transport::TCP qw(trace); +use Data::Dumper; + + +############# +## if you want to see incoming/outgoing raw xml +## uncomment the following. + +#use Hook::LexWrap; +#wrap *IO::SessionData::read, post => \&show_read; +#wrap *IO::SessionData::write, post => \&show_write; + +## +############# + + +my $daemon = SOAP::Transport::TCP::Server->new( + LocalAddr => '127.0.0.1', + LocalPort => '82', + Listen => 5, + Reuse => 1 +); + +# dispatch +$daemon->dispatch_to('SOAP_Example_Server'); +$daemon->handle; + +############# +## callback functions for Hook::LexWrap; +## + +# show incoming xml +sub show_read { + print $/,'## read ##',$/; + print Dumper($_[0]); +} + +# show outgoing xml +sub show_write { + print $/,'## write ##',$/; + print Dumper($_[0]); +} +################################################################################ + + + +################################################################################ +# SOAP_Example_Server +# Simple test class, method test returns double what you send to it, thats all! +################################################################################ +package SOAP_Example_Server; + +sub echoString { + return $_[1] x 2; +} + +1; diff --git a/thirdparty/pear/SOAP/example/tcp_server.php b/thirdparty/pear/SOAP/example/tcp_server.php new file mode 100644 index 0000000..41c8468 --- /dev/null +++ b/thirdparty/pear/SOAP/example/tcp_server.php @@ -0,0 +1,35 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: tcp_server.php,v 1.4 2005/03/10 23:16:40 yunosh Exp $ +// + +// first, include the SOAP/Server class +require_once 'SOAP/Server/TCP.php'; +set_time_limit(0); + +$server = new SOAP_Server_TCP("127.0.0.1",82); +/* tell server to translate to classes we provide if possible */ +$server->_auto_translation = true; + +require_once 'example_server.php'; + +$soapclass = new SOAP_Example_Server(); +$server->addObjectMap($soapclass,'urn:SOAP_Example_Server'); +$server->run(); +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/example/wsdl_client.php b/thirdparty/pear/SOAP/example/wsdl_client.php new file mode 100644 index 0000000..dc63a76 --- /dev/null +++ b/thirdparty/pear/SOAP/example/wsdl_client.php @@ -0,0 +1,83 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: wsdl_client.php,v 1.3 2005/03/10 23:16:40 yunosh Exp $ +// +include("SOAP/Client.php"); + +/** + * this client runs against the example server in SOAP/example/server.php + * it does not use WSDL to run these requests, but that can be changed easily by simply + * adding '?wsdl' to the end of the url. + */ +$wsdl = new SOAP_WSDL("http://localhost/SOAP/example/server.php?wsdl"); +$soapclient = $wsdl->getProxy(); + +$ret = $soapclient->echoStringSimple("this is a test string"); +#print $soapclient->__get_wire(); +print_r($ret);echo "
\n"; + +$ret = $soapclient->echoString("this is a test string"); +print_r($ret);echo "
\n"; + +$ret = $soapclient->divide(22,7); +# print $soapclient->__get_wire(); +if (PEAR::isError($ret)) + print("Error: " . $ret->getMessage() . "
\n"); +else + print("Quotient is " . $ret . "
\n"); + +$ret = $soapclient->divide(22,0); +if (PEAR::isError($ret)) + print("Error: " . $ret->getMessage() . "
\n"); +else + print("Quotient is " . $ret . "
\n"); + + +// SOAPStruct is defined in the following file +require_once 'example_types.php'; + +$struct = new SOAPStruct('test string',123,123.123); + +/* send an object, get an object back */ +/* tell client to translate to classes we provide if possible */ +$soapclient->_auto_translation = true; +/* or you can explicitly set the translation for + a specific class. auto_translation works for all cases, + but opens ANY class in the script to be used as a data type, + and may not be desireable. both can be used on client or + server */ +$soapclient->__set_type_translation('{http://soapinterop.org/xsd}SOAPStruct','SOAPStruct'); +$ret = $soapclient->echoStruct($struct->__to_soap()); +#print $soapclient->__get_wire(); +print_r($ret); + +/** + * PHP doesn't support multiple OUT parameters in function calls, so we + * must do a little work to make it happen here. This requires knowledge on the + * developers part to figure out how they want to deal with it. + */ +$ret = $soapclient->echoStructAsSimpleTypes($struct->__to_soap()); +if (PEAR::isError($ret)) { + print("Error: " . $ret->getMessage() . "
\n"); +} else { + list($string, $int, $float) = array_values($ret); +} +echo "varString: $string
\nvarInt: $int
\nvarFloat: $float
\n"; + +?> \ No newline at end of file diff --git a/thirdparty/pear/SOAP/tools/genproxy.php b/thirdparty/pear/SOAP/tools/genproxy.php new file mode 100644 index 0000000..8a334e1 --- /dev/null +++ b/thirdparty/pear/SOAP/tools/genproxy.php @@ -0,0 +1,21 @@ + foo.php + * + */ + +function do_wsdl($uri) { + $wsdl =& new SOAP_WSDL($uri); + print $wsdl->generateAllProxies(); +} +echo ""; +?> \ No newline at end of file