php-soap/psr18-transport

PSR-18 HTTP 客户端传输用于 SOAP

1.6.0 2024-03-18 10:21 UTC

This package is auto-updated.

Last update: 2024-09-18 11:25:00 UTC


README

此传输允许您通过 PSR-18 HTTP 客户端实现发送 SOAP 请求。您可以使用任何客户端,从 curl、guzzle、httplug、symfony/http-client 等等。它允许您完全控制 HTTP 层,例如克服 ext-soap 中的一些已知问题。此软件包最好与处理数据编码和解码的 SOAP 驱动器 一起使用。

想要帮忙吗?💚

想要更多关于此项目未来的信息?查看我们将要工作的下一个大型项目列表。

先决条件

选择您想要使用的 HTTP 客户端。此软件包期望存在某些 PSR 实现,以便进行安装

  • PSR-7: psr/http-message-implementation,例如 nyholm/psr7guzzlehttp/psr7
  • PSR-17: psr/http-factory-implementation,例如 nyholm/psr7guzzlehttp/psr7
  • PSR-18: psr/http-client-implementation,例如 symfony/http-clientguzzlehttp/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/httpreact/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);