diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:31:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 11:31:45 +0000 |
commit | 4e393913a4b1f06509da4341f0f58a41adac9117 (patch) | |
tree | 9c27e3eb77d109dff5fd031502311c5616adab04 /vendor/clue/soap-react | |
parent | Initial commit. (diff) | |
download | icinga-php-thirdparty-upstream.tar.xz icinga-php-thirdparty-upstream.zip |
Adding upstream version 0.12.1+ds.upstream/0.12.1+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/clue/soap-react')
-rw-r--r-- | vendor/clue/soap-react/CHANGELOG.md | 130 | ||||
-rw-r--r-- | vendor/clue/soap-react/LICENSE | 21 | ||||
-rw-r--r-- | vendor/clue/soap-react/README.md | 453 | ||||
-rw-r--r-- | vendor/clue/soap-react/composer.json | 29 | ||||
-rw-r--r-- | vendor/clue/soap-react/src/Client.php | 326 | ||||
-rw-r--r-- | vendor/clue/soap-react/src/Protocol/ClientDecoder.php | 51 | ||||
-rw-r--r-- | vendor/clue/soap-react/src/Protocol/ClientEncoder.php | 69 | ||||
-rw-r--r-- | vendor/clue/soap-react/src/Proxy.php | 50 |
8 files changed, 1129 insertions, 0 deletions
diff --git a/vendor/clue/soap-react/CHANGELOG.md b/vendor/clue/soap-react/CHANGELOG.md new file mode 100644 index 0000000..2b605d2 --- /dev/null +++ b/vendor/clue/soap-react/CHANGELOG.md @@ -0,0 +1,130 @@ +# Changelog + +## 2.0.0 (2020-10-28) + +* Feature / BC break: Update to reactphp/http v1.0.0. + (#45 by @SimonFrings) + +* Feature / BC break: Add type declarations and require PHP 7.1+ as a consequence + (#47 by @SimonFrings, #49 by @clue) + +* Use fully qualified class names in documentation. + (#46 by @SimonFrings) + +* Improve test suite and add `.gitattributes` to exclude dev files from export. + Prepare PHP 8 support, update to PHPUnit 9 and simplify test matrix. + (#40 by @andreybolonin, #42 and #44 by @SimonFrings and #48 by @clue) + +## 1.0.0 (2018-11-07) + +* First stable release, now following SemVer! + + I'd like to thank [Bergfreunde GmbH](https://www.bergfreunde.de/), a German-based + online retailer for Outdoor Gear & Clothing, for sponsoring large parts of this development! 🎉 + Thanks to sponsors like this, who understand the importance of open source + development, I can justify spending time and focus on open source development + instead of traditional paid work. + + > Did you know that I offer custom development services and issuing invoices for + sponsorships of releases and for contributions? Contact me (@clue) for details. + +* BC break / Feature: Replace `Factory` with simplified `Client` constructor, + add support for optional SOAP options and non-WSDL mode and + respect WSDL type definitions when decoding and support classmap option. + (#31, #32 and #33 by @clue) + + ```php + // old + $factory = new Factory($loop); + $client = $factory->createClientFromWsdl($wsdl); + + // new + $browser = new Browser($loop); + $client = new Client($browser, $wsdl); + ``` + + The `Client` constructor now accepts an array of options. All given options will + be passed through to the underlying `SoapClient`. However, not all options + make sense in this async implementation and as such may not have the desired + effect. See also [`SoapClient`](http://php.net/manual/en/soapclient.soapclient.php) + documentation for more details. + + If working in WSDL mode, the `$options` parameter is optional. If working in + non-WSDL mode, the WSDL parameter must be set to `null` and the options + parameter must contain the `location` and `uri` options, where `location` is + the URL of the SOAP server to send the request to, and `uri` is the target + namespace of the SOAP service: + + ```php + $client = new Client($browser, null, array( + 'location' => 'http://example.com', + 'uri' => 'http://ping.example.com', + )); + ``` + +* BC break: Mark all classes as final and all internal APIs as `@internal`. + (#26 and #37 by @clue) + +* Feature: Add new `Client::withLocation()` method. + (#38 by @floriansimon1, @pascal-hofmann and @clue) + + The `withLocation(string $location): self` method can be used to + return a new `Client` with the updated location (URI) for all functions. + + Note that this is not to be confused with the WSDL file location. + A WSDL file can contain any number of function definitions. + It's very common that all of these functions use the same location definition. + However, technically each function can potentially use a different location. + + ```php + $client = $client->withLocation('http://example.com/soap'); + + assert('http://example.com/soap' === $client->getLocation('echo')); + ``` + + As an alternative to this method, you can also set the `location` option + in the `Client` constructor (such as when in non-WSDL mode). + +* Feature: Properly handle SOAP error responses, accept HTTP error responses and do not follow any HTTP redirects. + (#35 by @clue) + +* Improve documentation and update project homepage, + documentation for HTTP proxy servers, + support timeouts for SOAP requests (HTTP timeout option) and + add cancellation support. + (#25, #29, #30 #34 and #36 by @clue) + +* Improve test suite by supporting PHPUnit 6, + optionally skip functional integration tests requiring internet and + test against PHP 7.2 and PHP 7.1 and latest ReactPHP components. + (#24 by @carusogabriel and #27 and #28 by @clue) + +## 0.2.0 (2017-10-02) + +* Feature: Added the possibility to use local WSDL files + (#11 by @floriansimon1) + + ```php + $factory = new Factory($loop); + $wsdl = file_get_contents('service.wsdl'); + $client = $factory->createClientFromWsdl($wsdl); + ``` + +* Feature: Add `Client::getLocation()` helper + (#13 by @clue) + +* Feature: Forward compatibility with clue/buzz-react v2.0 and upcoming EventLoop + (#9 by @floriansimon1 and #19 and #21 by @clue) + +* Improve test suite by adding PHPUnit to require-dev and + test PHP 5.3 through PHP 7.0 and HHVM and + fix Travis build config + (#1 by @WyriHaximus and #12, #17 and #22 by @clue) + +## 0.1.0 (2014-07-28) + +* First tagged release + +## 0.0.0 (2014-07-20) + +* Initial concept diff --git a/vendor/clue/soap-react/LICENSE b/vendor/clue/soap-react/LICENSE new file mode 100644 index 0000000..9426ad3 --- /dev/null +++ b/vendor/clue/soap-react/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Christian Lück + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/clue/soap-react/README.md b/vendor/clue/soap-react/README.md new file mode 100644 index 0000000..0984e13 --- /dev/null +++ b/vendor/clue/soap-react/README.md @@ -0,0 +1,453 @@ +# clue/reactphp-soap [![Build Status](https://travis-ci.org/clue/reactphp-soap.svg?branch=master)](https://travis-ci.org/clue/reactphp-soap) + +Simple, async [SOAP](https://en.wikipedia.org/wiki/SOAP) web service client library, +built on top of [ReactPHP](https://reactphp.org/). + +Most notably, SOAP is often used for invoking +[Remote procedure calls](https://en.wikipedia.org/wiki/Remote_procedure_call) (RPCs) +in distributed systems. +Internally, SOAP messages are encoded as XML and usually sent via HTTP POST requests. +For the most part, SOAP (originally *Simple Object Access protocol*) is a protocol of the past, +and in fact anything but *simple*. +It is still in use by many (often *legacy*) systems. +This project provides a *simple* API for invoking *async* RPCs to remote web services. + +* **Async execution of functions** - + Send any number of functions (RPCs) to the remote web service in parallel and + process their responses as soon as results come in. + The Promise-based design provides a *sane* interface to working with out of order responses. +* **Async processing of the WSDL** - + The WSDL (web service description language) file will be downloaded and processed + in the background. +* **Event-driven core** - + Internally, everything uses event handlers to react to incoming events, such as an incoming RPC result. +* **Lightweight, SOLID design** - + Provides a thin abstraction that is [*just good enough*](https://en.wikipedia.org/wiki/Principle_of_good_enough) + and does not get in your way. + Built on top of tested components instead of re-inventing the wheel. +* **Good test coverage** - + Comes with an automated tests suite and is regularly tested against actual web services in the wild. + +**Table of contents** + +* [Support us](#support-us) +* [Quickstart example](#quickstart-example) +* [Usage](#usage) + * [Client](#client) + * [soapCall()](#soapcall) + * [getFunctions()](#getfunctions) + * [getTypes()](#gettypes) + * [getLocation()](#getlocation) + * [withLocation()](#withlocation) + * [Proxy](#proxy) + * [Functions](#functions) + * [Promises](#promises) + * [Cancellation](#cancellation) + * [Timeouts](#timeouts) +* [Install](#install) +* [Tests](#tests) +* [License](#license) + +## Support us + +We invest a lot of time developing, maintaining and updating our awesome +open-source projects. You can help us sustain this high-quality of our work by +[becoming a sponsor on GitHub](https://github.com/sponsors/clue). Sponsors get +numerous benefits in return, see our [sponsoring page](https://github.com/sponsors/clue) +for details. + +Let's take these projects to the next level together! 🚀 + +## Quickstart example + +Once [installed](#install), you can use the following code to query an example +web service via SOAP: + +```php +$loop = React\EventLoop\Factory::create(); +$browser = new React\Http\Browser($loop); +$wsdl = 'http://example.com/demo.wsdl'; + +$browser->get($wsdl)->then(function (Psr\Http\Message\ResponseInterface $response) use ($browser) { + $client = new Clue\React\Soap\Client($browser, (string)$response->getBody()); + $api = new Clue\React\Soap\Proxy($client); + + $api->getBank(array('blz' => '12070000'))->then(function ($result) { + var_dump('Result', $result); + }); +}); + +$loop->run(); +``` + +See also the [examples](examples). + +## Usage + +### Client + +The `Client` class is responsible for communication with the remote SOAP +WebService server. + +It requires a [`Browser`](https://github.com/reactphp/http#browser) object +bound to the main [`EventLoop`](https://github.com/reactphp/event-loop#usage) +in order to handle async requests, the WSDL file contents and an optional +array of SOAP options: + +```php +$loop = React\EventLoop\Factory::create(); +$browser = new React\Http\Browser($loop); + +$wsdl = '<?xml …'; +$options = array(); + +$client = new Clue\React\Soap\Client($browser, $wsdl, $options); +``` + +If you need custom connector settings (DNS resolution, TLS parameters, timeouts, +proxy servers etc.), you can explicitly pass a custom instance of the +[`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface) +to the [`Browser`](https://github.com/reactphp/http#browser) instance: + +```php +$connector = new React\Socket\Connector($loop, array( + 'dns' => '127.0.0.1', + 'tcp' => array( + 'bindto' => '192.168.10.1:0' + ), + 'tls' => array( + 'verify_peer' => false, + 'verify_peer_name' => false + ) +)); + +$browser = new React\Http\Browser($loop, $connector); +$client = new Clue\React\Soap\Client($browser, $wsdl); +``` + +The `Client` works similar to PHP's `SoapClient` (which it uses under the +hood), but leaves you the responsibility to load the WSDL file. This allows +you to use local WSDL files, WSDL files from a cache or the most common form, +downloading the WSDL file contents from an URL through the `Browser`: + +```php +$browser = new React\Http\Browser($loop); + +$browser->get($url)->then( + function (Psr\Http\Message\ResponseInterface $response) use ($browser) { + // WSDL file is ready, create client + $client = new Clue\React\Soap\Client($browser, (string)$response->getBody()); + + // do something… + }, + function (Exception $e) { + // an error occured while trying to download the WSDL + } +); +``` + +The `Client` constructor loads the given WSDL file contents into memory and +parses its definition. If the given WSDL file is invalid and can not be +parsed, this will throw a `SoapFault`: + +```php +try { + $client = new Clue\React\Soap\Client($browser, $wsdl); +} catch (SoapFault $e) { + echo 'Error: ' . $e->getMessage() . PHP_EOL; +} +``` + +> Note that if you have an old version of `ext-xdebug` < 2.7 loaded, this may + halt with a fatal error instead of throwing a `SoapFault`. It is not + recommended to use this extension in production, so this should only ever + affect test environments. + +The `Client` constructor accepts an array of options. All given options will +be passed through to the underlying `SoapClient`. However, not all options +make sense in this async implementation and as such may not have the desired +effect. See also [`SoapClient`](https://www.php.net/manual/en/soapclient.soapclient.php) +documentation for more details. + +If working in WSDL mode, the `$options` parameter is optional. If working in +non-WSDL mode, the WSDL parameter must be set to `null` and the options +parameter must contain the `location` and `uri` options, where `location` is +the URL of the SOAP server to send the request to, and `uri` is the target +namespace of the SOAP service: + +```php +$client = new Clue\React\Soap\Client($browser, null, array( + 'location' => 'http://example.com', + 'uri' => 'http://ping.example.com', +)); +``` + +Similarly, if working in WSDL mode, the `location` option can be used to +explicitly overwrite the URL of the SOAP server to send the request to: + +```php +$client = new Clue\React\Soap\Client($browser, $wsdl, array( + 'location' => 'http://example.com' +)); +``` + +You can use the `soap_version` option to change from the default SOAP 1.1 to +use SOAP 1.2 instead: + +```php +$client = new Clue\React\Soap\Client($browser, $wsdl, array( + 'soap_version' => SOAP_1_2 +)); +``` + +You can use the `classmap` option to map certain WSDL types to PHP classes +like this: + +```php +$client = new Clue\React\Soap\Client($browser, $wsdl, array( + 'classmap' => array( + 'getBankResponseType' => BankResponse::class + ) +)); +``` + +The `proxy_host` option (and family) is not supported by this library. As an +alternative, you can configure the given `$browser` instance to use an +[HTTP proxy server](https://github.com/reactphp/http#http-proxy). +If you find any other option is missing or not supported here, PRs are much +appreciated! + +All public methods of the `Client` are considered *advanced usage*. +If you want to call RPC functions, see below for the [`Proxy`](#proxy) class. + +#### soapCall() + +The `soapCall(string $method, mixed[] $arguments): PromiseInterface<mixed, Exception>` method can be used to +queue the given function to be sent via SOAP and wait for a response from the remote web service. + +```php +// advanced usage, see Proxy for recommended alternative +$promise = $client->soapCall('ping', array('hello', 42)); +``` + +Note: This is considered *advanced usage*, you may want to look into using the [`Proxy`](#proxy) instead. + +```php +$proxy = new Clue\React\Soap\Proxy($client); +$promise = $proxy->ping('hello', 42); +``` + +#### getFunctions() + +The `getFunctions(): string[]|null` method can be used to +return an array of functions defined in the WSDL. + +It returns the equivalent of PHP's +[`SoapClient::__getFunctions()`](https://www.php.net/manual/en/soapclient.getfunctions.php). +In non-WSDL mode, this method returns `null`. + +#### getTypes() + +The `getTypes(): string[]|null` method can be used to +return an array of types defined in the WSDL. + +It returns the equivalent of PHP's +[`SoapClient::__getTypes()`](https://www.php.net/manual/en/soapclient.gettypes.php). +In non-WSDL mode, this method returns `null`. + +#### getLocation() + +The `getLocation(string|int $function): string` method can be used to +return the location (URI) of the given webservice `$function`. + +Note that this is not to be confused with the WSDL file location. +A WSDL file can contain any number of function definitions. +It's very common that all of these functions use the same location definition. +However, technically each function can potentially use a different location. + +The `$function` parameter should be a string with the the SOAP function name. +See also [`getFunctions()`](#getfunctions) for a list of all available functions. + +```php +assert('http://example.com/soap/service' === $client->getLocation('echo')); +``` + +For easier access, this function also accepts a numeric function index. +It then uses [`getFunctions()`](#getfunctions) internally to get the function +name for the given index. +This is particularly useful for the very common case where all functions use the +same location and accessing the first location is sufficient. + +```php +assert('http://example.com/soap/service' === $client->getLocation(0)); +``` + +When the `location` option has been set in the `Client` constructor +(such as when in non-WSDL mode) or via the `withLocation()` method, this +method returns the value of the given location. + +Passing a `$function` not defined in the WSDL file will throw a `SoapFault`. + +#### withLocation() + +The `withLocation(string $location): self` method can be used to +return a new `Client` with the updated location (URI) for all functions. + +Note that this is not to be confused with the WSDL file location. +A WSDL file can contain any number of function definitions. +It's very common that all of these functions use the same location definition. +However, technically each function can potentially use a different location. + +```php +$client = $client->withLocation('http://example.com/soap'); + +assert('http://example.com/soap' === $client->getLocation('echo')); +``` + +As an alternative to this method, you can also set the `location` option +in the `Client` constructor (such as when in non-WSDL mode). + +### Proxy + +The `Proxy` class wraps an existing [`Client`](#client) instance in order to ease calling +SOAP functions. + +```php +$proxy = new Clue\React\Soap\Proxy($client); +``` + +> Note that this class is called "Proxy" because it will forward (proxy) all + method calls to the actual SOAP service via the underlying + [`Client::soapCall()`](#soapcall) method. This is not to be confused with + using a proxy server. See [`Client`](#client) documentation for more + details on how to use an HTTP proxy server. + +#### Functions + +Each and every method call to the `Proxy` class will be sent via SOAP. + +```php +$proxy->myMethod($myArg1, $myArg2)->then(function ($response) { + // result received +}); +``` + +Please refer to your WSDL or its accompanying documentation for details +on which functions and arguments are supported. + +#### Promises + +Issuing SOAP functions is async (non-blocking), so you can actually send multiple RPC requests in parallel. +The web service will respond to each request with a return value. The order is not guaranteed. +Sending requests uses a [Promise](https://github.com/reactphp/promise)-based interface that makes it easy to react to when a request is *fulfilled* +(i.e. either successfully resolved or rejected with an error): + +```php +$proxy->demo()->then( + function ($response) { + // response received for demo function + }, + function (Exception $e) { + // an error occured while executing the request + } +}); +``` + +#### Cancellation + +The returned Promise is implemented in such a way that it can be cancelled +when it is still pending. +Cancelling a pending promise will reject its value with an Exception and +clean up any underlying resources. + +```php +$promise = $proxy->demo(); + +$loop->addTimer(2.0, function () use ($promise) { + $promise->cancel(); +}); +``` + +#### Timeouts + +This library uses a very efficient HTTP implementation, so most SOAP requests +should usually be completed in mere milliseconds. However, when sending SOAP +requests over an unreliable network (the internet), there are a number of things +that can go wrong and may cause the request to fail after a time. As such, +timeouts are handled by the underlying HTTP library and this library respects +PHP's `default_socket_timeout` setting (default 60s) as a timeout for sending the +outgoing SOAP request and waiting for a successful response and will otherwise +cancel the pending request and reject its value with an Exception. + +Note that this timeout value covers creating the underlying transport connection, +sending the SOAP request, waiting for the remote service to process the request +and receiving the full SOAP response. To pass a custom timeout value, you can +assign the underlying [`timeout` option](https://github.com/clue/reactphp/http#timeouts) +like this: + +```php +$browser = new React\Http\Browser($loop); +$browser = $browser->withOptions(array( + 'timeout' => 10.0 +)); + +$client = new Clue\React\Soap\Client($browser, $wsdl); +$proxy = new Clue\React\Soap\Proxy($client); + +$proxy->demo()->then(function ($response) { + // response received within 10 seconds maximum + var_dump($response); +}); +``` + +Similarly, you can use a negative timeout value to not apply a timeout at all +or use a `null` value to restore the default handling. Note that the underlying +connection may still impose a different timeout value. See also the underlying +[`timeout` option](https://github.com/clue/reactphp/http#timeouts) for more details. + +## Install + +The recommended way to install this library is [through Composer](https://getcomposer.org). +[New to Composer?](https://getcomposer.org/doc/00-intro.md) + +This project follows [SemVer](https://semver.org/). +This will install the latest supported version: + +```bash +$ composer require clue/soap-react:^2.0 +``` + +See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. + +This project aims to run on any platform and thus only requires `ext-soap` and +supports running on PHP 7.1+. + +## Tests + +To run the test suite, you first need to clone this repo and then install all +dependencies [through Composer](https://getcomposer.org): + +```bash +$ composer install +``` + +To run the test suite, go to the project root and run: + +```bash +$ php vendor/bin/phpunit +``` + +The test suite also contains a number of functional integration tests that rely +on a stable internet connection. +If you do not want to run these, they can simply be skipped like this: + +```bash +$ php vendor/bin/phpunit --exclude-group internet +``` + +## License + +This project is released under the permissive [MIT license](LICENSE). + +> Did you know that I offer custom development services and issuing invoices for + sponsorships of releases and for contributions? Contact me (@clue) for details. diff --git a/vendor/clue/soap-react/composer.json b/vendor/clue/soap-react/composer.json new file mode 100644 index 0000000..c2a918e --- /dev/null +++ b/vendor/clue/soap-react/composer.json @@ -0,0 +1,29 @@ +{ + "name": "clue/soap-react", + "description": "Simple, async SOAP webservice client library, built on top of ReactPHP", + "keywords": ["SOAP", "SoapClient", "WebService", "WSDL", "ReactPHP"], + "homepage": "https://github.com/clue/reactphp-soap", + "license": "MIT", + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "autoload": { + "psr-4": { "Clue\\React\\Soap\\": "src/" } + }, + "autoload-dev": { + "psr-4": { "Clue\\Tests\\React\\Soap\\": "tests/" } + }, + "require": { + "php": ">=7.1", + "react/http": "^1.0", + "react/promise": "^2.1 || ^1.2", + "ext-soap": "*" + }, + "require-dev": { + "clue/block-react": "^1.0", + "phpunit/phpunit": "^9.3 || ^7.5" + } +} diff --git a/vendor/clue/soap-react/src/Client.php b/vendor/clue/soap-react/src/Client.php new file mode 100644 index 0000000..dda7b98 --- /dev/null +++ b/vendor/clue/soap-react/src/Client.php @@ -0,0 +1,326 @@ +<?php + +namespace Clue\React\Soap; + +use Clue\React\Soap\Protocol\ClientDecoder; +use Clue\React\Soap\Protocol\ClientEncoder; +use Psr\Http\Message\ResponseInterface; +use React\Http\Browser; +use React\Promise\Deferred; +use React\Promise\PromiseInterface; + +/** + * The `Client` class is responsible for communication with the remote SOAP + * WebService server. + * + * It requires a [`Browser`](https://github.com/reactphp/http#browser) object + * bound to the main [`EventLoop`](https://github.com/reactphp/event-loop#usage) + * in order to handle async requests, the WSDL file contents and an optional + * array of SOAP options: + * + * ```php + * $loop = React\EventLoop\Factory::create(); + * $browser = new React\Http\Browser($loop); + * + * $wsdl = '<?xml …'; + * $options = array(); + * + * $client = new Clue\React\Soap\Client($browser, $wsdl, $options); + * ``` + * + * If you need custom connector settings (DNS resolution, TLS parameters, timeouts, + * proxy servers etc.), you can explicitly pass a custom instance of the + * [`ConnectorInterface`](https://github.com/reactphp/socket#connectorinterface) + * to the [`Browser`](https://github.com/clue/reactphp/http#browser) instance: + * + * ```php + * $connector = new React\Socket\Connector($loop, array( + * 'dns' => '127.0.0.1', + * 'tcp' => array( + * 'bindto' => '192.168.10.1:0' + * ), + * 'tls' => array( + * 'verify_peer' => false, + * 'verify_peer_name' => false + * ) + * )); + * + * $browser = new React\Http\Browser($loop, $connector); + * $client = new Clue\React\Soap\Client($browser, $wsdl); + * ``` + * + * The `Client` works similar to PHP's `SoapClient` (which it uses under the + * hood), but leaves you the responsibility to load the WSDL file. This allows + * you to use local WSDL files, WSDL files from a cache or the most common form, + * downloading the WSDL file contents from an URL through the `Browser`: + * + * ```php + * $browser = new React\Http\Browser($loop); + * + * $browser->get($url)->then( + * function (Psr\Http\Message\ResponseInterface $response) use ($browser) { + * // WSDL file is ready, create client + * $client = new Clue\React\Soap\Client($browser, (string)$response->getBody()); + * + * // do something… + * }, + * function (Exception $e) { + * // an error occured while trying to download the WSDL + * } + * ); + * ``` + * + * The `Client` constructor loads the given WSDL file contents into memory and + * parses its definition. If the given WSDL file is invalid and can not be + * parsed, this will throw a `SoapFault`: + * + * ```php + * try { + * $client = new Clue\React\Soap\Client($browser, $wsdl); + * } catch (SoapFault $e) { + * echo 'Error: ' . $e->getMessage() . PHP_EOL; + * } + * ``` + * + * > Note that if you have an old version of `ext-xdebug` < 2.7 loaded, this may + * halt with a fatal error instead of throwing a `SoapFault`. It is not + * recommended to use this extension in production, so this should only ever + * affect test environments. + * + * The `Client` constructor accepts an array of options. All given options will + * be passed through to the underlying `SoapClient`. However, not all options + * make sense in this async implementation and as such may not have the desired + * effect. See also [`SoapClient`](https://www.php.net/manual/en/soapclient.soapclient.php) + * documentation for more details. + * + * If working in WSDL mode, the `$options` parameter is optional. If working in + * non-WSDL mode, the WSDL parameter must be set to `null` and the options + * parameter must contain the `location` and `uri` options, where `location` is + * the URL of the SOAP server to send the request to, and `uri` is the target + * namespace of the SOAP service: + * + * ```php + * $client = new Clue\React\Soap\Client($browser, null, array( + * 'location' => 'http://example.com', + * 'uri' => 'http://ping.example.com', + * )); + * ``` + * + * Similarly, if working in WSDL mode, the `location` option can be used to + * explicitly overwrite the URL of the SOAP server to send the request to: + * + * ```php + * $client = new Clue\React\Soap\Client($browser, $wsdl, array( + * 'location' => 'http://example.com' + * )); + * ``` + * + * You can use the `soap_version` option to change from the default SOAP 1.1 to + * use SOAP 1.2 instead: + * + * ```php + * $client = new Clue\React\Soap\Client($browser, $wsdl, array( + * 'soap_version' => SOAP_1_2 + * )); + * ``` + * + * You can use the `classmap` option to map certain WSDL types to PHP classes + * like this: + * + * ```php + * $client = new Clue\React\Soap\Client($browser, $wsdl, array( + * 'classmap' => array( + * 'getBankResponseType' => BankResponse::class + * ) + * )); + * ``` + * + * The `proxy_host` option (and family) is not supported by this library. As an + * alternative, you can configure the given `$browser` instance to use an + * [HTTP proxy server](https://github.com/clue/reactphp/http#http-proxy). + * If you find any other option is missing or not supported here, PRs are much + * appreciated! + * + * All public methods of the `Client` are considered *advanced usage*. + * If you want to call RPC functions, see below for the [`Proxy`](#proxy) class. + */ +class Client +{ + private $browser; + private $encoder; + private $decoder; + + /** + * Instantiate a new SOAP client for the given WSDL contents. + * + * @param Browser $browser + * @param string|null $wsdlContents + * @param array $options + */ + public function __construct(Browser $browser, ?string $wsdlContents, array $options = array()) + { + $wsdl = $wsdlContents !== null ? 'data://text/plain;base64,' . base64_encode($wsdlContents) : null; + + // Accept HTTP responses with error status codes as valid responses. + // This is done in order to process these error responses through the normal SOAP decoder. + // Additionally, we explicitly limit number of redirects to zero because following redirects makes little sense + // because it transforms the POST request to a GET one and hence loses the SOAP request body. + $browser = $browser->withRejectErrorResponse(false); + $browser = $browser->withFollowRedirects(0); + + $this->browser = $browser; + $this->encoder = new ClientEncoder($wsdl, $options); + $this->decoder = new ClientDecoder($wsdl, $options); + } + + /** + * Queue the given function to be sent via SOAP and wait for a response from the remote web service. + * + * ```php + * // advanced usage, see Proxy for recommended alternative + * $promise = $client->soapCall('ping', array('hello', 42)); + * ``` + * + * Note: This is considered *advanced usage*, you may want to look into using the [`Proxy`](#proxy) instead. + * + * ```php + * $proxy = new Clue\React\Soap\Proxy($client); + * $promise = $proxy->ping('hello', 42); + * ``` + * + * @param string $name + * @param mixed[] $args + * @return PromiseInterface Returns a Promise<mixed, Exception> + */ + public function soapCall(string $name, array $args): PromiseInterface + { + try { + $request = $this->encoder->encode($name, $args); + } catch (\Exception $e) { + $deferred = new Deferred(); + $deferred->reject($e); + return $deferred->promise(); + } + + $decoder = $this->decoder; + + return $this->browser->request( + $request->getMethod(), + (string) $request->getUri(), + $request->getHeaders(), + (string) $request->getBody() + )->then( + function (ResponseInterface $response) use ($decoder, $name) { + // HTTP response received => decode results for this function call + return $decoder->decode($name, (string)$response->getBody()); + } + ); + } + + /** + * Returns an array of functions defined in the WSDL. + * + * It returns the equivalent of PHP's + * [`SoapClient::__getFunctions()`](https://www.php.net/manual/en/soapclient.getfunctions.php). + * In non-WSDL mode, this method returns `null`. + * + * @return string[]|null + */ + public function getFunctions(): ?array + { + return $this->encoder->__getFunctions(); + } + + /** + * Returns an array of types defined in the WSDL. + * + * It returns the equivalent of PHP's + * [`SoapClient::__getTypes()`](https://www.php.net/manual/en/soapclient.gettypes.php). + * In non-WSDL mode, this method returns `null`. + * + * @return string[]|null + */ + public function getTypes(): ?array + { + return $this->encoder->__getTypes(); + } + + /** + * Returns the location (URI) of the given webservice `$function`. + * + * Note that this is not to be confused with the WSDL file location. + * A WSDL file can contain any number of function definitions. + * It's very common that all of these functions use the same location definition. + * However, technically each function can potentially use a different location. + * + * The `$function` parameter should be a string with the the SOAP function name. + * See also [`getFunctions()`](#getfunctions) for a list of all available functions. + * + * ```php + * assert('http://example.com/soap/service' === $client->getLocation('echo')); + * ``` + * + * For easier access, this function also accepts a numeric function index. + * It then uses [`getFunctions()`](#getfunctions) internally to get the function + * name for the given index. + * This is particularly useful for the very common case where all functions use the + * same location and accessing the first location is sufficient. + * + * ```php + * assert('http://example.com/soap/service' === $client->getLocation(0)); + * ``` + * + * When the `location` option has been set in the `Client` constructor + * (such as when in non-WSDL mode) or via the `withLocation()` method, this + * method returns the value of the given location. + * + * Passing a `$function` not defined in the WSDL file will throw a `SoapFault`. + * + * @param string|int $function + * @return string + * @throws \SoapFault if given function does not exist + * @see self::getFunctions() + */ + public function getLocation($function): string + { + if (is_int($function)) { + $functions = $this->getFunctions(); + if (isset($functions[$function]) && preg_match('/^\w+ (\w+)\(/', $functions[$function], $match)) { + $function = $match[1]; + } + } + + // encode request for given $function + return (string)$this->encoder->encode($function, array())->getUri(); + } + + /** + * Returns a new `Client` with the updated location (URI) for all functions. + * + * Note that this is not to be confused with the WSDL file location. + * A WSDL file can contain any number of function definitions. + * It's very common that all of these functions use the same location definition. + * However, technically each function can potentially use a different location. + * + * ```php + * $client = $client->withLocation('http://example.com/soap'); + * + * assert('http://example.com/soap' === $client->getLocation('echo')); + * ``` + * + * As an alternative to this method, you can also set the `location` option + * in the `Client` constructor (such as when in non-WSDL mode). + * + * @param string $location + * @return self + * @see self::getLocation() + */ + public function withLocation(string $location): self + { + $client = clone $this; + $client->encoder = clone $this->encoder; + $client->encoder->__setLocation($location); + + return $client; + } +} diff --git a/vendor/clue/soap-react/src/Protocol/ClientDecoder.php b/vendor/clue/soap-react/src/Protocol/ClientDecoder.php new file mode 100644 index 0000000..a4d7912 --- /dev/null +++ b/vendor/clue/soap-react/src/Protocol/ClientDecoder.php @@ -0,0 +1,51 @@ +<?php + +namespace Clue\React\Soap\Protocol; + +/** + * @internal + */ +final class ClientDecoder extends \SoapClient +{ + private $response = null; + + /** + * Decodes the SOAP response / return value from the given SOAP envelope (HTTP response body) + * + * @param string $function + * @param string $response + * @return mixed + * @throws \SoapFault if response indicates a fault (error condition) or is invalid + */ + public function decode(string $function, string $response) + { + // Temporarily save response internally for further processing + $this->response = $response; + + // Let's pretend we just invoked the given SOAP function. + // This won't actually invoke anything (see `__doRequest()`), but this + // requires a valid function name to match its definition in the WSDL. + // Internally, simply use the injected response to parse its results. + $ret = $this->__soapCall($function, array()); + $this->response = null; + + return $ret; + } + + /** + * Overwrites the internal request logic to parse the response + * + * By overwriting this method, we can skip the actual request sending logic + * and still use the internal parsing logic by injecting the response as + * the return code in this method. This will implicitly be invoked by the + * call to `pseudoCall()` in the above `decode()` method. + * + * @see \SoapClient::__doRequest() + */ + public function __doRequest($request, $location, $action, $version, $one_way = 0) + { + // the actual result doesn't actually matter, just return the given result + // this will be processed internally and will return the parsed result + return $this->response; + } +} diff --git a/vendor/clue/soap-react/src/Protocol/ClientEncoder.php b/vendor/clue/soap-react/src/Protocol/ClientEncoder.php new file mode 100644 index 0000000..8b065b9 --- /dev/null +++ b/vendor/clue/soap-react/src/Protocol/ClientEncoder.php @@ -0,0 +1,69 @@ +<?php + +namespace Clue\React\Soap\Protocol; + +use Psr\Http\Message\RequestInterface; +use RingCentral\Psr7\Request; + +/** + * @internal + */ +final class ClientEncoder extends \SoapClient +{ + private $request = null; + + /** + * Encodes the given RPC function name and arguments as a SOAP request + * + * @param string $name + * @param array $args + * @return RequestInterface + * @throws \SoapFault if request is invalid according to WSDL + */ + public function encode(string $name, array $args): RequestInterface + { + $this->__soapCall($name, $args); + + $request = $this->request; + $this->request = null; + + return $request; + } + + /** + * Overwrites the internal request logic to build the request message + * + * By overwriting this method, we can skip the actual request sending logic + * and still use the internal request serializing logic by accessing the + * given `$request` parameter and building our custom request object from + * it. We skip/ignore its parsing logic by returing an empty response here. + * This will implicitly be invoked by the call to `__soapCall()` in the + * above `encode()` method. + * + * @see \SoapClient::__doRequest() + */ + public function __doRequest($request, $location, $action, $version, $one_way = 0) + { + $headers = array(); + if ($version === SOAP_1_1) { + $headers = array( + 'SOAPAction' => $action, + 'Content-Type' => 'text/xml; charset=utf-8' + ); + } elseif ($version === SOAP_1_2) { + $headers = array( + 'Content-Type' => 'application/soap+xml; charset=utf-8; action=' . $action + ); + } + + $this->request = new Request( + 'POST', + (string)$location, + $headers, + (string)$request + ); + + // do not actually block here, just pretend we're done... + return ''; + } +} diff --git a/vendor/clue/soap-react/src/Proxy.php b/vendor/clue/soap-react/src/Proxy.php new file mode 100644 index 0000000..9c1fd11 --- /dev/null +++ b/vendor/clue/soap-react/src/Proxy.php @@ -0,0 +1,50 @@ +<?php + +namespace Clue\React\Soap; + +use React\Promise\PromiseInterface; + +/** + * The `Proxy` class wraps an existing [`Client`](#client) instance in order to ease calling + * SOAP functions. + * + * ```php + * $proxy = new Clue\React\Soap\Proxy($client); + * ``` + * + * Each and every method call to the `Proxy` class will be sent via SOAP. + * + * ```php + * $proxy->myMethod($myArg1, $myArg2)->then(function ($response) { + * // result received + * }); + * ``` + * + * Please refer to your WSDL or its accompanying documentation for details + * on which functions and arguments are supported. + * + * > Note that this class is called "Proxy" because it will forward (proxy) all + * method calls to the actual SOAP service via the underlying + * [`Client::soapCall()`](#soapcall) method. This is not to be confused with + * using a proxy server. See [`Client`](#client) documentation for more + * details on how to use an HTTP proxy server. + */ +final class Proxy +{ + private $client; + + public function __construct(Client $client) + { + $this->client = $client; + } + + /** + * @param string $name + * @param mixed[] $args + * @return PromiseInterface + */ + public function __call(string $name, array $args): PromiseInterface + { + return $this->client->soapCall($name, $args); + } +} |