533 lines
17 KiB
PHP
533 lines
17 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Zend Framework
|
||
|
*
|
||
|
* LICENSE
|
||
|
*
|
||
|
* This source file is subject to the new BSD license that is bundled
|
||
|
* with this package in the file LICENSE.txt.
|
||
|
* It is also available through the world-wide-web at this URL:
|
||
|
* http://framework.zend.com/license/new-bsd
|
||
|
* If you did not receive a copy of the license and are unable to
|
||
|
* obtain it through the world-wide-web, please send an email
|
||
|
* to license@zend.com so we can send you a copy immediately.
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Soap
|
||
|
* @subpackage AutoDiscover
|
||
|
* @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
|
||
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
||
|
* @version $Id: AutoDiscover.php 16210 2009-06-21 19:22:17Z thomas $
|
||
|
*/
|
||
|
|
||
|
require_once 'Zend/Server/Interface.php';
|
||
|
require_once 'Zend/Soap/Wsdl.php';
|
||
|
require_once 'Zend/Server/Reflection.php';
|
||
|
require_once 'Zend/Server/Abstract.php';
|
||
|
require_once 'Zend/Uri.php';
|
||
|
|
||
|
/**
|
||
|
* Zend_Soap_AutoDiscover
|
||
|
*
|
||
|
* @category Zend
|
||
|
* @package Zend_Soap
|
||
|
* @subpackage AutoDiscover
|
||
|
*/
|
||
|
class Zend_Soap_AutoDiscover implements Zend_Server_Interface {
|
||
|
/**
|
||
|
* @var Zend_Soap_Wsdl
|
||
|
*/
|
||
|
protected $_wsdl = null;
|
||
|
|
||
|
/**
|
||
|
* @var Zend_Server_Reflection
|
||
|
*/
|
||
|
protected $_reflection = null;
|
||
|
|
||
|
/**
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $_functions = array();
|
||
|
|
||
|
/**
|
||
|
* @var boolean
|
||
|
*/
|
||
|
protected $_strategy;
|
||
|
|
||
|
/**
|
||
|
* Url where the WSDL file will be available at.
|
||
|
*
|
||
|
* @var WSDL Uri
|
||
|
*/
|
||
|
protected $_uri;
|
||
|
|
||
|
/**
|
||
|
* soap:body operation style options
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $_operationBodyStyle = array('use' => 'encoded', 'encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/");
|
||
|
|
||
|
/**
|
||
|
* soap:operation style
|
||
|
*
|
||
|
* @var array
|
||
|
*/
|
||
|
protected $_bindingStyle = array('style' => 'rpc', 'transport' => 'http://schemas.xmlsoap.org/soap/http');
|
||
|
|
||
|
/**
|
||
|
* Constructor
|
||
|
*
|
||
|
* @param boolean|string|Zend_Soap_Wsdl_Strategy_Interface $strategy
|
||
|
* @param string|Zend_Uri $uri
|
||
|
*/
|
||
|
public function __construct($strategy = true, $uri=null)
|
||
|
{
|
||
|
$this->_reflection = new Zend_Server_Reflection();
|
||
|
$this->setComplexTypeStrategy($strategy);
|
||
|
|
||
|
if($uri !== null) {
|
||
|
$this->setUri($uri);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the location at which the WSDL file will be availabe.
|
||
|
*
|
||
|
* @see Zend_Soap_Exception
|
||
|
* @throws Zend_Soap_AutoDiscover_Exception
|
||
|
* @param Zend_Uri|string $uri
|
||
|
* @return Zend_Soap_AutoDiscover
|
||
|
*/
|
||
|
public function setUri($uri)
|
||
|
{
|
||
|
if(!is_string($uri) && !($uri instanceof Zend_Uri)) {
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("No uri given to Zend_Soap_AutoDiscover::setUri as string or Zend_Uri instance.");
|
||
|
}
|
||
|
$this->_uri = $uri;
|
||
|
|
||
|
// change uri in WSDL file also if existant
|
||
|
if($this->_wsdl instanceof Zend_Soap_Wsdl) {
|
||
|
$this->_wsdl->setUri($uri);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return the current Uri that the SOAP WSDL Service will be located at.
|
||
|
*
|
||
|
* @return Zend_Uri
|
||
|
*/
|
||
|
public function getUri()
|
||
|
{
|
||
|
if($this->_uri !== null) {
|
||
|
$uri = $this->_uri;
|
||
|
} else {
|
||
|
$schema = $this->getSchema();
|
||
|
$host = $this->getHostName();
|
||
|
$scriptName = $this->getRequestUriWithoutParameters();
|
||
|
$uri = Zend_Uri::factory($schema . '://' . $host . $scriptName);
|
||
|
$this->setUri($uri);
|
||
|
}
|
||
|
return $uri;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set options for all the binding operations soap:body elements.
|
||
|
*
|
||
|
* By default the options are set to 'use' => 'encoded' and
|
||
|
* 'encodingStyle' => "http://schemas.xmlsoap.org/soap/encoding/".
|
||
|
*
|
||
|
* @see Zend_Soap_AutoDiscover_Exception
|
||
|
* @param array $operationStyle
|
||
|
* @return Zend_Soap_AutoDiscover
|
||
|
*/
|
||
|
public function setOperationBodyStyle(array $operationStyle=array())
|
||
|
{
|
||
|
if(!isset($operationStyle['use'])) {
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("Key 'use' is required in Operation soap:body style.");
|
||
|
}
|
||
|
$this->_operationBodyStyle = $operationStyle;
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set Binding soap:binding style.
|
||
|
*
|
||
|
* By default 'style' is 'rpc' and 'transport' is 'http://schemas.xmlsoap.org/soap/http'.
|
||
|
*
|
||
|
* @param array $bindingStyle
|
||
|
* @return Zend_Soap_AutoDiscover
|
||
|
*/
|
||
|
public function setBindingStyle(array $bindingStyle=array())
|
||
|
{
|
||
|
if(isset($bindingStyle['style'])) {
|
||
|
$this->_bindingStyle['style'] = $bindingStyle['style'];
|
||
|
}
|
||
|
if(isset($bindingStyle['transport'])) {
|
||
|
$this->_bindingStyle['transport'] = $bindingStyle['transport'];
|
||
|
}
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Detect and returns the current HTTP/HTTPS Schema
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getSchema()
|
||
|
{
|
||
|
$schema = "http";
|
||
|
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
|
||
|
$schema = 'https';
|
||
|
}
|
||
|
return $schema;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Detect and return the current hostname
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getHostName()
|
||
|
{
|
||
|
if(isset($_SERVER['HTTP_HOST'])) {
|
||
|
$host = $_SERVER['HTTP_HOST'];
|
||
|
} else {
|
||
|
$host = $_SERVER['SERVER_NAME'];
|
||
|
}
|
||
|
return $host;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Detect and return the current script name without parameters
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getRequestUriWithoutParameters()
|
||
|
{
|
||
|
if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // check this first so IIS will catch
|
||
|
$requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
|
||
|
} elseif (isset($_SERVER['REQUEST_URI'])) {
|
||
|
$requestUri = $_SERVER['REQUEST_URI'];
|
||
|
} elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0, PHP as CGI
|
||
|
$requestUri = $_SERVER['ORIG_PATH_INFO'];
|
||
|
} else {
|
||
|
$requestUri = $_SERVER['SCRIPT_NAME'];
|
||
|
}
|
||
|
if( ($pos = strpos($requestUri, "?")) !== false) {
|
||
|
$requestUri = substr($requestUri, 0, $pos);
|
||
|
}
|
||
|
|
||
|
return $requestUri;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the strategy that handles functions and classes that are added AFTER this call.
|
||
|
*
|
||
|
* @param boolean|string|Zend_Soap_Wsdl_Strategy_Interface $strategy
|
||
|
* @return Zend_Soap_AutoDiscover
|
||
|
*/
|
||
|
public function setComplexTypeStrategy($strategy)
|
||
|
{
|
||
|
$this->_strategy = $strategy;
|
||
|
if($this->_wsdl instanceof Zend_Soap_Wsdl) {
|
||
|
$this->_wsdl->setComplexTypeStrategy($strategy);
|
||
|
}
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the Class the SOAP server will use
|
||
|
*
|
||
|
* @param string $class Class Name
|
||
|
* @param string $namespace Class Namspace - Not Used
|
||
|
* @param array $argv Arguments to instantiate the class - Not Used
|
||
|
*/
|
||
|
public function setClass($class, $namespace = '', $argv = null)
|
||
|
{
|
||
|
$uri = $this->getUri();
|
||
|
|
||
|
$wsdl = new Zend_Soap_Wsdl($class, $uri, $this->_strategy);
|
||
|
|
||
|
// The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
|
||
|
$wsdl->addSchemaTypeSection();
|
||
|
|
||
|
$port = $wsdl->addPortType($class . 'Port');
|
||
|
$binding = $wsdl->addBinding($class . 'Binding', 'tns:' .$class. 'Port');
|
||
|
|
||
|
$wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
|
||
|
$wsdl->addService($class . 'Service', $class . 'Port', 'tns:' . $class . 'Binding', $uri);
|
||
|
foreach ($this->_reflection->reflectClass($class)->getMethods() as $method) {
|
||
|
$this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
|
||
|
}
|
||
|
$this->_wsdl = $wsdl;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a Single or Multiple Functions to the WSDL
|
||
|
*
|
||
|
* @param string $function Function Name
|
||
|
* @param string $namespace Function namespace - Not Used
|
||
|
*/
|
||
|
public function addFunction($function, $namespace = '')
|
||
|
{
|
||
|
static $port;
|
||
|
static $operation;
|
||
|
static $binding;
|
||
|
|
||
|
if (!is_array($function)) {
|
||
|
$function = (array) $function;
|
||
|
}
|
||
|
|
||
|
$uri = $this->getUri();
|
||
|
|
||
|
if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
|
||
|
$parts = explode('.', basename($_SERVER['SCRIPT_NAME']));
|
||
|
$name = $parts[0];
|
||
|
$wsdl = new Zend_Soap_Wsdl($name, $uri, $this->_strategy);
|
||
|
|
||
|
// The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
|
||
|
$wsdl->addSchemaTypeSection();
|
||
|
|
||
|
$port = $wsdl->addPortType($name . 'Port');
|
||
|
$binding = $wsdl->addBinding($name . 'Binding', 'tns:' .$name. 'Port');
|
||
|
|
||
|
$wsdl->addSoapBinding($binding, $this->_bindingStyle['style'], $this->_bindingStyle['transport']);
|
||
|
$wsdl->addService($name . 'Service', $name . 'Port', 'tns:' . $name . 'Binding', $uri);
|
||
|
} else {
|
||
|
$wsdl = $this->_wsdl;
|
||
|
}
|
||
|
|
||
|
foreach ($function as $func) {
|
||
|
$method = $this->_reflection->reflectFunction($func);
|
||
|
$this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
|
||
|
}
|
||
|
$this->_wsdl = $wsdl;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Add a function to the WSDL document.
|
||
|
*
|
||
|
* @param $function Zend_Server_Reflection_Function_Abstract function to add
|
||
|
* @param $wsdl Zend_Soap_Wsdl WSDL document
|
||
|
* @param $port object wsdl:portType
|
||
|
* @param $binding object wsdl:binding
|
||
|
* @return void
|
||
|
*/
|
||
|
protected function _addFunctionToWsdl($function, $wsdl, $port, $binding)
|
||
|
{
|
||
|
$uri = $this->getUri();
|
||
|
|
||
|
// We only support one prototype: the one with the maximum number of arguments
|
||
|
$prototype = null;
|
||
|
$maxNumArgumentsOfPrototype = -1;
|
||
|
foreach ($function->getPrototypes() as $tmpPrototype) {
|
||
|
$numParams = count($tmpPrototype->getParameters());
|
||
|
if ($numParams > $maxNumArgumentsOfPrototype) {
|
||
|
$maxNumArgumentsOfPrototype = $numParams;
|
||
|
$prototype = $tmpPrototype;
|
||
|
}
|
||
|
}
|
||
|
if ($prototype === null) {
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("No prototypes could be found for the '" . $function->getName() . "' function");
|
||
|
}
|
||
|
|
||
|
// Add the input message (parameters)
|
||
|
$args = array();
|
||
|
if ($this->_bindingStyle['style'] == 'document') {
|
||
|
// Document style: wrap all parameters in a sequence element
|
||
|
$sequence = array();
|
||
|
foreach ($prototype->getParameters() as $param) {
|
||
|
$sequenceElement = array(
|
||
|
'name' => $param->getName(),
|
||
|
'type' => $wsdl->getType($param->getType())
|
||
|
);
|
||
|
if ($param->isOptional()) {
|
||
|
$sequenceElement['nillable'] = 'true';
|
||
|
}
|
||
|
$sequence[] = $sequenceElement;
|
||
|
}
|
||
|
$element = array(
|
||
|
'name' => $function->getName(),
|
||
|
'sequence' => $sequence
|
||
|
);
|
||
|
// Add the wrapper element part, which must be named 'parameters'
|
||
|
$args['parameters'] = array('element' => $wsdl->addElement($element));
|
||
|
} else {
|
||
|
// RPC style: add each parameter as a typed part
|
||
|
foreach ($prototype->getParameters() as $param) {
|
||
|
$args[$param->getName()] = array('type' => $wsdl->getType($param->getType()));
|
||
|
}
|
||
|
}
|
||
|
$wsdl->addMessage($function->getName() . 'In', $args);
|
||
|
|
||
|
$isOneWayMessage = false;
|
||
|
if($prototype->getReturnType() == "void") {
|
||
|
$isOneWayMessage = true;
|
||
|
}
|
||
|
|
||
|
if($isOneWayMessage == false) {
|
||
|
// Add the output message (return value)
|
||
|
$args = array();
|
||
|
if ($this->_bindingStyle['style'] == 'document') {
|
||
|
// Document style: wrap the return value in a sequence element
|
||
|
$sequence = array();
|
||
|
if ($prototype->getReturnType() != "void") {
|
||
|
$sequence[] = array(
|
||
|
'name' => $function->getName() . 'Result',
|
||
|
'type' => $wsdl->getType($prototype->getReturnType())
|
||
|
);
|
||
|
}
|
||
|
$element = array(
|
||
|
'name' => $function->getName() . 'Response',
|
||
|
'sequence' => $sequence
|
||
|
);
|
||
|
// Add the wrapper element part, which must be named 'parameters'
|
||
|
$args['parameters'] = array('element' => $wsdl->addElement($element));
|
||
|
} else if ($prototype->getReturnType() != "void") {
|
||
|
// RPC style: add the return value as a typed part
|
||
|
$args['return'] = array('type' => $wsdl->getType($prototype->getReturnType()));
|
||
|
}
|
||
|
$wsdl->addMessage($function->getName() . 'Out', $args);
|
||
|
}
|
||
|
|
||
|
// Add the portType operation
|
||
|
if($isOneWayMessage == false) {
|
||
|
$portOperation = $wsdl->addPortOperation($port, $function->getName(), 'tns:' . $function->getName() . 'In', 'tns:' . $function->getName() . 'Out');
|
||
|
} else {
|
||
|
$portOperation = $wsdl->addPortOperation($port, $function->getName(), 'tns:' . $function->getName() . 'In', false);
|
||
|
}
|
||
|
$desc = $function->getDescription();
|
||
|
if (strlen($desc) > 0) {
|
||
|
$wsdl->addDocumentation($portOperation, $desc);
|
||
|
}
|
||
|
|
||
|
// When using the RPC style, make sure the operation style includes a 'namespace' attribute (WS-I Basic Profile 1.1 R2717)
|
||
|
if ($this->_bindingStyle['style'] == 'rpc' && !isset($this->_operationBodyStyle['namespace'])) {
|
||
|
$this->_operationBodyStyle['namespace'] = ''.$uri;
|
||
|
}
|
||
|
|
||
|
// Add the binding operation
|
||
|
$operation = $wsdl->addBindingOperation($binding, $function->getName(), $this->_operationBodyStyle, $this->_operationBodyStyle);
|
||
|
$wsdl->addSoapOperation($operation, $uri . '#' .$function->getName());
|
||
|
|
||
|
// Add the function name to the list
|
||
|
$this->_functions[] = $function->getName();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Action to take when an error occurs
|
||
|
*
|
||
|
* @param string $fault
|
||
|
* @param string|int $code
|
||
|
*/
|
||
|
public function fault($fault = null, $code = null)
|
||
|
{
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Handle the Request
|
||
|
*
|
||
|
* @param string $request A non-standard request - Not Used
|
||
|
*/
|
||
|
public function handle($request = false)
|
||
|
{
|
||
|
if (!headers_sent()) {
|
||
|
header('Content-Type: text/xml');
|
||
|
}
|
||
|
$this->_wsdl->dump();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Proxy to WSDL dump function
|
||
|
*
|
||
|
* @param string $filename
|
||
|
*/
|
||
|
public function dump($filename)
|
||
|
{
|
||
|
if($this->_wsdl !== null) {
|
||
|
return $this->_wsdl->dump($filename);
|
||
|
} else {
|
||
|
/**
|
||
|
* @see Zend_Soap_AutoDiscover_Exception
|
||
|
*/
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("Cannot dump autodiscovered contents, WSDL file has not been generated yet.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Proxy to WSDL toXml() function
|
||
|
*/
|
||
|
public function toXml()
|
||
|
{
|
||
|
if($this->_wsdl !== null) {
|
||
|
return $this->_wsdl->toXml();
|
||
|
} else {
|
||
|
/**
|
||
|
* @see Zend_Soap_AutoDiscover_Exception
|
||
|
*/
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("Cannot return autodiscovered contents, WSDL file has not been generated yet.");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return an array of functions in the WSDL
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function getFunctions()
|
||
|
{
|
||
|
return $this->_functions;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Load Functions
|
||
|
*
|
||
|
* @param unknown_type $definition
|
||
|
*/
|
||
|
public function loadFunctions($definition)
|
||
|
{
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set Persistance
|
||
|
*
|
||
|
* @param int $mode
|
||
|
*/
|
||
|
public function setPersistence($mode)
|
||
|
{
|
||
|
require_once "Zend/Soap/AutoDiscover/Exception.php";
|
||
|
throw new Zend_Soap_AutoDiscover_Exception("Function has no use in AutoDiscover.");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns an XSD Type for the given PHP type
|
||
|
*
|
||
|
* @param string $type PHP Type to get the XSD type for
|
||
|
* @return string
|
||
|
*/
|
||
|
public function getType($type)
|
||
|
{
|
||
|
if (!($this->_wsdl instanceof Zend_Soap_Wsdl)) {
|
||
|
/** @todo Exception throwing may be more correct */
|
||
|
|
||
|
// WSDL is not defined yet, so we can't recognize type in context of current service
|
||
|
return '';
|
||
|
} else {
|
||
|
return $this->_wsdl->getType($type);
|
||
|
}
|
||
|
}
|
||
|
}
|