PHP 没有 Soap 客户端的 Soap 服务器
PHP Soap Server without Soap Client
有几个星期,我一直在尝试在 php 中创建一个 soap 服务器,它首先提供一个带有身份验证 header 的 wsdl,然后它只接受经过身份验证的用户要求。但我只是让它在没有身份验证的情况下完全工作。我所做的每一次搜索和我找到的每一个解决方案都包含一个 SoapClient,Zend_Soap_Client,nu_soap_client(你的名字)和我的 [=51= 周围的某种包装器 class ] 或仅在客户端添加用户名和密码。
但在我的解决方案中,只有服务器在 php 中,客户端是用 java 等编写的各种程序, 而不是 在 php 中。这是我的代码(我在这里使用 zend,但想法在普通 php 上是相同的)wsdl 生成和服务器部分:
use Zend\Soap\AutoDiscover as Zend_Soap_AutoDiscover;
use Zend\Soap\Server as Zend_Soap_Server;
if (isset($_GET['wsdl'])) {
$autodiscover = new Zend\Soap\AutoDiscover();
$autodiscover->setClass('MyClass');
$autodiscover->setUri('http://Myclass/path/');
$autodiscover->handle();
exit;
}
$server = new Zend_Soap_Server(null, array(
'uri' => 'http://Myclass/path/',
));
$server->setClass('Myclass');
$server->handle();
我还使用了 piotrooo 的 wsdl 生成器和普通的 php soap 库,如下所示:
use WSDL\WSDLCreator;
// use WSDL\XML\Styles\DocumentLiteralWrapped;
if (isset($_GET['wsdl'])) {
$wsdl = new WSDL\WSDLCreator('Myclass', 'http://Myclass/path/');
$wsdl->setNamespace("http://Myclass/path/");
$wsdl->renderWSDL();
exit;
}
$server = new SoapServer(null, array(
'uri' => 'http://Myclass/path/',
// 'style' => SOAP_DOCUMENT,
// 'use' => SOAP_LITERAL,
));
$server->setClass('Myclass');
$server->handle();
还有我的class:
class Myclass
{
public function __construct()
{
/*some db stuff with doctrine*/
}
/**
* @param string $id
* @return object
*/
public function Id($id)
{
/*I'm using doctrine to fetch data from db and then return an object/or array*/
}
}
最后这是自动生成的 wsdl:
<definitions name="Myclass" targetNamespace="http://Myclass/path/"><types><xsd:schema targetNamespace="http://Myclass/path/"/></types><portType name="MyclassPort"><operation name="Id"><documentation>Id</documentation><input message="tns:IdIn"/><output message="tns:IdOut"/></operation></portType><binding name="MyclassBinding" type="tns:MyclassPort"><soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/><operation name="Id"><soap:operation soapAction="http://Myclass/path/#Id"/><input><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://Myclass/path/"/></input><output><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://Myclass/path/"/></output></operation></binding><service name="MyclassService"><port name="MyclassPort" binding="tns:MyclassBinding"><soap:address location="http://Myclass/path/"/></port></service><message name="IdIn"><part name="id" type="xsd:string"/></message><message name="IdOut"><part name="return" type="xsd:struct"/></message></definitions>
每个生成器的注释各不相同。
我也尝试过 nusoap 但我很失望,因为它是纯粹的 class 方法发现。我必须补充一点,我正在使用 soapui 测试服务的使用情况(这就是为什么我不想要 php 的 SoapClient 或等效示例的原因)。
最后我还必须说,我尝试了在我的 class 中添加身份验证方法的解决方案并且这有效 但是 这并没有阻止未经身份验证用户访问 ws.
一些额外的信息。根据我的研究,我发现的每个答案都是关于 SOAPClient 的,例如 $client->__addheader() 函数等。请告诉我我是否错了,或者这不能用 [=50= 完成] 因为我必须找其他人用另一种编程语言为我做这件事 Java 等等
提前致谢
季米特里斯
您可以让您的客户端在基本上 3 个地方发送身份验证信息:SOAP Body、SOAP Headers、HTTP Headers。在这三个中,我认为合适的是 SOAP Headers,所以我将在本示例中使用它。 (请注意,我正在使用一些自定义身份验证 header 格式,但我建议您研究 WS-Security 协议。)
class Myclass
{
public function __construct()
{
/*some db stuff with doctrine*/
}
public function Auth($auth)
{
if (! $this->validateUser($auth->Username, $auth->Password)) {
throw new SoapFault('Client.Authentication', 'Invalid username or password');
}
}
/**
* @param string $id
* @return object
*/
public function Id($id)
{
/*...*/
}
private function validateUser($user, $password)
{
/*...*/
}
}
现在对于客户端:我认为您作为服务器角色不必担心哪些特定客户端会使用您的服务,只是因为您无法考虑所有客户端。这就是为什么有标准,可以从特定的实现中抽象出来。因此,只要您遵循标准,您就可以相信 任何 客户端都会遵守。幸运的是,SOAP header 是标准的一部分。
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<Auth>
<Username>foo</Username>
<Password>bar</Password>
</Auth>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<Id>4</Id>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
这就是您期望收到的 XML,与客户无关。
最后,WSDL。据我所知,Zend Autodiscover 和 piotrooo 的库都不支持 headers 定义。显然 Yii 的 CWebService 可以(使用适当的方法注释)。
在最坏的情况下,您可以自己编写 WSDL,或者根据您选择的库生成的 WSDL 对其进行改编。
链接:
- http://www.yiiframework.com/doc/api/1.1/CWebService
- http://www.ibm.com/developerworks/library/ws-tip-headers/
更新:
class Auth
{
/**
* @soap
* @var string
*/
public $Username;
/**
* @soap
* @var string
*/
public $Password;
}
class MyClass
{
private $authenticated = false;
public function Auth($auth)
{
if ($this->validateUser($auth->Username, $auth->Password)) {
$this->authenticated = true;
}
}
/**
* @soap
* @header Auth $auth
* @param string $id
* @return object
*/
public function Id($id)
{
if (! $this->authenticated) {
throw new SoapFault('Client.Authentication', 'Invalid username or password');
}
//return $id;
}
private function validateUser($user, $password)
{
return $user == 'foo';
}
}
require __DIR__ . '/vendor/yiisoft/yii/framework/yii.php';
$URL = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'];
if (isset($_GET['wsdl'])) {
$gen = new CWsdlGenerator();
$wsdl = $gen->generateWsdl(MyClass::class, $URL);
header("Content-type: text/xml; charset=utf-8");
echo $wsdl;
}
else {
$server = new SoapServer($URL . '?wsdl');
$server->setClass(MyClass::class);
echo $server->handle();
}
这确实与我之前提供的示例 XML 的预期一样有效。
(您只需将 <Id>4</Id>
更改为 <Id><id>4</id></Id>
)。
有几个星期,我一直在尝试在 php 中创建一个 soap 服务器,它首先提供一个带有身份验证 header 的 wsdl,然后它只接受经过身份验证的用户要求。但我只是让它在没有身份验证的情况下完全工作。我所做的每一次搜索和我找到的每一个解决方案都包含一个 SoapClient,Zend_Soap_Client,nu_soap_client(你的名字)和我的 [=51= 周围的某种包装器 class ] 或仅在客户端添加用户名和密码。 但在我的解决方案中,只有服务器在 php 中,客户端是用 java 等编写的各种程序, 而不是 在 php 中。这是我的代码(我在这里使用 zend,但想法在普通 php 上是相同的)wsdl 生成和服务器部分:
use Zend\Soap\AutoDiscover as Zend_Soap_AutoDiscover;
use Zend\Soap\Server as Zend_Soap_Server;
if (isset($_GET['wsdl'])) {
$autodiscover = new Zend\Soap\AutoDiscover();
$autodiscover->setClass('MyClass');
$autodiscover->setUri('http://Myclass/path/');
$autodiscover->handle();
exit;
}
$server = new Zend_Soap_Server(null, array(
'uri' => 'http://Myclass/path/',
));
$server->setClass('Myclass');
$server->handle();
我还使用了 piotrooo 的 wsdl 生成器和普通的 php soap 库,如下所示:
use WSDL\WSDLCreator;
// use WSDL\XML\Styles\DocumentLiteralWrapped;
if (isset($_GET['wsdl'])) {
$wsdl = new WSDL\WSDLCreator('Myclass', 'http://Myclass/path/');
$wsdl->setNamespace("http://Myclass/path/");
$wsdl->renderWSDL();
exit;
}
$server = new SoapServer(null, array(
'uri' => 'http://Myclass/path/',
// 'style' => SOAP_DOCUMENT,
// 'use' => SOAP_LITERAL,
));
$server->setClass('Myclass');
$server->handle();
还有我的class:
class Myclass
{
public function __construct()
{
/*some db stuff with doctrine*/
}
/**
* @param string $id
* @return object
*/
public function Id($id)
{
/*I'm using doctrine to fetch data from db and then return an object/or array*/
}
}
最后这是自动生成的 wsdl:
<definitions name="Myclass" targetNamespace="http://Myclass/path/"><types><xsd:schema targetNamespace="http://Myclass/path/"/></types><portType name="MyclassPort"><operation name="Id"><documentation>Id</documentation><input message="tns:IdIn"/><output message="tns:IdOut"/></operation></portType><binding name="MyclassBinding" type="tns:MyclassPort"><soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/><operation name="Id"><soap:operation soapAction="http://Myclass/path/#Id"/><input><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://Myclass/path/"/></input><output><soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://Myclass/path/"/></output></operation></binding><service name="MyclassService"><port name="MyclassPort" binding="tns:MyclassBinding"><soap:address location="http://Myclass/path/"/></port></service><message name="IdIn"><part name="id" type="xsd:string"/></message><message name="IdOut"><part name="return" type="xsd:struct"/></message></definitions>
每个生成器的注释各不相同。 我也尝试过 nusoap 但我很失望,因为它是纯粹的 class 方法发现。我必须补充一点,我正在使用 soapui 测试服务的使用情况(这就是为什么我不想要 php 的 SoapClient 或等效示例的原因)。 最后我还必须说,我尝试了在我的 class 中添加身份验证方法的解决方案并且这有效 但是 这并没有阻止未经身份验证用户访问 ws.
一些额外的信息。根据我的研究,我发现的每个答案都是关于 SOAPClient 的,例如 $client->__addheader() 函数等。请告诉我我是否错了,或者这不能用 [=50= 完成] 因为我必须找其他人用另一种编程语言为我做这件事 Java 等等
提前致谢
季米特里斯
您可以让您的客户端在基本上 3 个地方发送身份验证信息:SOAP Body、SOAP Headers、HTTP Headers。在这三个中,我认为合适的是 SOAP Headers,所以我将在本示例中使用它。 (请注意,我正在使用一些自定义身份验证 header 格式,但我建议您研究 WS-Security 协议。)
class Myclass
{
public function __construct()
{
/*some db stuff with doctrine*/
}
public function Auth($auth)
{
if (! $this->validateUser($auth->Username, $auth->Password)) {
throw new SoapFault('Client.Authentication', 'Invalid username or password');
}
}
/**
* @param string $id
* @return object
*/
public function Id($id)
{
/*...*/
}
private function validateUser($user, $password)
{
/*...*/
}
}
现在对于客户端:我认为您作为服务器角色不必担心哪些特定客户端会使用您的服务,只是因为您无法考虑所有客户端。这就是为什么有标准,可以从特定的实现中抽象出来。因此,只要您遵循标准,您就可以相信 任何 客户端都会遵守。幸运的是,SOAP header 是标准的一部分。
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Header>
<Auth>
<Username>foo</Username>
<Password>bar</Password>
</Auth>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<Id>4</Id>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
这就是您期望收到的 XML,与客户无关。
最后,WSDL。据我所知,Zend Autodiscover 和 piotrooo 的库都不支持 headers 定义。显然 Yii 的 CWebService 可以(使用适当的方法注释)。
在最坏的情况下,您可以自己编写 WSDL,或者根据您选择的库生成的 WSDL 对其进行改编。
链接:
- http://www.yiiframework.com/doc/api/1.1/CWebService
- http://www.ibm.com/developerworks/library/ws-tip-headers/
更新:
class Auth
{
/**
* @soap
* @var string
*/
public $Username;
/**
* @soap
* @var string
*/
public $Password;
}
class MyClass
{
private $authenticated = false;
public function Auth($auth)
{
if ($this->validateUser($auth->Username, $auth->Password)) {
$this->authenticated = true;
}
}
/**
* @soap
* @header Auth $auth
* @param string $id
* @return object
*/
public function Id($id)
{
if (! $this->authenticated) {
throw new SoapFault('Client.Authentication', 'Invalid username or password');
}
//return $id;
}
private function validateUser($user, $password)
{
return $user == 'foo';
}
}
require __DIR__ . '/vendor/yiisoft/yii/framework/yii.php';
$URL = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'];
if (isset($_GET['wsdl'])) {
$gen = new CWsdlGenerator();
$wsdl = $gen->generateWsdl(MyClass::class, $URL);
header("Content-type: text/xml; charset=utf-8");
echo $wsdl;
}
else {
$server = new SoapServer($URL . '?wsdl');
$server->setClass(MyClass::class);
echo $server->handle();
}
这确实与我之前提供的示例 XML 的预期一样有效。
(您只需将 <Id>4</Id>
更改为 <Id><id>4</id></Id>
)。