php-soap / psr18-transport
PSR-18 HTTP 客户端传输用于 SOAP
Requires
- php: ~8.1.0 || ~8.2.0 || ~8.3.0
- ext-dom: *
- php-http/client-common: ^2.3
- php-http/discovery: ^1.12
- php-soap/engine: ^1.3|^2.0
- php-soap/wsdl: ^1.3
- php-soap/xml: ^1.4
- psr/http-client-implementation: ^1.0
- psr/http-factory-implementation: ^1.0
- psr/http-message: ^1.0.1|^2.0
- psr/http-message-implementation: ^1.0
- veewee/xml: ^2.2 || ^3.0
Requires (Dev)
- ext-soap: *
- guzzlehttp/guzzle: ^7.5
- nyholm/psr7: ^1.5
- php-http/mock-client: ^1.5
- php-soap/engine-integration-tests: ^1.4
- php-soap/ext-soap-engine: ^1.4
- phpunit/phpunit: ^10.0
README
此传输允许您通过 PSR-18 HTTP 客户端实现发送 SOAP 请求。您可以使用任何客户端,从 curl、guzzle、httplug、symfony/http-client 等等。它允许您完全控制 HTTP 层,例如克服 ext-soap
中的一些已知问题。此软件包最好与处理数据编码和解码的 SOAP 驱动器 一起使用。
想要帮忙吗?💚
想要更多关于此项目未来的信息?查看我们将要工作的下一个大型项目列表。
先决条件
选择您想要使用的 HTTP 客户端。此软件包期望存在某些 PSR 实现,以便进行安装
- PSR-7:
psr/http-message-implementation
,例如nyholm/psr7
或guzzlehttp/psr7
- PSR-17:
psr/http-factory-implementation
,例如nyholm/psr7
或guzzlehttp/psr7
- PSR-18:
psr/http-client-implementation
,例如symfony/http-client
或guzzlehttp/guzzle
安装
composer require php-soap/psr18-transport
用法
use Http\Client\Common\PluginClient; use Soap\Engine\SimpleEngine; use Soap\Psr18Transport\Psr18Transport; $engine = new SimpleEngine( $driver, $transport = Psr18Transport::createForClient( new PluginClient( $psr18Client, [...$middleware] ) ) );
中间件
此软件包提供了一些中间件实现来处理一些常见的 SOAP 问题。
Wsdl\DisableExtensionsMiddleware
PHP 的 ext-soap 实现不支持 wsdl:required
属性,因为 PHP 中没有 SOAP 扩展机制。当 WSDL 包含必需的 SOAP 扩展时,您将获取此异常:“[SoapFault] SOAP-ERROR: 解析 WSDL:未知必需的 WSDL 扩展”。
此中间件可以在加载 WSDL 时将“wsdl:required”属性设置为 false,这样您就不必更改服务器上的 WSDL。
用法
use Http\Client\Common\PluginClient; use Soap\Psr18Transport\Middleware\Wsdl\DisableExtensionsMiddleware; $wsdlClient = new PluginClient( $psr18Client, [ new DisableExtensionsMiddleware(), ] );
Wsdl\DisablePoliciesMiddleware
PHP 的 ext-soap 客户端不支持 Web 服务策略框架 属性,因为 PHP 中没有此类支持。当 WSDL 包含 WS 策略时,您将获取此异常:“[SoapFault] SOAP-ERROR: 解析 WSDL:未知必需的 WSDL 扩展 'http://schemas.xmlsoap.org/ws/2004/09/policy'”。
此中间件可以用于动态删除所有 UsingPolicy 和 Policy 标签,这样您就不必更改服务器上的 WSDL。
用法
use Http\Client\Common\PluginClient; use Soap\Psr18Transport\Middleware\Wsdl\DisablePoliciesMiddleware; $wsdlClient = new PluginClient( $psr18Client, [ new DisablePoliciesMiddleware(), ] );
RemoveEmptyNodesMiddleware
空属性在请求 XML 中转换为空节点。如果您需要避免请求 xml 中的空节点,您可以添加此中间件。
用法
use Http\Client\Common\PluginClient; use Soap\Psr18Transport\Middleware\RemoveEmptyNodesMiddleware; $httpClient = new PluginClient( $psr18Client, [ new RemoveEmptyNodesMiddleware() ] );
SoapHeaderMiddleware
在发送 SOAP 封装之前将多个 SOAP 标头附加到请求上。
用法
use Http\Client\Common\PluginClient; use Soap\Psr18Transport\Middleware\RemoveEmptyNodesMiddleware; use Soap\Xml\Builder\Header\Actor; use Soap\Xml\Builder\Header\MustUnderstand; use Soap\Xml\Builder\SoapHeader; $httpClient = new PluginClient( $psr18Client, [ new SoapHeaderMiddleware( new SoapHeader( $tns, 'x:Auth', children( namespaced_element($tns, 'x:user', value('josbos')), namespaced_element($tns, 'x:password', value('topsecret')) ) ), new SoapHeader($tns, 'Acting', Actor::next()), new SoapHeader($tns, 'Understanding', new MustUnderstand()) ) ] );
有关 SoapHeader 配置器的更多信息,请参阅 php-soap/xml。
HTTPlug 中间件
此软件包包括 来自 httplug 的所有基本插件。您可以加载任何额外的插件,例如例如 日志插件。
示例
use Http\Client\Common\Plugin\AuthenticationPlugin; use Http\Client\Common\Plugin\BaseUriPlugin; use Http\Client\Common\Plugin\LoggerPlugin; use Http\Message\Authentication\BasicAuth; $httpClient = new PluginClient( $psr18Client, [ new BaseUriPlugin($baseLocation), new AuthenticationPlugin(new BasicAuth($_ENV['user'], $_ENV['pass'])), new LoggerPlugin($psrLogger), ] );
编写自己的中间件
我们使用httplug,因为它拥有插件系统。您可以通过遵循其文档来创建自己的中间件。
身份验证
您可以为WSDL获取和SOAP处理部分添加身份验证。为此,我们建议您使用默认的httplug身份验证提供者。
NTLM
添加NTLM身份验证需要您使用基于curl
的PSR-18 HTTP客户端。在这些客户端上,您可以设置以下选项:[CURLOPT_HTTPAUTH => CURLAUTH_NTLM, CURLOPT_USERPWD => '用户:密码']
。guzzle和symfony/http-client等客户端也支持NTLM,通过在客户端配置期间设置选项来实现。
处理XML
在编写自定义SOAP中间件时,一个常见任务是转换请求或响应的XML。此软件包提供了一些围绕php-soap/xml的快捷工具,以便您更容易地处理XML。
示例
use Http\Client\Common\Plugin; use Http\Promise\Promise; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Soap\Psr18Transport\Xml\XmlMessageManipulator; use VeeWee\Xml\Dom\Document; class SomeMiddleware implements Plugin { public function handleRequest(RequestInterface $request, callable $next, callable $first): Promise { $request = (new XmlMessageManipulator)( $request, fn (Document $document) => $document->manipulate( doSomethingWithRequestXml() ) ); return $next($request) ->then(function (ResponseInterface $response): ResponseInterface { return (new XmlMessageManipulator)( $response, fn (Document $document) => $document->manipulate( doSomethingWithResponseXml() ) ); }); } }
使用PSR-18客户端加载WSDL
对于加载WSDL,您可能想使用PSR-18客户端来完成繁重的HTTP工作。这允许您进行更高级的配置,其中WSDL位于基本身份验证之后。此软件包提供了一个PSR-18 WSDL加载器,可用于使用您喜欢的HTTP客户端加载HTTP位置。它可以与例如来自php-soap/ext-soap-engine的WSDL加载器一起使用。
Psr18Loader
示例
use Http\Client\Common\PluginClient; use Soap\Psr18Transport\Wsdl\Psr18Loader; use Soap\Wsdl\Loader\FlatteningLoader; $loader = Psr18Loader::createForClient( $wsdlClient = new PluginClient( $psr18Client, [...$middleware] ) ); // If you want to flatten all imports whilst using this PSR-18 loader: $loader = new FlatteningLoader($loader); $payload = $loader('http://some.wsdl');
注意:如果您想扁平化WSDL内部的导入,您必须将此加载器与FlatteningLoader结合使用。
异步SOAP调用
从PHP 8.1开始,PHP引入了纤维。这意味着您可以使用任何基于纤维的PSR-18客户端来发送异步调用。
以下是一个关于react/http
和react/async
的简短示例。
composer require react/async veewee/psr18-react-browser
(目前还没有AMP或ReactPHP的官方基于纤维的PSR-18实现。因此,可以使用一个小型桥梁作为中间解决方案)
用法
use Http\Client\Common\PluginClient; use Soap\Engine\SimpleEngine; use Soap\ExtSoapEngine\ExtSoapDriver; use Soap\ExtSoapEngine\ExtSoapOptions; use Soap\ExtSoapEngine\Wsdl\TemporaryWsdlLoaderProvider; use Soap\Psr18Transport\Psr18Transport; use Soap\Psr18Transport\Wsdl\Psr18Loader; use Soap\Wsdl\Loader\FlatteningLoader; use Veewee\Psr18ReactBrowser\Psr18ReactBrowserClient; use function React\Async\async; use function React\Async\await; use function React\Async\parallel; $asyncHttpClient = Psr18ReactBrowserClient::default(); $engine = new SimpleEngine( ExtSoapDriver::createFromClient( $client = AbusedClient::createFromOptions( ExtSoapOptions::defaults('http://www.dneonline.com/calculator.asmx?wsdl', []) ->disableWsdlCache() ) ), $transport = Psr18Transport::createForClient( new PluginClient( $asyncHttpClient, [...$middleware] ) ) ); $add = async(fn ($a, $b) => $engine->request('Add', [['intA' => $a, 'intB' => $b]])); $addWithLogger = fn ($a, $b) => $add($a, $b)->then( function ($result) use ($a, $b) { echo "SUCCESS {$a}+{$b} = ${result}!" . PHP_EOL; return $result; }, function (Exception $e) { echo 'ERROR: ' . $e->getMessage() . PHP_EOL; } ); $results = await(parallel([ fn() => $addWithLogger(1, 2), fn() => $addWithLogger(3, 4), fn() => $addWithLogger(5, 6) ])); var_dump($results);