/lib/PEAR/SOAP/WSDL.php
PHP | 2294 lines | 1550 code | 241 blank | 503 comment | 340 complexity | 67394dd9431b6970eac9a32df6171f2a MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
Large files files are truncated, but you can click here to view the full file
- <?php
- /**
- * This file contains the code for dealing with WSDL access and services.
- *
- * PHP versions 4 and 5
- *
- * LICENSE: This source file is subject to version 2.02 of the PHP license,
- * that is bundled with this package in the file LICENSE, and is available at
- * through the world-wide-web at http://www.php.net/license/2_02.txt. If you
- * did not receive a copy of the PHP license and are unable to obtain it
- * through the world-wide-web, please send a note to license@php.net so we can
- * mail you a copy immediately.
- *
- * @category Web Services
- * @package SOAP
- * @author Dietrich Ayala <dietrich@ganx4.com> Original Author
- * @author Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more
- * @author Chuck Hagenbuch <chuck@horde.org> Maintenance
- * @author Jan Schneider <jan@horde.org> 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);
- /**
- * 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
- * - refactor namespace handling ($namespace/$ns)
- * - implement IDL type syntax declaration so we can generate WSDL
- *
- * @access public
- * @package SOAP
- * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
- * @author Dietrich Ayala <dietrich@ganx4.com> 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 = '';
- /**
- * URL to WSDL file.
- *
- * @var string
- */
- var $uri;
- /**
- * Parse documentation in the WSDL?
- *
- * @var boolean
- */
- var $docs;
- /**
- * Proxy parameters.
- *
- * @var array
- */
- var $proxy;
- /**
- * Enable tracing in the generated proxy class?
- *
- * @var boolean
- */
- var $trace = false;
- /**
- * Use WSDL cache?
- *
- * @var boolean
- */
- var $cacheUse;
- /**
- * WSDL cache directory.
- *
- * @var string
- */
- var $cacheDir;
- /**
- * Cache maximum lifetime (in seconds).
- *
- * @var integer
- */
- var $cacheMaxAge;
- /**
- * Class to use for WSDL parsing. Can be overridden for special cases,
- * subclasses, etc.
- *
- * @var string
- */
- var $wsdlParserClass = 'SOAP_WSDL_Parser';
- /**
- * Reserved PHP keywords.
- *
- * @link http://www.php.net/manual/en/reserved.php
- *
- * @var array
- */
- var $_reserved = array('abstract', 'and', 'array', 'as', 'break', 'case',
- 'catch', 'cfunction', 'class', 'clone', 'const',
- 'continue', 'declare', 'default', 'die', 'do',
- 'echo', 'else', 'elseif', 'empty', 'enddeclare',
- 'endfor', 'endforeach', 'endif', 'endswitch',
- 'endwhile', 'eval', 'exception', 'exit', 'extends',
- 'final', 'for', 'foreach', 'function', 'global',
- 'if', 'implements', 'include', 'include_once',
- 'interface', 'isset', 'list', 'new', 'old_function',
- 'or', 'php_user_filter', 'print', 'private',
- 'protected', 'public', 'require', 'require_once',
- 'return', 'static', 'switch', 'this', 'throw',
- 'try', 'unset', 'use', 'var', 'while', 'xor');
- /**
- * Regular expressions for invalid PHP labels.
- *
- * @link http://www.php.net/manual/en/language.variables.php.
- *
- * @var string
- */
- var $_invalid = array('/^[^a-zA-Z_\x7f-\xff]/', '/[^a-zA-Z0-9_\x7f-\xff]/');
- /**
- * SOAP_WSDL constructor.
- *
- * @param string $wsdl_uri URL to WSDL file.
- * @param array $proxy Options for HTTP_Request class
- * @see HTTP_Request.
- * @param boolean|string $cacheUse Use WSDL caching? The cache directory
- * if a string.
- * @param integer $cacheMaxAge Cache maximum lifetime (in seconds).
- * @param boolean $docs Parse documentation in the WSDL?
- *
- * @access public
- */
- function SOAP_WSDL($wsdl_uri = false,
- $proxy = array(),
- $cacheUse = false,
- $cacheMaxAge = WSDL_CACHE_MAX_AGE,
- $docs = false)
- {
- parent::SOAP_Base('WSDL');
- $this->uri = $wsdl_uri;
- $this->proxy = $proxy;
- $this->cacheUse = !empty($cacheUse);
- $this->cacheMaxAge = $cacheMaxAge;
- $this->docs = $docs;
- if (is_string($cacheUse)) {
- $this->cacheDir = $cacheUse;
- }
- if ($wsdl_uri) {
- if (!PEAR::isError($this->parseURL($wsdl_uri))) {
- reset($this->services);
- $this->service = key($this->services);
- }
- }
- }
- /**
- * @deprecated Use setService().
- */
- function set_service($service)
- {
- $this->setService($service);
- }
- /**
- * Sets the service currently to be used.
- *
- * @param string $service An (existing) service name.
- */
- function setService($service)
- {
- if (array_key_exists($service, $this->services)) {
- $this->service = $service;
- }
- }
- /**
- * Fills the WSDL array tree with data from a WSDL file.
- *
- * @param string $wsdl_uri URL to WSDL file.
- */
- function parseURL($wsdl_uri)
- {
- $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 $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])) {
- return null;
- }
- $nsp = $this->ns[$namespace];
- //if (!isset($this->elements[$nsp]))
- // $nsp = $this->namespaces[$nsp];
- if (!isset($this->elements[$nsp][$datatype])) {
- return null;
- }
- $checkmessages = array();
- // Find what messages use this datatype.
- foreach ($this->messages as $messagename => $message) {
- foreach ($message as $part) {
- if ($part['type'] == $datatype) {
- $checkmessages[] = $messagename;
- break;
- }
- }
- }
- // Find the operation that uses this message.
- foreach($this->portTypes as $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 = $this->_sanitize($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) {
- $_argname = $this->_sanitize($_argname);
- if ($opstyle == 'document' && $use == 'literal' &&
- $_argtype['name'] == 'parameters') {
- // The type or element refered to is used for
- // parameters.
- $elattrs = null;
- $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) {
- $elname = $this->_sanitize($elname);
- // 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 = $this->_sanitize($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' => true" : '') . "));\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 = $this->_sanitize($classname);
- if (!class_exists($classname)) {
- $proxy = $this->generateProxyCode($port, $classname);
- require_once 'SOAP/Client.php';
- eval($proxy);
- }
- $proxy = new $classname;
- return $proxy;
- }
- /**
- * Sanitizes a SOAP value, method or class name so that it can be used as
- * a valid PHP identifier. Invalid characters are converted into
- * underscores and reserved words are prefixed with an underscore.
- *
- * @param string $name The identifier to sanitize.
- *
- * @return string The sanitized identifier.
- */
- function _sanitize($name)
- {
- $name = preg_replace($this->_invalid, '_', $name);
- if (in_array($name, $this->_reserved)) {
- $name = '_' . $name;
- }
- return $name;
- }
- 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'];
- } elseif (isset($this->ns[$ns]) &&
- isset($this->elements[$this->ns[$ns]][$name]['complex']) &&
- $this->elements[$this->ns[$ns]][$name]['complex']) {
- // Type is not an element but complex.
- return $this->elements[$this->ns[$ns]][$name]['elements'][$child_name]['type'];
- }
- return null;
- }
- /**
- * @param QName $name A parameter name.
- * @param QName $type A parameter type.
- *
- * @return array A list of [type, array element type, array element
- * namespace, array length].
- */
- function getSchemaType($type, $name)
- {
- // 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 $types) {
- if (isset($types[$type->name])) {
- if (isset($types[$type->name]['type'])) {
- list($arraytype_ns, $arraytype, $array_depth) = isset($types[$type->name]['arrayType'])
- ? $this->_getDeepestArrayType($types[$type->name]['namespace'], $types[$type->name]['arrayType'])
- : array($this->namespaces[$types[$type->name]['namespace']], null, 0);
- return array($types[$type->name]['type'], $arraytype, $arraytype_ns, $array_depth);
- }
- if (isset($types[$type->name]['arrayType'])) {
- list($arraytype_ns, $arraytype, $array_depth) =
- $this->_getDeepestArrayType($types[$type->name]['namespace'], $types[$type->name]['arrayType']);
- return array('Array', $arraytype, $arraytype_ns, $array_depth);
- }
- if (!empty($types[$type->name]['elements'][$name->name])) {
- $type->name = $types[$type->name]['elements']['type'];
- return array($type->name, null, $this->namespaces[$types[$type->name]['namespace']], null);
- }
- break;
- }
- }
- }
- 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 && !empty($this->complexTypes[$p][$type->name])) {
- if ($arrayType = $this->complexTypes[$p][$type->name]['arrayType']) {
- $type->name = 'Array';
- } elseif ($this->complexTypes[$p][$type->name]['order'] == 'sequence' &&
- array_key_exists('elements', $this->complexTypes[$p][$type->name])) {
- reset($this->complexTypes[$p][$type->name]['elements']);
- // assume an array
- if (count($this->complexTypes[$p][$type->name]['elements']) == 1) {
- $arg = current($this->complexTypes[$p][$type->name]['elements']);
- $arrayType = $arg['type'];
- $type->name = 'Array';
- } else {
- foreach ($this->complexTypes[$p][$type->name]['elements'] as $element) {
- if ($element['name'] == $type->name) {
- $arrayType = $element['type'];
- $type->name = $element['type'];
- }
- }
- }
- } else {
- $type->name = 'Struct';
- }
- return array($type->name, $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
- {
- /**
- * Use WSDL cache?
- *
- * @var boolean
- */
- var $_cacheUse;
- /**
- * WSDL cache directory.
- *
- * @var string
- */
- var $_cacheDir;
- /**
- * Cache maximum lifetime (in seconds)
- *
- * @var integer
- */
- var $_cacheMaxAge;
- /**
- * Constructor.
- *
- * @param boolean $cashUse Use caching?
- * @param integer $cacheMaxAge Cache maximum lifetime (in seconds)
- */
- function SOAP_WSDL_Cache($cacheUse = false,
- $cacheMaxAge = WSDL_CACHE_MAX_AGE,
- $cacheDir = null)
- {
- parent::SOAP_Base('WSDLCACHE');
- $this->_cacheUse = $cacheUse;
- $this->_cacheDir = $cacheDir;
- $this->_cacheMaxAge = $cacheMaxAge;
- }
- /**
- * Returns the path to the cache and creates it, if it doesn't exist.
- *
- * @private
- *
- * @return string The directory to use for the cache.
- */
- function _cacheDir()
- {
- if (!empty($this->_cacheDir)) {
- $dir = $this->_cacheDir;
- } else {
- $dir = getenv('WSDLCACHE');
- if (empty($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 = $this->_cacheDir() . '/' . md5($wsdl_fname). ' .wsdl';
- if (file_exists($cachename) &&
- $file_data = file_get_contents($cachename)) {
- $md5_wsdl = md5($file_data);
- if ($cache) {
- if ($cache != $md5_wsdl) {
- return $this->_raiseSoapFault('WSDL Checksum error!', $wsdl_fname);
- }
- } else {
- $fi = stat($cachename);
- $cache_mtime = $fi[8];
- if ($cache_mtime + $this->_cacheMaxAge < time()) {
- // Expired, refetch.
- $md5_wsdl = '';
- }
- }
- }
- }
- // Not cached or not using cache. Retrieve WSDL from URL
- if (!$md5_wsdl) {
- // Is it a local file?
- if (strpos($wsdl_fname, 'file://') === 0) {
- $wsdl_fname = substr($wsdl_fname, 7);
- if (!file_exists($wsdl_fname)) {
- return $this->_raiseSoapFault('Unable to read local WSDL file', $wsdl_fname);
- }
- $file_data = file_get_contents($wsdl_fname);
- } elseif (!preg_match('|^https?://|', $wsdl_fname)) {
- return $this->_raiseSoapFault('Unknown schema of WSDL URL', $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,
- $wsdl->cacheDir);
- $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 == …
Large files files are truncated, but you can click here to view the full file