mirror of
https://github.com/torrentpier/torrentpier-lts.git
synced 2025-02-28 15:10:54 +03:00
615 lines
18 KiB
PHP
615 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* Zend Framework (http://framework.zend.com/)
|
|
*
|
|
* @link http://github.com/zendframework/zf2 for the canonical source repository
|
|
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
|
|
* @license http://framework.zend.com/license/new-bsd New BSD License
|
|
*/
|
|
|
|
namespace Zend\Soap;
|
|
|
|
use Zend\Server\Reflection;
|
|
use Zend\Soap\AutoDiscover\DiscoveryStrategy\DiscoveryStrategyInterface as DiscoveryStrategy;
|
|
use Zend\Soap\AutoDiscover\DiscoveryStrategy\ReflectionDiscovery;
|
|
use Zend\Soap\Wsdl\ComplexTypeStrategy\ComplexTypeStrategyInterface as ComplexTypeStrategy;
|
|
use Zend\Uri;
|
|
|
|
class AutoDiscover
|
|
{
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $serviceName;
|
|
|
|
/**
|
|
* @var Reflection
|
|
*/
|
|
protected $reflection = null;
|
|
|
|
/**
|
|
* Service function names
|
|
* @var array
|
|
*/
|
|
protected $functions = array();
|
|
|
|
/**
|
|
* Service class name
|
|
* @var string
|
|
*/
|
|
protected $class;
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
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'
|
|
);
|
|
|
|
/**
|
|
* Name of the class to handle the WSDL creation.
|
|
* @var string
|
|
*/
|
|
protected $wsdlClass = 'Zend\Soap\Wsdl';
|
|
|
|
/**
|
|
* Class Map of PHP to WSDL types.
|
|
* @var array
|
|
*/
|
|
protected $classMap = array();
|
|
|
|
/**
|
|
* Discovery strategy for types and other method details.
|
|
* @var DiscoveryStrategy
|
|
*/
|
|
protected $discoveryStrategy;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param null|ComplexTypeStrategy $strategy
|
|
* @param null|string|Uri\Uri $endpointUri
|
|
* @param null|string $wsdlClass
|
|
* @param null|array $classMap
|
|
*/
|
|
public function __construct(
|
|
ComplexTypeStrategy $strategy = null,
|
|
$endpointUri = null,
|
|
$wsdlClass = null,
|
|
array $classMap = array()
|
|
) {
|
|
$this->reflection = new Reflection();
|
|
$this->setDiscoveryStrategy(new ReflectionDiscovery());
|
|
|
|
if (null !== $strategy) {
|
|
$this->setComplexTypeStrategy($strategy);
|
|
}
|
|
if (null !== $endpointUri) {
|
|
$this->setUri($endpointUri);
|
|
}
|
|
if (null !== $wsdlClass) {
|
|
$this->setWsdlClass($wsdlClass);
|
|
}
|
|
$this->setClassMap($classMap);
|
|
}
|
|
|
|
/**
|
|
* Set the discovery strategy for method type and other information.
|
|
*
|
|
* @param DiscoveryStrategy $discoveryStrategy
|
|
* @return self
|
|
*/
|
|
public function setDiscoveryStrategy(DiscoveryStrategy $discoveryStrategy)
|
|
{
|
|
$this->discoveryStrategy = $discoveryStrategy;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the discovery strategy.
|
|
*
|
|
* @return DiscoveryStrategy
|
|
*/
|
|
public function getDiscoveryStrategy()
|
|
{
|
|
return $this->discoveryStrategy;
|
|
}
|
|
|
|
/**
|
|
* Get the class map of php to wsdl mappings.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getClassMap()
|
|
{
|
|
return $this->classMap;
|
|
}
|
|
|
|
/**
|
|
* Set the class map of php to wsdl mappings.
|
|
*
|
|
* @param array $classMap
|
|
* @return self
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setClassMap($classMap)
|
|
{
|
|
if (!is_array($classMap)) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'%s expects an array; received "%s"',
|
|
__METHOD__,
|
|
(is_object($classMap) ? get_class($classMap) : gettype($classMap))
|
|
));
|
|
}
|
|
|
|
$this->classMap = $classMap;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set service name
|
|
*
|
|
* @param string $serviceName
|
|
* @return self
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setServiceName($serviceName)
|
|
{
|
|
$matches = array();
|
|
|
|
// first character must be letter or underscore {@see http://www.w3.org/TR/wsdl#_document-n}
|
|
$i = preg_match('/^[a-z\_]/ims', $serviceName, $matches);
|
|
if ($i != 1) {
|
|
throw new Exception\InvalidArgumentException('Service Name must start with letter or _');
|
|
}
|
|
|
|
$this->serviceName = $serviceName;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get service name
|
|
*
|
|
* @return string
|
|
* @throws Exception\RuntimeException
|
|
*/
|
|
public function getServiceName()
|
|
{
|
|
if (!$this->serviceName) {
|
|
if ($this->class) {
|
|
return $this->reflection->reflectClass($this->class)->getShortName();
|
|
} else {
|
|
throw new Exception\RuntimeException('No service name given. Call AutoDiscover::setServiceName().');
|
|
}
|
|
}
|
|
return $this->serviceName;
|
|
}
|
|
|
|
/**
|
|
* Set the location at which the WSDL file will be available.
|
|
*
|
|
* @param Uri\Uri|string $uri
|
|
* @return self
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setUri($uri)
|
|
{
|
|
if (!is_string($uri) && !($uri instanceof Uri\Uri)) {
|
|
throw new Exception\InvalidArgumentException(
|
|
'Argument to \Zend\Soap\AutoDiscover::setUri should be string or \Zend\Uri\Uri instance.'
|
|
);
|
|
}
|
|
|
|
$uri = trim($uri);
|
|
$uri = htmlspecialchars($uri, ENT_QUOTES, 'UTF-8', false);
|
|
|
|
if (empty($uri)) {
|
|
throw new Exception\InvalidArgumentException('Uri contains invalid characters or is empty');
|
|
}
|
|
|
|
$this->uri = $uri;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return the current Uri that the SOAP WSDL Service will be located at.
|
|
*
|
|
* @return Uri\Uri
|
|
* @throws Exception\RuntimeException
|
|
*/
|
|
public function getUri()
|
|
{
|
|
if ($this->uri === null) {
|
|
throw new Exception\RuntimeException(
|
|
'Missing uri. You have to explicitly configure the Endpoint Uri by calling AutoDiscover::setUri().'
|
|
);
|
|
}
|
|
if (is_string($this->uri)) {
|
|
$this->uri = Uri\UriFactory::factory($this->uri);
|
|
}
|
|
return $this->uri;
|
|
}
|
|
|
|
/**
|
|
* Set the name of the WSDL handling class.
|
|
*
|
|
* @param string $wsdlClass
|
|
* @return self
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setWsdlClass($wsdlClass)
|
|
{
|
|
if (!is_string($wsdlClass) && !is_subclass_of($wsdlClass, '\Zend\Soap\Wsdl')) {
|
|
throw new Exception\InvalidArgumentException(
|
|
'No \Zend\Soap\Wsdl subclass given to Zend\Soap\AutoDiscover::setWsdlClass as string.'
|
|
);
|
|
}
|
|
|
|
$this->wsdlClass = $wsdlClass;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Return the name of the WSDL handling class.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getWsdlClass()
|
|
{
|
|
return $this->wsdlClass;
|
|
}
|
|
|
|
/**
|
|
* 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/".
|
|
*
|
|
* @param array $operationStyle
|
|
* @return self
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function setOperationBodyStyle(array $operationStyle = array())
|
|
{
|
|
if (!isset($operationStyle['use'])) {
|
|
throw new Exception\InvalidArgumentException('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 self
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Set the strategy that handles functions and classes that are added AFTER this call.
|
|
*
|
|
* @param ComplexTypeStrategy $strategy
|
|
* @return self
|
|
*/
|
|
public function setComplexTypeStrategy(ComplexTypeStrategy $strategy)
|
|
{
|
|
$this->strategy = $strategy;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set the Class the SOAP server will use
|
|
*
|
|
* @param string $class Class Name
|
|
* @return self
|
|
*/
|
|
public function setClass($class)
|
|
{
|
|
$this->class = $class;
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add a Single or Multiple Functions to the WSDL
|
|
*
|
|
* @param string $function Function Name
|
|
* @return self
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
public function addFunction($function)
|
|
{
|
|
if (is_array($function)) {
|
|
foreach ($function as $row) {
|
|
$this->addFunction($row);
|
|
}
|
|
} elseif (is_string($function)) {
|
|
if (function_exists($function)) {
|
|
$this->functions[] = $function;
|
|
} else {
|
|
throw new Exception\InvalidArgumentException(
|
|
'Argument to Zend\Soap\AutoDiscover::addFunction should be a valid function name.'
|
|
);
|
|
}
|
|
} else {
|
|
throw new Exception\InvalidArgumentException(
|
|
'Argument to Zend\Soap\AutoDiscover::addFunction should be string or array of strings.'
|
|
);
|
|
}
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Generate the WSDL for a service class.
|
|
*
|
|
* @return Wsdl
|
|
*/
|
|
protected function _generateClass()
|
|
{
|
|
return $this->_generateWsdl($this->reflection->reflectClass($this->class)->getMethods());
|
|
}
|
|
|
|
/**
|
|
* Generate the WSDL for a set of functions.
|
|
*
|
|
* @return Wsdl
|
|
*/
|
|
protected function _generateFunctions()
|
|
{
|
|
$methods = array();
|
|
foreach (array_unique($this->functions) as $func) {
|
|
$methods[] = $this->reflection->reflectFunction($func);
|
|
}
|
|
return $this->_generateWsdl($methods);
|
|
}
|
|
|
|
/**
|
|
* Generate the WSDL for a set of reflection method instances.
|
|
*
|
|
* @param array $reflectionMethods
|
|
* @return Wsdl
|
|
*/
|
|
protected function _generateWsdl(array $reflectionMethods)
|
|
{
|
|
$uri = $this->getUri();
|
|
|
|
$serviceName = $this->getServiceName();
|
|
|
|
$wsdl = new $this->wsdlClass($serviceName, $uri, $this->strategy, $this->classMap);
|
|
|
|
// The wsdl:types element must precede all other elements (WS-I Basic Profile 1.1 R2023)
|
|
$wsdl->addSchemaTypeSection();
|
|
|
|
$port = $wsdl->addPortType($serviceName . 'Port');
|
|
$binding = $wsdl->addBinding($serviceName . 'Binding', Wsdl::TYPES_NS . ':' . $serviceName . 'Port');
|
|
|
|
$wsdl->addSoapBinding($binding, $this->bindingStyle['style'], $this->bindingStyle['transport']);
|
|
$wsdl->addService($serviceName . 'Service', $serviceName . 'Port', Wsdl::TYPES_NS . ':' . $serviceName . 'Binding', $uri);
|
|
|
|
foreach ($reflectionMethods as $method) {
|
|
$this->_addFunctionToWsdl($method, $wsdl, $port, $binding);
|
|
}
|
|
|
|
return $wsdl;
|
|
}
|
|
|
|
/**
|
|
* Add a function to the WSDL document.
|
|
*
|
|
* @param $function Reflection\AbstractFunction function to add
|
|
* @param $wsdl Wsdl WSDL document
|
|
* @param $port \DOMElement wsdl:portType
|
|
* @param $binding \DOMElement wsdl:binding
|
|
* @throws Exception\InvalidArgumentException
|
|
*/
|
|
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) {
|
|
throw new Exception\InvalidArgumentException(sprintf(
|
|
'No prototypes could be found for the "%s" function',
|
|
$function->getName()
|
|
));
|
|
}
|
|
|
|
$functionName = $wsdl->translateType($function->getName());
|
|
|
|
// 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($this->discoveryStrategy->getFunctionParameterType($param))
|
|
);
|
|
if ($param->isOptional()) {
|
|
$sequenceElement['nillable'] = 'true';
|
|
}
|
|
$sequence[] = $sequenceElement;
|
|
}
|
|
|
|
$element = array(
|
|
'name' => $functionName,
|
|
'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($this->discoveryStrategy->getFunctionParameterType($param))
|
|
);
|
|
}
|
|
}
|
|
$wsdl->addMessage($functionName . 'In', $args);
|
|
|
|
$isOneWayMessage = $this->discoveryStrategy->isFunctionOneWay($function, $prototype);
|
|
|
|
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' => $functionName . 'Result',
|
|
'type' => $wsdl->getType($this->discoveryStrategy->getFunctionReturnType($function, $prototype))
|
|
);
|
|
}
|
|
|
|
$element = array(
|
|
'name' => $functionName . 'Response',
|
|
'sequence' => $sequence
|
|
);
|
|
|
|
// Add the wrapper element part, which must be named 'parameters'
|
|
$args['parameters'] = array('element' => $wsdl->addElement($element));
|
|
} elseif ($prototype->getReturnType() != "void") {
|
|
// RPC style: add the return value as a typed part
|
|
$args['return'] = array(
|
|
'type' => $wsdl->getType($this->discoveryStrategy->getFunctionReturnType($function, $prototype))
|
|
);
|
|
}
|
|
|
|
$wsdl->addMessage($functionName . 'Out', $args);
|
|
}
|
|
|
|
// Add the portType operation
|
|
if ($isOneWayMessage == false) {
|
|
$portOperation = $wsdl->addPortOperation(
|
|
$port,
|
|
$functionName,
|
|
Wsdl::TYPES_NS . ':' . $functionName . 'In', Wsdl::TYPES_NS . ':' . $functionName . 'Out'
|
|
);
|
|
} else {
|
|
$portOperation = $wsdl->addPortOperation(
|
|
$port,
|
|
$functionName,
|
|
Wsdl::TYPES_NS . ':' . $functionName . 'In', false
|
|
);
|
|
}
|
|
$desc = $this->discoveryStrategy->getFunctionDocumentation($function);
|
|
|
|
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)
|
|
$operationBodyStyle = $this->operationBodyStyle;
|
|
if ($this->bindingStyle['style'] == 'rpc' && !isset($operationBodyStyle['namespace'])) {
|
|
$operationBodyStyle['namespace'] = '' . $uri;
|
|
}
|
|
|
|
// Add the binding operation
|
|
if ($isOneWayMessage == false) {
|
|
$operation = $wsdl->addBindingOperation($binding, $functionName, $operationBodyStyle, $operationBodyStyle);
|
|
} else {
|
|
$operation = $wsdl->addBindingOperation($binding, $functionName, $operationBodyStyle);
|
|
}
|
|
$wsdl->addSoapOperation($operation, $uri . '#' . $functionName);
|
|
}
|
|
|
|
/**
|
|
* Generate the WSDL file from the configured input.
|
|
*
|
|
* @return Wsdl
|
|
* @throws Exception\RuntimeException
|
|
*/
|
|
public function generate()
|
|
{
|
|
if ($this->class && $this->functions) {
|
|
throw new Exception\RuntimeException('Can either dump functions or a class as a service, not both.');
|
|
}
|
|
|
|
if ($this->class) {
|
|
$wsdl = $this->_generateClass();
|
|
} else {
|
|
$wsdl = $this->_generateFunctions();
|
|
}
|
|
|
|
return $wsdl;
|
|
}
|
|
|
|
/**
|
|
* Proxy to WSDL dump function
|
|
*
|
|
* @param string $filename
|
|
* @return bool
|
|
* @throws Exception\RuntimeException
|
|
*/
|
|
public function dump($filename)
|
|
{
|
|
return $this->generate()->dump($filename);
|
|
}
|
|
|
|
/**
|
|
* Proxy to WSDL toXml() function
|
|
*
|
|
* @return string
|
|
* @throws Exception\RuntimeException
|
|
*/
|
|
public function toXml()
|
|
{
|
|
return $this->generate()->toXml();
|
|
}
|
|
|
|
/**
|
|
* Handle WSDL document.
|
|
*/
|
|
public function handle()
|
|
{
|
|
header('Content-Type: text/xml');
|
|
echo $this->toXml();
|
|
}
|
|
}
|