SoapClient large refactoring & tests update
This commit is contained in:
parent
00ddf149b0
commit
aee034791e
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
/vendor/
|
||||
composer.lock
|
||||
phpunit.xml
|
||||
.idea/
|
||||
|
102
README.md
102
README.md
@ -1,35 +1,36 @@
|
||||
# BeSimpleSoap
|
||||
|
||||
Build SOAP and WSDL based web services
|
||||
Build SOAP and WSDL based web services.
|
||||
This fork from 2017 is a refactored version that fixes a lot of errors and provides
|
||||
better APi, more robust, stable and modern codebase.
|
||||
See [How to use](#how-to-use) that will help you to understand the magic.
|
||||
|
||||
# Components
|
||||
|
||||
BeSimpleSoap consists of five components ...
|
||||
|
||||
## BeSimpleSoapBundle
|
||||
|
||||
The BeSimpleSoapBundle is a Symfony2 bundle to build WSDL and SOAP based web services.
|
||||
For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapBundle/README.md).
|
||||
|
||||
## BeSimpleSoapClient
|
||||
|
||||
The BeSimpleSoapClient is a component that extends the native PHP SoapClient with further features like SwA, MTOM and WS-Security.
|
||||
For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapClient/README.md).
|
||||
|
||||
## BeSimpleSoapCommon
|
||||
|
||||
The BeSimpleSoapCommon component contains functionylity shared by both the server and client implementations.
|
||||
For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapCommon/README.md).
|
||||
|
||||
**Refactored** BeSimpleSoapClient is a component that extends the native PHP SoapClient with further features like SwA and WS-Security.
|
||||
|
||||
## BeSimpleSoapServer
|
||||
|
||||
The BeSimpleSoapServer is a component that extends the native PHP SoapServer with further features like SwA, MTOM and WS-Security.
|
||||
For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapServer/README.md).
|
||||
**Refactored** BeSimpleSoapServer is a component that extends the native PHP SoapServer with further features like SwA and WS-Security.
|
||||
|
||||
## BeSimpleSoapCommon
|
||||
|
||||
**Refactored** BeSimpleSoapCommon component contains functionality shared by both the server and client implementations.
|
||||
|
||||
## BeSimpleSoapWsdl
|
||||
|
||||
For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapWsdl/README.md).
|
||||
Currently **unsupported!** For further information see the [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapWsdl/README.md).
|
||||
|
||||
## BeSimpleSoapBundle
|
||||
|
||||
Currently **unsupported!**
|
||||
The BeSimpleSoapBundle is a Symfony2 bundle to build WSDL and SOAP based web services.
|
||||
For further information see the the original [README](https://github.com/BeSimple/BeSimpleSoap/blob/master/src/BeSimple/SoapBundle/README.md).
|
||||
*May not work properly since the Symfony libraries were removed.*
|
||||
|
||||
# Installation
|
||||
|
||||
@ -54,3 +55,70 @@ Now you are ready to install the library:
|
||||
```sh
|
||||
php /usr/local/bin/composer.phar install
|
||||
```
|
||||
|
||||
# How to use
|
||||
|
||||
You can investigate the unit tests in order to get a clue.
|
||||
Forget about associative arrays, multiple extension and silent errors!
|
||||
|
||||
```
|
||||
// unit tests for soap client
|
||||
BeSimple\SoapClient\Tests\SoapClientBuilderTest
|
||||
// unit tests for soap server
|
||||
BeSimple\SoapServer\Tests\SoapServerBuilderTest
|
||||
```
|
||||
|
||||
## Small example of soap client call
|
||||
|
||||
```php
|
||||
$soapClientBuilder = new SoapClientBuilder();
|
||||
$soapClient = $soapClientBuilder->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults('http://path/to/wsdlfile.wsdl')
|
||||
);
|
||||
$myRequest = new MyRequest();
|
||||
$myRequest->attribute = 'string value';
|
||||
$soapResponse = $soapClient->soapCall('myMethod', [$myRequest]);
|
||||
|
||||
var_dump($soapResponse); // Contains Response, Attachments
|
||||
```
|
||||
|
||||
### Something wrong?!
|
||||
Turn on the tracking and catch `SoapFaultWithTracingData` exception to get some sweets :)
|
||||
|
||||
```php
|
||||
try {
|
||||
$soapResponse = $soapClient->soapCall('GetUKLocationByCounty', [$getUKLocationByCountyRequest]);
|
||||
} catch (SoapFaultWithTracingData $fault) {
|
||||
var_dump($fault->getSoapResponseTracingData()->getLastRequest());
|
||||
}
|
||||
```
|
||||
|
||||
## Small example of soap server handling
|
||||
|
||||
Starting a SOAP server is a bit more complex.
|
||||
I would suggest you to inspect SoapServer unit tests to get complete image.
|
||||
But don't be scared too much, you just need to create a DummyService that will
|
||||
handle your client SOAP calls.
|
||||
|
||||
```php
|
||||
$dummyService = new DummyService();
|
||||
$classMap = new ClassMap();
|
||||
foreach ($dummyService->getClassMap() as $type => $className) {
|
||||
$classMap->add($type, $className);
|
||||
}
|
||||
$soapServerBuilder = new SoapServerBuilder();
|
||||
$soapServerOptions = SoapServerOptionsBuilder::createWithDefaults($dummyService);
|
||||
$soapOptions = SoapOptionsBuilder::createWithClassMap($dummyService->getWsdlPath(), $classMap);
|
||||
$soapServer = $soapServerBuilder->build($soapServerOptions, $soapOptions);
|
||||
|
||||
$request = $soapServer->createRequest(
|
||||
$dummyService->getEndpoint(),
|
||||
'DummyService.dummyServiceMethod',
|
||||
'text/xml;charset=UTF-8',
|
||||
'<your><soap><request><here /></request></soap></your>'
|
||||
);
|
||||
$response = $soapServer->handleRequest($request);
|
||||
|
||||
var_dump($response); // Contains Response, Attachments
|
||||
```
|
||||
|
2
cache/.gitignore
vendored
Normal file
2
cache/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
@ -19,16 +19,14 @@
|
||||
},
|
||||
{
|
||||
"name": "Petr Bechyně",
|
||||
"email": "petr.bechyne@vodafone.com"
|
||||
"email": "mail@petrbechyne.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"php": ">=5.3.0|>=7.0",
|
||||
"ext-soap": "*",
|
||||
"ext-curl": "*",
|
||||
"ass/xmlsecurity": "~1.0",
|
||||
"symfony/framework-bundle": "~2.6|~3.0",
|
||||
"symfony/twig-bundle": "~2.6|~3.0",
|
||||
"zendframework/zend-mime": "2.1.*"
|
||||
},
|
||||
"replace": {
|
||||
@ -41,8 +39,7 @@
|
||||
"require-dev": {
|
||||
"ext-mcrypt": "*",
|
||||
"mikey179/vfsStream": "~1.0",
|
||||
"symfony/filesystem": "~2.3",
|
||||
"symfony/process": "~2.3"
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": { "BeSimple\\": "src/" }
|
||||
|
1349
composer.lock
generated
Normal file
1349
composer.lock
generated
Normal file
@ -0,0 +1,1349 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "7601f1ec280c086361e1deaf021f8ca1",
|
||||
"content-hash": "59372f34124af17d5c35938dfffc6075",
|
||||
"packages": [
|
||||
{
|
||||
"name": "ass/xmlsecurity",
|
||||
"version": "v1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aschamberger/XmlSecurity.git",
|
||||
"reference": "c8976519ebbf6e4d953cd781d09df44b7f65fbb8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aschamberger/XmlSecurity/zipball/c8976519ebbf6e4d953cd781d09df44b7f65fbb8",
|
||||
"reference": "c8976519ebbf6e4d953cd781d09df44b7f65fbb8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"lib-openssl": ">=0.9.0",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"satooshi/php-coveralls": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mcrypt": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"ass\\XmlSecurity": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Robert Richards",
|
||||
"email": "rrichards@cdatazone.org"
|
||||
},
|
||||
{
|
||||
"name": "Andreas Schamberger",
|
||||
"email": "mail@andreass.net"
|
||||
}
|
||||
],
|
||||
"description": "The XmlSecurity library is written in PHP for working with XML Encryption and Signatures",
|
||||
"homepage": "https://github.com/aschamberger/XmlSecurity",
|
||||
"keywords": [
|
||||
"encryption",
|
||||
"security",
|
||||
"signature",
|
||||
"xml"
|
||||
],
|
||||
"time": "2015-05-31 10:10:35"
|
||||
},
|
||||
{
|
||||
"name": "zendframework/zend-mime",
|
||||
"version": "2.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zendframework/zend-mime.git",
|
||||
"reference": "066d6eecff586a7fb10e8907c032beaf1a9d6104"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zendframework/zend-mime/zipball/066d6eecff586a7fb10e8907c032beaf1a9d6104",
|
||||
"reference": "066d6eecff586a7fb10e8907c032beaf1a9d6104",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"zendframework/zend-stdlib": "self.version"
|
||||
},
|
||||
"require-dev": {
|
||||
"fabpot/php-cs-fixer": "1.7.*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"satooshi/php-coveralls": "dev-master",
|
||||
"zendframework/zend-mail": "self.version"
|
||||
},
|
||||
"suggest": {
|
||||
"zendframework/zend-mail": "Zend\\Mail component"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev",
|
||||
"dev-develop": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Zend\\Mime\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"homepage": "https://github.com/zendframework/zend-mime",
|
||||
"keywords": [
|
||||
"mime",
|
||||
"zf2"
|
||||
],
|
||||
"time": "2013-04-17 13:32:54"
|
||||
},
|
||||
{
|
||||
"name": "zendframework/zend-stdlib",
|
||||
"version": "2.1.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/zendframework/zend-stdlib.git",
|
||||
"reference": "0027339961ad3d49f91ee092e23f7269c18cb470"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/zendframework/zend-stdlib/zipball/0027339961ad3d49f91ee092e23f7269c18cb470",
|
||||
"reference": "0027339961ad3d49f91ee092e23f7269c18cb470",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"fabpot/php-cs-fixer": "1.7.*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"satooshi/php-coveralls": "dev-master",
|
||||
"zendframework/zend-eventmanager": "self.version",
|
||||
"zendframework/zend-filter": "self.version",
|
||||
"zendframework/zend-serializer": "self.version",
|
||||
"zendframework/zend-servicemanager": "self.version"
|
||||
},
|
||||
"suggest": {
|
||||
"pecl-weakref": "Implementation of weak references for Stdlib\\CallbackHandler",
|
||||
"zendframework/zend-eventmanager": "To support aggregate hydrator usage",
|
||||
"zendframework/zend-filter": "To support naming strategy hydrator usage",
|
||||
"zendframework/zend-serializer": "Zend\\Serializer component",
|
||||
"zendframework/zend-servicemanager": "To support hydrator plugin manager usage"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev",
|
||||
"dev-develop": "2.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Zend\\Stdlib\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"homepage": "https://github.com/zendframework/zend-stdlib",
|
||||
"keywords": [
|
||||
"stdlib",
|
||||
"zf2"
|
||||
],
|
||||
"time": "2013-04-17 13:32:54"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "doctrine/instantiator",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/instantiator.git",
|
||||
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d",
|
||||
"reference": "8e884e78f9f0eb1329e445619e04456e64d8051d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3,<8.0-DEV"
|
||||
},
|
||||
"require-dev": {
|
||||
"athletic/athletic": "~0.1.8",
|
||||
"ext-pdo": "*",
|
||||
"ext-phar": "*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"squizlabs/php_codesniffer": "~2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Pivetta",
|
||||
"email": "ocramius@gmail.com",
|
||||
"homepage": "http://ocramius.github.com/"
|
||||
}
|
||||
],
|
||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
||||
"homepage": "https://github.com/doctrine/instantiator",
|
||||
"keywords": [
|
||||
"constructor",
|
||||
"instantiate"
|
||||
],
|
||||
"time": "2015-06-14 21:17:01"
|
||||
},
|
||||
{
|
||||
"name": "mikey179/vfsStream",
|
||||
"version": "v1.6.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mikey179/vfsStream.git",
|
||||
"reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mikey179/vfsStream/zipball/0247f57b2245e8ad2e689d7cee754b45fbabd592",
|
||||
"reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"org\\bovigo\\vfs\\": "src/main/php"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Frank Kleine",
|
||||
"homepage": "http://frankkleine.de/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Virtual file system to mock the real file system in unit tests.",
|
||||
"homepage": "http://vfs.bovigo.org/",
|
||||
"time": "2016-07-18 14:02:57"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
"version": "1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionCommon.git",
|
||||
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
|
||||
"reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jaap van Otterdijk",
|
||||
"email": "opensource@ijaap.nl"
|
||||
}
|
||||
],
|
||||
"description": "Common reflection classes used by phpdocumentor to reflect the code structure",
|
||||
"homepage": "http://www.phpdoc.org",
|
||||
"keywords": [
|
||||
"FQSEN",
|
||||
"phpDocumentor",
|
||||
"phpdoc",
|
||||
"reflection",
|
||||
"static analysis"
|
||||
],
|
||||
"time": "2015-12-27 11:43:31"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
"version": "3.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
||||
"reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e",
|
||||
"reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5",
|
||||
"phpdocumentor/reflection-common": "^1.0@dev",
|
||||
"phpdocumentor/type-resolver": "^0.2.0",
|
||||
"webmozart/assert": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"phpunit/phpunit": "^4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mike van Riel",
|
||||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2016-09-30 07:12:33"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
"version": "0.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpDocumentor/TypeResolver.git",
|
||||
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
|
||||
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5",
|
||||
"phpdocumentor/reflection-common": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^0.9.4",
|
||||
"phpunit/phpunit": "^5.2||^4.8.24"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"phpDocumentor\\Reflection\\": [
|
||||
"src/"
|
||||
]
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mike van Riel",
|
||||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"time": "2016-11-25 06:54:22"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "v1.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
|
||||
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
|
||||
"sebastian/comparator": "^1.1",
|
||||
"sebastian/recursion-context": "^1.0|^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpspec/phpspec": "^2.0",
|
||||
"phpunit/phpunit": "^4.8 || ^5.6.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Prophecy\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Konstantin Kudryashov",
|
||||
"email": "ever.zet@gmail.com",
|
||||
"homepage": "http://everzet.com"
|
||||
},
|
||||
{
|
||||
"name": "Marcello Duarte",
|
||||
"email": "marcello.duarte@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Highly opinionated mocking framework for PHP 5.3+",
|
||||
"homepage": "https://github.com/phpspec/prophecy",
|
||||
"keywords": [
|
||||
"Double",
|
||||
"Dummy",
|
||||
"fake",
|
||||
"mock",
|
||||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2016-11-21 14:58:47"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "2.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979",
|
||||
"reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-file-iterator": "~1.3",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-token-stream": "~1.3",
|
||||
"sebastian/environment": "^1.3.2",
|
||||
"sebastian/version": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-xdebug": ">=2.1.4",
|
||||
"phpunit/phpunit": "~4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-dom": "*",
|
||||
"ext-xdebug": ">=2.2.1",
|
||||
"ext-xmlwriter": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-code-coverage",
|
||||
"keywords": [
|
||||
"coverage",
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-10-06 15:47:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
"version": "1.4.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
|
||||
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
|
||||
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "FilterIterator implementation that filters files based on a list of suffixes.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
|
||||
"keywords": [
|
||||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2016-10-03 07:40:28"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
"version": "1.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-text-template.git",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Simple template engine.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-text-template/",
|
||||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"time": "2015-06-21 13:50:34"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
"version": "1.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-timer.git",
|
||||
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260",
|
||||
"reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4|~5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Utility class for timing",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-timer/",
|
||||
"keywords": [
|
||||
"timer"
|
||||
],
|
||||
"time": "2016-05-12 18:03:57"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
"version": "1.4.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
|
||||
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
|
||||
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-tokenizer": "*",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Wrapper around PHP's tokenizer extension.",
|
||||
"homepage": "https://github.com/sebastianbergmann/php-token-stream/",
|
||||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2016-11-15 14:06:22"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "4.8.34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7eb45205d27edd94bd2b3614085ea158bd1e2bca",
|
||||
"reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-json": "*",
|
||||
"ext-pcre": "*",
|
||||
"ext-reflection": "*",
|
||||
"ext-spl": "*",
|
||||
"php": ">=5.3.3",
|
||||
"phpspec/prophecy": "^1.3.1",
|
||||
"phpunit/php-code-coverage": "~2.1",
|
||||
"phpunit/php-file-iterator": "~1.4",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"phpunit/php-timer": "^1.0.6",
|
||||
"phpunit/phpunit-mock-objects": "~2.3",
|
||||
"sebastian/comparator": "~1.2.2",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/environment": "~1.3",
|
||||
"sebastian/exporter": "~1.2",
|
||||
"sebastian/global-state": "~1.0",
|
||||
"sebastian/version": "~1.0",
|
||||
"symfony/yaml": "~2.1|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"phpunit/php-invoker": "~1.1"
|
||||
},
|
||||
"bin": [
|
||||
"phpunit"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.8.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "The PHP Unit Testing framework.",
|
||||
"homepage": "https://phpunit.de/",
|
||||
"keywords": [
|
||||
"phpunit",
|
||||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2017-01-26 16:15:36"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
"version": "2.3.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
|
||||
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983",
|
||||
"reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": ">=5.3.3",
|
||||
"phpunit/php-text-template": "~1.2",
|
||||
"sebastian/exporter": "~1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-soap": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sb@sebastian-bergmann.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Mock Object library for PHPUnit",
|
||||
"homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
|
||||
"keywords": [
|
||||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2015-10-02 06:51:40"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
"version": "1.2.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||
"reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
|
||||
"reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/exporter": "~1.2 || ~2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Volker Dusch",
|
||||
"email": "github@wallbash.com"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@2bepublished.at"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Provides the functionality to compare PHP values for equality",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/comparator",
|
||||
"keywords": [
|
||||
"comparator",
|
||||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2017-01-29 09:50:25"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "1.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
|
||||
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.4-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kore Nordmann",
|
||||
"email": "mail@kore-nordmann.de"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Diff implementation",
|
||||
"homepage": "https://github.com/sebastianbergmann/diff",
|
||||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"time": "2015-12-08 07:14:41"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
"version": "1.3.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/environment.git",
|
||||
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
|
||||
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.3 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8 || ^5.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Provides functionality to handle HHVM/PHP environments",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/environment",
|
||||
"keywords": [
|
||||
"Xdebug",
|
||||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2016-08-18 05:49:44"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/exporter.git",
|
||||
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
|
||||
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"sebastian/recursion-context": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-mbstring": "*",
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Volker Dusch",
|
||||
"email": "github@wallbash.com"
|
||||
},
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@2bepublished.at"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
},
|
||||
{
|
||||
"name": "Adam Harvey",
|
||||
"email": "aharvey@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Provides the functionality to export PHP variables for visualization",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/exporter",
|
||||
"keywords": [
|
||||
"export",
|
||||
"exporter"
|
||||
],
|
||||
"time": "2016-06-17 09:04:28"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
"version": "1.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/global-state.git",
|
||||
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4",
|
||||
"reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.2"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-uopz": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
}
|
||||
],
|
||||
"description": "Snapshotting of global state",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/global-state",
|
||||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
"time": "2015-10-12 03:26:01"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/recursion-context",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/recursion-context.git",
|
||||
"reference": "913401df809e99e4f47b27cdd781f4a258d58791"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
|
||||
"reference": "913401df809e99e4f47b27cdd781f4a258d58791",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jeff Welch",
|
||||
"email": "whatthejeff@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de"
|
||||
},
|
||||
{
|
||||
"name": "Adam Harvey",
|
||||
"email": "aharvey@php.net"
|
||||
}
|
||||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"time": "2015-11-11 19:50:13"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
"version": "1.0.6",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/version.git",
|
||||
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
|
||||
"reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sebastian Bergmann",
|
||||
"email": "sebastian@phpunit.de",
|
||||
"role": "lead"
|
||||
}
|
||||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"time": "2015-06-21 13:59:46"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "50eadbd7926e31842893c957eca362b21592a97d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/50eadbd7926e31842893c957eca362b21592a97d",
|
||||
"reference": "50eadbd7926e31842893c957eca362b21592a97d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/console": "~2.8|~3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/console": "For validating YAML files using the lint command"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "3.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-01-03 13:51:32"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/webmozart/assert.git",
|
||||
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
|
||||
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3.3 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.6",
|
||||
"sebastian/version": "^1.0.1"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webmozart\\Assert\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Bernhard Schussek",
|
||||
"email": "bschussek@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Assertions to validate method input/output with nice error messages.",
|
||||
"keywords": [
|
||||
"assert",
|
||||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2016-11-23 20:04:58"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=5.3.0|>=7.0",
|
||||
"ext-soap": "*",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"platform-dev": {
|
||||
"ext-mcrypt": "*"
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
stderr="true"
|
||||
bootstrap="vendor/autoload.php"
|
||||
>
|
||||
|
||||
@ -18,17 +19,8 @@
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="BeSimpleSoap Test Suite">
|
||||
<directory>./src/BeSimple/*/Tests/</directory>
|
||||
<file>src/BeSimple/SoapClient/Tests/SoapClientBuilderTest.php</file>
|
||||
<file>src/BeSimple/SoapServer/Tests/SoapServerBuilderTest.php</file>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./src/BeSimple/</directory>
|
||||
<exclude>
|
||||
<directory>./src/BeSimple/*/Tests</directory>
|
||||
<directory>./src/BeSimple/*/Resources</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
|
@ -13,27 +13,45 @@
|
||||
namespace BeSimple\SoapBundle;
|
||||
|
||||
use BeSimple\SoapCommon\Cache as BaseCache;
|
||||
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
class Cache
|
||||
{
|
||||
public function __construct($cacheDisabled, $type, $directory, $lifetime = null, $limit = null)
|
||||
public function __construct(SoapOptions $soapOptions)
|
||||
{
|
||||
$isEnabled = (Boolean) $cacheDisabled ? BaseCache::DISABLED : BaseCache::ENABLED;
|
||||
if ($soapOptions->isWsdlCached()) {
|
||||
$isEnabled = (bool)$soapOptions->isWsdlCached() ? BaseCache::ENABLED : BaseCache::DISABLED;
|
||||
|
||||
BaseCache::setEnabled($isEnabled);
|
||||
|
||||
BaseCache::setType($type);
|
||||
BaseCache::setDirectory($directory);
|
||||
|
||||
if (null !== $lifetime) {
|
||||
BaseCache::setLifetime($lifetime);
|
||||
BaseCache::setEnabled($isEnabled);
|
||||
BaseCache::setType($soapOptions->getWsdlCacheType());
|
||||
BaseCache::setDirectory($soapOptions->getWsdlCacheDir());
|
||||
} else {
|
||||
BaseCache::setEnabled(BaseCache::DISABLED);
|
||||
BaseCache::setType(SoapOptions::SOAP_CACHE_TYPE_NONE);
|
||||
BaseCache::setDirectory(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $limit) {
|
||||
BaseCache::setLimit($limit);
|
||||
public function validateSettings(SoapOptions $soapOptions)
|
||||
{
|
||||
if ($soapOptions->isWsdlCached()) {
|
||||
if (BaseCache::isEnabled() !== true) {
|
||||
throw new Exception('WSDL cache could not be set');
|
||||
}
|
||||
if ($soapOptions->getWsdlCacheType() !== (int)BaseCache::getType()) {
|
||||
throw new Exception('WSDL cache type could not be set, ini settings is: '.BaseCache::getType());
|
||||
}
|
||||
if ($soapOptions->getWsdlCacheDir() !== BaseCache::getDirectory()) {
|
||||
throw new Exception('WSDL cache dir could not be set, real dir is: '.BaseCache::getDirectory());
|
||||
}
|
||||
} else {
|
||||
if (BaseCache::isEnabled() !== false) {
|
||||
throw new Exception('WSDL cache could not be turned off');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
36
src/BeSimple/SoapBundle/Soap/SoapAttachmentList.php
Normal file
36
src/BeSimple/SoapBundle/Soap/SoapAttachmentList.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapBundle\Soap;
|
||||
|
||||
class SoapAttachmentList
|
||||
{
|
||||
private $soapAttachments;
|
||||
|
||||
/**
|
||||
* @param SoapAttachment[] $soapAttachments
|
||||
*/
|
||||
public function __construct(array $soapAttachments = [])
|
||||
{
|
||||
$this->soapAttachments = $soapAttachments;
|
||||
}
|
||||
|
||||
public function hasSoapAttachments()
|
||||
{
|
||||
return $this->soapAttachments !== null && count($this->soapAttachments) > 0;
|
||||
}
|
||||
|
||||
public function getSoapAttachments()
|
||||
{
|
||||
return $this->soapAttachments;
|
||||
}
|
||||
|
||||
public function getSoapAttachmentIds()
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($this->getSoapAttachments() as $soapAttachment) {
|
||||
$ids[] = $soapAttachment->getId();
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
@ -13,6 +13,8 @@ namespace BeSimple\SoapBundle;
|
||||
|
||||
use BeSimple\SoapBundle\ServiceBinding\ServiceBinder;
|
||||
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
|
||||
use BeSimple\SoapCommon\SoapOptionsBuilder;
|
||||
use BeSimple\SoapServer\SoapServerOptionsBuilder;
|
||||
use BeSimple\SoapWsdl\Dumper\Dumper;
|
||||
use BeSimple\SoapServer\SoapServerBuilder;
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
@ -102,15 +104,14 @@ class WebServiceContext
|
||||
public function getServerBuilder()
|
||||
{
|
||||
if (null === $this->serverBuilder) {
|
||||
$this->serverBuilder = SoapServerBuilder::createWithDefaults()
|
||||
->withWsdl($this->getWsdlFile())
|
||||
->withClassmap($this->getServiceDefinition()->getTypeRepository()->getClassmap())
|
||||
->withTypeConverters($this->converters)
|
||||
;
|
||||
|
||||
if (null !== $this->options['cache_type']) {
|
||||
$this->serverBuilder->withWsdlCache($this->options['cache_type']);
|
||||
}
|
||||
$soapServerBuilder = new SoapServerBuilder();
|
||||
$this->serverBuilder = $soapServerBuilder->build(
|
||||
SoapServerOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithClassMap(
|
||||
$this->getWsdlFile(),
|
||||
$this->getServiceDefinition()->getTypeRepository()->getClassmap()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->serverBuilder;
|
||||
|
@ -1,336 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the BeSimpleSoapClient.
|
||||
*
|
||||
* (c) Christian Kerl <christian-kerl@web.de>
|
||||
* (c) Francis Besset <francis.besset@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
/**
|
||||
* cURL wrapper class for doing HTTP requests that uses the soap class options.
|
||||
*
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
*/
|
||||
class Curl
|
||||
{
|
||||
/**
|
||||
* HTTP User Agent.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const USER_AGENT = 'PHP-SOAP/\BeSimple\SoapClient';
|
||||
|
||||
/**
|
||||
* Curl resource.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $ch;
|
||||
|
||||
/**
|
||||
* Maximum number of location headers to follow.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $followLocationMaxRedirects;
|
||||
|
||||
/**
|
||||
* Request response data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $response;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $options Options array from SoapClient constructor
|
||||
* @param int $followLocationMaxRedirects Redirection limit for Location header
|
||||
*/
|
||||
public function __construct(array $options = [], $followLocationMaxRedirects = 10)
|
||||
{
|
||||
// set the default HTTP user agent
|
||||
if (!isset($options['user_agent'])) {
|
||||
$options['user_agent'] = self::USER_AGENT;
|
||||
}
|
||||
$this->followLocationMaxRedirects = $followLocationMaxRedirects;
|
||||
|
||||
// make http request
|
||||
$this->ch = curl_init();
|
||||
$curlOptions = array(
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_FAILONERROR => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_USERAGENT => $options['user_agent'],
|
||||
CURLINFO_HEADER_OUT => true,
|
||||
);
|
||||
curl_setopt_array($this->ch, $curlOptions);
|
||||
if (isset($options['compression']) && !($options['compression'] & SOAP_COMPRESSION_ACCEPT)) {
|
||||
curl_setopt($this->ch, CURLOPT_ENCODING, 'identity');
|
||||
}
|
||||
if (isset($options['connection_timeout'])) {
|
||||
curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, $options['connection_timeout']);
|
||||
}
|
||||
|
||||
if (isset($options['proxy_host'])) {
|
||||
if (false !== $options['proxy_host']) {
|
||||
$proxyHost = $options['proxy_host'].(isset($options['proxy_port']) ? $options['proxy_port'] : 8080);
|
||||
} else {
|
||||
$proxyHost = false;
|
||||
}
|
||||
|
||||
curl_setopt($this->ch, CURLOPT_PROXY, $proxyHost);
|
||||
|
||||
if (false !== $proxyHost && isset($options['proxy_login'])) {
|
||||
curl_setopt($this->ch, CURLOPT_PROXYUSERPWD, $options['proxy_login'].':'.$options['proxy_password']);
|
||||
|
||||
if (isset($options['proxy_auth'])) {
|
||||
curl_setopt($this->ch, CURLOPT_PROXYAUTH, $options['proxy_auth']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['login'])) {
|
||||
curl_setopt($this->ch, CURLOPT_HTTPAUTH, isset($options['extra_options']['http_auth']) ? $options['extra_options']['http_auth'] : CURLAUTH_ANY);
|
||||
curl_setopt($this->ch, CURLOPT_USERPWD, $options['login'].':'.$options['password']);
|
||||
}
|
||||
if (isset($options['local_cert'])) {
|
||||
curl_setopt($this->ch, CURLOPT_SSLCERT, $options['local_cert']);
|
||||
curl_setopt($this->ch, CURLOPT_SSLCERTPASSWD, $options['passphrase']);
|
||||
}
|
||||
if (isset($options['ca_info'])) {
|
||||
curl_setopt($this->ch, CURLOPT_CAINFO, $options['ca_info']);
|
||||
}
|
||||
if (isset($options['ca_path'])) {
|
||||
curl_setopt($this->ch, CURLOPT_CAPATH, $options['ca_path']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
curl_close($this->ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute HTTP request.
|
||||
* Returns true if request was successful.
|
||||
*
|
||||
* @param string $location HTTP location
|
||||
* @param string $request Request body
|
||||
* @param array $requestHeaders Request header strings
|
||||
* @param array $requestOptions An array of request options
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exec($location, $request = null, $requestHeaders = array(), $requestOptions = array())
|
||||
{
|
||||
curl_setopt($this->ch, CURLOPT_URL, $location);
|
||||
|
||||
if (!is_null($request)) {
|
||||
curl_setopt($this->ch, CURLOPT_POST, true);
|
||||
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $request);
|
||||
}
|
||||
|
||||
if (count($requestHeaders) > 0) {
|
||||
curl_setopt($this->ch, CURLOPT_HTTPHEADER, $requestHeaders);
|
||||
}
|
||||
|
||||
if (count($requestOptions) > 0) {
|
||||
curl_setopt_array($this->ch, $requestOptions);
|
||||
}
|
||||
|
||||
$this->response = $this->execManualRedirect();
|
||||
|
||||
return ($this->response === false) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom curl_exec wrapper that allows to follow redirects when specific
|
||||
* http response code is set. SOAP only allows 307.
|
||||
*
|
||||
* @param int $redirects Current redirection count
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function execManualRedirect($redirects = 0)
|
||||
{
|
||||
if ($redirects > $this->followLocationMaxRedirects) {
|
||||
|
||||
// TODO Redirection limit reached, aborting
|
||||
return false;
|
||||
}
|
||||
curl_setopt($this->ch, CURLOPT_HEADER, true);
|
||||
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
|
||||
$response = curl_exec($this->ch);
|
||||
$httpResponseCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
|
||||
if ($httpResponseCode == 307) {
|
||||
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($response, 0, $headerSize);
|
||||
$matches = array();
|
||||
preg_match('/Location:(.*?)\n/', $header, $matches);
|
||||
$url = trim(array_pop($matches));
|
||||
// @parse_url to suppress E_WARNING for invalid urls
|
||||
if (($url = @parse_url($url)) !== false) {
|
||||
$lastUrl = parse_url(curl_getinfo($this->ch, CURLINFO_EFFECTIVE_URL));
|
||||
if (!isset($url['scheme'])) {
|
||||
$url['scheme'] = $lastUrl['scheme'];
|
||||
}
|
||||
if (!isset($url['host'])) {
|
||||
$url['host'] = $lastUrl['host'];
|
||||
}
|
||||
if (!isset($url['path'])) {
|
||||
$url['path'] = $lastUrl['path'];
|
||||
}
|
||||
$newUrl = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query'] ? '?' . $url['query'] : '');
|
||||
curl_setopt($this->ch, CURLOPT_URL, $newUrl);
|
||||
|
||||
return $this->execManualRedirect($redirects++);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error code mapping from cURL error codes to PHP ext/soap error messages
|
||||
* (where applicable)
|
||||
*
|
||||
* http://curl.haxx.se/libcurl/c/libcurl-errors.html
|
||||
*
|
||||
* @return array(int=>string)
|
||||
*/
|
||||
protected function getErrorCodeMapping()
|
||||
{
|
||||
return array(
|
||||
1 => 'Unknown protocol. Only http and https are allowed.', //CURLE_UNSUPPORTED_PROTOCOL
|
||||
3 => 'Unable to parse URL', //CURLE_URL_MALFORMAT
|
||||
5 => 'Could not connect to host', //CURLE_COULDNT_RESOLVE_PROXY
|
||||
6 => 'Could not connect to host', //CURLE_COULDNT_RESOLVE_HOST
|
||||
7 => 'Could not connect to host', //CURLE_COULDNT_CONNECT
|
||||
9 => 'Could not connect to host', //CURLE_REMOTE_ACCESS_DENIED
|
||||
28 => 'Failed Sending HTTP SOAP request', //CURLE_OPERATION_TIMEDOUT
|
||||
35 => 'Could not connect to host', //CURLE_SSL_CONNECT_ERROR
|
||||
41 => 'Can\'t uncompress compressed response', //CURLE_FUNCTION_NOT_FOUND
|
||||
51 => 'Could not connect to host', //CURLE_PEER_FAILED_VERIFICATION
|
||||
52 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_GOT_NOTHING
|
||||
53 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_NOTFOUND
|
||||
54 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_SETFAILED
|
||||
55 => 'Failed Sending HTTP SOAP request', //CURLE_SEND_ERROR
|
||||
56 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_RECV_ERROR
|
||||
58 => 'Could not connect to host', //CURLE_SSL_CERTPROBLEM
|
||||
59 => 'Could not connect to host', //CURLE_SSL_CIPHER
|
||||
60 => 'Could not connect to host', //CURLE_SSL_CACERT
|
||||
61 => 'Unknown Content-Encoding', //CURLE_BAD_CONTENT_ENCODING
|
||||
65 => 'Failed Sending HTTP SOAP request', //CURLE_SEND_FAIL_REWIND
|
||||
66 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_INITFAILED
|
||||
67 => 'Could not connect to host', //CURLE_LOGIN_DENIED
|
||||
77 => 'Could not connect to host', //CURLE_SSL_CACERT_BADFILE
|
||||
80 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_SSL_SHUTDOWN_FAILED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the curl error message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getErrorMessage()
|
||||
{
|
||||
$errorCodeMapping = $this->getErrorCodeMapping();
|
||||
$errorNumber = curl_errno($this->ch);
|
||||
if (isset($errorCodeMapping[$errorNumber])) {
|
||||
|
||||
return $errorCodeMapping[$errorNumber];
|
||||
}
|
||||
|
||||
return curl_error($this->ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the request headers as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRequestHeaders()
|
||||
{
|
||||
return curl_getinfo($this->ch, CURLINFO_HEADER_OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the whole response (including headers) as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response body as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseBody()
|
||||
{
|
||||
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
|
||||
|
||||
return substr($this->response, $headerSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response content type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseContentType()
|
||||
{
|
||||
return curl_getinfo($this->ch, CURLINFO_CONTENT_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response headers as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseHeaders()
|
||||
{
|
||||
$headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE);
|
||||
|
||||
return substr($this->response, 0, $headerSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response http status code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseStatusCode()
|
||||
{
|
||||
return curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the response http status message.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getResponseStatusMessage()
|
||||
{
|
||||
preg_match('/HTTP\/(1\.[0-1]+) ([0-9]{3}) (.*)/', $this->response, $matches);
|
||||
|
||||
return trim(array_pop($matches));
|
||||
}
|
||||
}
|
234
src/BeSimple/SoapClient/Curl/Curl.php
Normal file
234
src/BeSimple/SoapClient/Curl/Curl.php
Normal file
@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl;
|
||||
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationBasicOptions;
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationDigestOptions;
|
||||
use BeSimple\SoapClient\Curl\Http\SslCertificateOptions;
|
||||
use Exception;
|
||||
|
||||
class Curl
|
||||
{
|
||||
const CURL_SUCCESS = true;
|
||||
const CURL_FAILED = false;
|
||||
|
||||
private $curlSession;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @param CurlOptions $options
|
||||
*/
|
||||
public function __construct(CurlOptions $options)
|
||||
{
|
||||
$this->curlSession = $this->acquireNewCurlSession($options);
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
$this->closeCurlSession($this->curlSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $location HTTP location
|
||||
* @param string $request Request body
|
||||
* @param array $requestHeaders Request header strings
|
||||
* @return CurlResponse
|
||||
*/
|
||||
public function executeCurlWithCachedSession($location, $request = null, $requestHeaders = [])
|
||||
{
|
||||
return $this->executeCurlSession($this->curlSession, $this->options, $location, $request, $requestHeaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CurlOptions $options
|
||||
* @param string $location HTTP location
|
||||
* @param string $request Request body
|
||||
* @param array $requestHeaders Request header strings
|
||||
* @return CurlResponse
|
||||
*/
|
||||
public function executeCurl(CurlOptions $options, $location, $request = null, $requestHeaders = [])
|
||||
{
|
||||
$curlSession = $this->acquireNewCurlSession($options);
|
||||
$curlResponse = $this->executeCurlSession($curlSession, $options, $location, $request, $requestHeaders);
|
||||
$this->closeCurlSession($curlSession);
|
||||
|
||||
return $curlResponse;
|
||||
}
|
||||
|
||||
private function acquireNewCurlSession(CurlOptions $options)
|
||||
{
|
||||
$curlSession = curl_init();
|
||||
curl_setopt_array($curlSession, [
|
||||
CURLOPT_ENCODING => '',
|
||||
CURLOPT_SSL_VERIFYPEER => false,
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_HEADER => true,
|
||||
CURLOPT_USERAGENT => $options->getUserAgent(),
|
||||
CURLINFO_HEADER_OUT => true,
|
||||
CURLOPT_CONNECTTIMEOUT => $options->getConnectionTimeout()
|
||||
]);
|
||||
|
||||
return $curlSession;
|
||||
}
|
||||
|
||||
private function closeCurlSession($curlSession)
|
||||
{
|
||||
curl_close($curlSession);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $curlSession Result of curl_init() handle
|
||||
* @param CurlOptions $options
|
||||
* @param string $location HTTP location
|
||||
* @param string $request Request body
|
||||
* @param array $requestHeaders Request header strings
|
||||
* @return CurlResponse
|
||||
*/
|
||||
private function executeCurlSession($curlSession, CurlOptions $options, $location, $request = null, $requestHeaders = [])
|
||||
{
|
||||
curl_setopt($curlSession, CURLOPT_URL, $location);
|
||||
curl_setopt($curlSession, CURLOPT_HEADER, true);
|
||||
curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
|
||||
if (!is_null($request)) {
|
||||
curl_setopt($curlSession, CURLOPT_POST, true);
|
||||
curl_setopt($curlSession, CURLOPT_POSTFIELDS, $request);
|
||||
} else {
|
||||
curl_setopt($curlSession, CURLOPT_POST, false);
|
||||
}
|
||||
if (count($requestHeaders) > 0) {
|
||||
curl_setopt($curlSession, CURLOPT_HTTPHEADER, $requestHeaders);
|
||||
}
|
||||
if (!$options->getSoapCompression() & SOAP_COMPRESSION_ACCEPT) {
|
||||
curl_setopt($curlSession, CURLOPT_ENCODING, 'identity');
|
||||
}
|
||||
if ($options->hasProxy()) {
|
||||
$proxyHost = $options->getProxy()->getHost() . $options->getProxy()->getPort();
|
||||
curl_setopt($curlSession, CURLOPT_PROXY, $proxyHost);
|
||||
if ($options->getProxy()->hasCredentials()) {
|
||||
curl_setopt($curlSession, CURLOPT_PROXYUSERPWD, $options->getProxy()->getLogin() . ':' . $options->getProxy()->getPassword());
|
||||
if ($options->getProxy()->hasAuthenticationType()) {
|
||||
curl_setopt($curlSession, CURLOPT_PROXYAUTH, $options->getProxy()->getAuthenticationType());
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($options->hasHttpAuthentication()) {
|
||||
if ($options->hasHttpAuthenticationBasic()) {
|
||||
/** @var HttpAuthenticationBasicOptions $httpAuthenticationBasic */
|
||||
$httpAuthenticationBasic = $options->getHttpAuthentication();
|
||||
curl_setopt($curlSession, CURLOPT_HTTPAUTH, $httpAuthenticationBasic->getAuthenticationType());
|
||||
curl_setopt($curlSession, CURLOPT_USERPWD, $httpAuthenticationBasic->getUsername() . ':' . $httpAuthenticationBasic->getPassword());
|
||||
} else if ($options->hasHttpAuthenticationDigest()) {
|
||||
/** @var HttpAuthenticationDigestOptions $httpAuthenticationDigest */
|
||||
$httpAuthenticationDigest = $options->getHttpAuthentication();
|
||||
curl_setopt($curlSession, CURLOPT_HTTPAUTH, $httpAuthenticationDigest->getAuthenticationType());
|
||||
} else {
|
||||
throw new Exception('Unresolved authentication type: '.get_class($options->getHttpAuthentication()));
|
||||
}
|
||||
}
|
||||
if ($options->hasSslCertificateOptions()) {
|
||||
$sslCertificateOptions = $options->getSslCertificateOptions();
|
||||
curl_setopt($curlSession, CURLOPT_SSLCERT, $sslCertificateOptions->getCertificateLocalPath());
|
||||
if ($sslCertificateOptions->hasCertificatePassPhrase()) {
|
||||
curl_setopt($curlSession, CURLOPT_SSLCERTPASSWD, $sslCertificateOptions->getCertificatePassPhrase());
|
||||
}
|
||||
if ($sslCertificateOptions->hasCertificateAuthorityInfo()) {
|
||||
curl_setopt($curlSession, CURLOPT_CAINFO, $sslCertificateOptions->getCertificateAuthorityInfo());
|
||||
}
|
||||
if ($sslCertificateOptions->hasCertificateAuthorityPath()) {
|
||||
curl_setopt($curlSession, CURLOPT_CAPATH, $sslCertificateOptions->hasCertificateAuthorityPath());
|
||||
}
|
||||
}
|
||||
$executeSoapCallResponse = $this->executeHttpCall($curlSession, $options);
|
||||
|
||||
$httpRequestHeadersAsString = curl_getinfo($curlSession, CURLINFO_HEADER_OUT);
|
||||
$headerSize = curl_getinfo($curlSession, CURLINFO_HEADER_SIZE);
|
||||
$httpResponseCode = curl_getinfo($curlSession, CURLINFO_HTTP_CODE);
|
||||
$httpResponseContentType = curl_getinfo($curlSession, CURLINFO_CONTENT_TYPE);;
|
||||
preg_match('/HTTP\/(1\.[0-1]+) ([0-9]{3}) (.*)/', $executeSoapCallResponse, $httpResponseMessages);
|
||||
$httpResponseMessage = trim(array_pop($httpResponseMessages));
|
||||
$curlErrorMessage = sprintf(
|
||||
'Curl error "%s" with message: %s occurred while connecting to %s',
|
||||
curl_errno($curlSession),
|
||||
curl_error($curlSession),
|
||||
$location
|
||||
);
|
||||
|
||||
if ($executeSoapCallResponse === false) {
|
||||
|
||||
return new CurlResponse(
|
||||
$httpRequestHeadersAsString,
|
||||
$httpResponseCode,
|
||||
$httpResponseMessage,
|
||||
$httpResponseContentType,
|
||||
self::CURL_FAILED,
|
||||
$curlErrorMessage
|
||||
);
|
||||
}
|
||||
|
||||
return new CurlResponse(
|
||||
$httpRequestHeadersAsString,
|
||||
$httpResponseCode,
|
||||
$httpResponseMessage,
|
||||
$httpResponseContentType,
|
||||
self::CURL_SUCCESS,
|
||||
null,
|
||||
substr($executeSoapCallResponse, 0, $headerSize),
|
||||
substr($executeSoapCallResponse, $headerSize)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom curl_exec wrapper that allows to follow redirects when specific
|
||||
* http response code is set. SOAP only allows 307.
|
||||
*
|
||||
* @param mixed $curlSession Result of curl_init() handle
|
||||
* @param CurlOptions $options
|
||||
* @param int $executedRedirects
|
||||
* @return string|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function executeHttpCall($curlSession, CurlOptions $options, $executedRedirects = 0)
|
||||
{
|
||||
if ($executedRedirects > $options->getFollowLocationMaxRedirects()) {
|
||||
throw new Exception('Cannot executeHttpCall - too many redirects: ' . $executedRedirects);
|
||||
}
|
||||
$curlExecResponse = curl_exec($curlSession);
|
||||
$httpResponseCode = curl_getinfo($curlSession, CURLINFO_HTTP_CODE);
|
||||
if ($httpResponseCode === 307) {
|
||||
$newUrl = $this->getRedirectUrlFromResponseHeaders($curlSession, $curlExecResponse);
|
||||
curl_setopt($curlSession, CURLOPT_URL, $newUrl);
|
||||
|
||||
return $this->executeHttpCall($curlSession, $options, ++$executedRedirects);
|
||||
}
|
||||
|
||||
return $curlExecResponse;
|
||||
}
|
||||
|
||||
private function getRedirectUrlFromResponseHeaders($curlSession, $curlExecResponse)
|
||||
{
|
||||
$curlExecResponseHeaders = substr($curlExecResponse, 0, curl_getinfo($curlSession, CURLINFO_HEADER_SIZE));
|
||||
$matches = [];
|
||||
preg_match('/Location:(.*?)\n/', $curlExecResponseHeaders, $matches);
|
||||
$url = trim(array_pop($matches));
|
||||
|
||||
if (($url = @parse_url($url)) !== false) {
|
||||
$lastUrl = parse_url(curl_getinfo($curlSession, CURLINFO_EFFECTIVE_URL));
|
||||
if (!isset($url['scheme'])) {
|
||||
$url['scheme'] = $lastUrl['scheme'];
|
||||
}
|
||||
if (!isset($url['host'])) {
|
||||
$url['host'] = $lastUrl['host'];
|
||||
}
|
||||
if (!isset($url['path'])) {
|
||||
$url['path'] = $lastUrl['path'];
|
||||
}
|
||||
|
||||
return $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query'] ? '?' . $url['query'] : '');
|
||||
}
|
||||
|
||||
throw new Exception('Cannot parse WSDL url redirect: ' . $url);
|
||||
}
|
||||
}
|
126
src/BeSimple/SoapClient/Curl/CurlOptions.php
Normal file
126
src/BeSimple/SoapClient/Curl/CurlOptions.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl;
|
||||
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationDigestOptions;
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationInterface;
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationBasicOptions;
|
||||
use BeSimple\SoapClient\Curl\Http\SslCertificateOptions;
|
||||
use BeSimple\SoapClient\SoapServerProxy\SoapServerProxy;
|
||||
|
||||
class CurlOptions
|
||||
{
|
||||
const DEFAULT_USER_AGENT = 'BeSimpleSoap';
|
||||
const SOAP_COMPRESSION_NONE = null;
|
||||
const SOAP_COMPRESSION_GZIP = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP;
|
||||
const SOAP_COMPRESSION_DEFLATE = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE;
|
||||
|
||||
private $userAgent;
|
||||
private $followLocationMaxRedirects;
|
||||
private $soapCompression;
|
||||
private $connectionTimeout;
|
||||
private $proxy;
|
||||
private $httpAuthentication;
|
||||
private $sslCertificateOptions;
|
||||
|
||||
/**
|
||||
* @param string $userAgent
|
||||
* @param int $followLocationMaxRedirects
|
||||
* @param CurlOptions::SOAP_COMPRESSION_NONE|CurlOptions::SOAP_COMPRESSION_GZIP|CurlOptions::SOAP_COMPRESSION_DEFLATE $soapCompression
|
||||
* @param int $connectionTimeout
|
||||
* @param SoapServerProxy|null $proxy
|
||||
* @param HttpAuthenticationInterface|null $httpAuthentication
|
||||
* @param SslCertificateOptions|null $sslCertificateOptions
|
||||
*/
|
||||
public function __construct(
|
||||
$userAgent,
|
||||
$followLocationMaxRedirects,
|
||||
$soapCompression,
|
||||
$connectionTimeout,
|
||||
SoapServerProxy $proxy = null,
|
||||
HttpAuthenticationInterface $httpAuthentication = null,
|
||||
SslCertificateOptions $sslCertificateOptions = null
|
||||
) {
|
||||
$this->userAgent = $userAgent;
|
||||
$this->followLocationMaxRedirects = $followLocationMaxRedirects;
|
||||
$this->soapCompression = $soapCompression;
|
||||
$this->connectionTimeout = $connectionTimeout;
|
||||
$this->proxy = $proxy;
|
||||
$this->httpAuthentication = $httpAuthentication;
|
||||
$this->sslCertificateOptions = $sslCertificateOptions;
|
||||
}
|
||||
|
||||
public function getUserAgent()
|
||||
{
|
||||
return $this->userAgent;
|
||||
}
|
||||
|
||||
public function getFollowLocationMaxRedirects()
|
||||
{
|
||||
return $this->followLocationMaxRedirects;
|
||||
}
|
||||
|
||||
public function getSoapCompression()
|
||||
{
|
||||
return $this->soapCompression;
|
||||
}
|
||||
|
||||
public function getConnectionTimeout()
|
||||
{
|
||||
return $this->connectionTimeout;
|
||||
}
|
||||
|
||||
public function getProxy()
|
||||
{
|
||||
return $this->proxy;
|
||||
}
|
||||
|
||||
public function getHttpAuthentication()
|
||||
{
|
||||
return $this->httpAuthentication;
|
||||
}
|
||||
|
||||
public function getSslCertificateOptions()
|
||||
{
|
||||
return $this->sslCertificateOptions;
|
||||
}
|
||||
|
||||
public function hasProxy()
|
||||
{
|
||||
return $this->proxy !== null;
|
||||
}
|
||||
|
||||
public function hasHttpAuthentication()
|
||||
{
|
||||
return $this->httpAuthentication !== null;
|
||||
}
|
||||
|
||||
public function hasSslCertificateOptions()
|
||||
{
|
||||
return $this->sslCertificateOptions !== null;
|
||||
}
|
||||
|
||||
public function hasHttpAuthenticationBasic()
|
||||
{
|
||||
if ($this->hasHttpAuthentication()) {
|
||||
if ($this->getHttpAuthentication() instanceof HttpAuthenticationBasicOptions) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasHttpAuthenticationDigest()
|
||||
{
|
||||
if ($this->hasHttpAuthentication()) {
|
||||
if ($this->getHttpAuthentication() instanceof HttpAuthenticationDigestOptions) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
79
src/BeSimple/SoapClient/Curl/CurlOptionsBuilder.php
Normal file
79
src/BeSimple/SoapClient/Curl/CurlOptionsBuilder.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl;
|
||||
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationDigestOptions;
|
||||
use BeSimple\SoapClient\Curl\Http\SslCertificateOptions;
|
||||
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
|
||||
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationBasic;
|
||||
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationDigest;
|
||||
use BeSimple\SoapClient\Curl\Http\HttpAuthenticationBasicOptions;
|
||||
use Exception;
|
||||
|
||||
class CurlOptionsBuilder
|
||||
{
|
||||
const DEFAULT_MAX_REDIRECTS = 10;
|
||||
const DEFAULT_CONNECTION_TIMEOUT = 10;
|
||||
|
||||
public static function buildDefault()
|
||||
{
|
||||
return new CurlOptions(
|
||||
CurlOptions::DEFAULT_USER_AGENT,
|
||||
self::DEFAULT_MAX_REDIRECTS,
|
||||
CurlOptions::SOAP_COMPRESSION_NONE,
|
||||
self::DEFAULT_CONNECTION_TIMEOUT
|
||||
);
|
||||
}
|
||||
|
||||
public static function buildForSoapClient(SoapClientOptions $soapClientOptions)
|
||||
{
|
||||
return new CurlOptions(
|
||||
$soapClientOptions->getUserAgent(),
|
||||
self::DEFAULT_MAX_REDIRECTS,
|
||||
$soapClientOptions->getCompression(),
|
||||
self::DEFAULT_CONNECTION_TIMEOUT,
|
||||
$soapClientOptions->getProxy(),
|
||||
self::getHttpAuthOptions($soapClientOptions),
|
||||
self::getSslCertificateOptions($soapClientOptions)
|
||||
);
|
||||
}
|
||||
|
||||
private static function getHttpAuthOptions(SoapClientOptions $soapClientOptions)
|
||||
{
|
||||
if ($soapClientOptions->hasAuthentication()) {
|
||||
if ($soapClientOptions->hasAuthenticationBasic()) {
|
||||
/** @var SoapServerAuthenticationBasic $basicAuthentication */
|
||||
$basicAuthentication = $soapClientOptions->getAuthentication();
|
||||
|
||||
return new HttpAuthenticationBasicOptions(
|
||||
$basicAuthentication->getLogin(),
|
||||
$basicAuthentication->getPassword()
|
||||
);
|
||||
|
||||
} else if ($soapClientOptions->hasAuthenticationDigest()) {
|
||||
|
||||
return new HttpAuthenticationDigestOptions();
|
||||
|
||||
} else {
|
||||
throw new Exception('Unresolved authentication type: '.get_class($soapClientOptions->getAuthentication()));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static function getSslCertificateOptions(SoapClientOptions $soapClientOptions)
|
||||
{
|
||||
if ($soapClientOptions->hasAuthenticationDigest()) {
|
||||
/** @var SoapServerAuthenticationDigest $digestAuthentication */
|
||||
$digestAuthentication = $soapClientOptions->getAuthentication();
|
||||
|
||||
return new SslCertificateOptions(
|
||||
$digestAuthentication->getLocalCert(),
|
||||
$digestAuthentication->getPassPhrase()
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
100
src/BeSimple/SoapClient/Curl/CurlResponse.php
Normal file
100
src/BeSimple/SoapClient/Curl/CurlResponse.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl;
|
||||
|
||||
class CurlResponse
|
||||
{
|
||||
private $httpRequestHeaders;
|
||||
private $httpResponseStatusCode;
|
||||
private $httpResponseStatusMessage;
|
||||
private $httpResponseContentType;
|
||||
private $curlStatus;
|
||||
private $curlErrorMessage;
|
||||
private $responseHeader;
|
||||
private $responseBody;
|
||||
|
||||
public function __construct(
|
||||
$httpRequestHeaders,
|
||||
$httpResponseStatusCode,
|
||||
$httpResponseStatusMessage,
|
||||
$httpResponseContentType,
|
||||
$curlStatus,
|
||||
$curlErrorMessage = null,
|
||||
$responseHeader = null,
|
||||
$responseBody = null
|
||||
) {
|
||||
$this->httpRequestHeaders = $httpRequestHeaders;
|
||||
$this->httpResponseStatusCode = $httpResponseStatusCode;
|
||||
$this->httpResponseStatusMessage = $httpResponseStatusMessage;
|
||||
$this->httpResponseContentType = $httpResponseContentType;
|
||||
$this->curlStatus = $curlStatus;
|
||||
$this->curlErrorMessage = $curlErrorMessage;
|
||||
$this->responseHeader = $responseHeader;
|
||||
$this->responseBody = $responseBody;
|
||||
}
|
||||
|
||||
public function getHttpRequestHeaders()
|
||||
{
|
||||
return $this->httpRequestHeaders;
|
||||
}
|
||||
|
||||
public function getHttpResponseStatusCode()
|
||||
{
|
||||
return $this->httpResponseStatusCode;
|
||||
}
|
||||
|
||||
public function getHttpResponseStatusMessage()
|
||||
{
|
||||
return $this->httpResponseStatusMessage;
|
||||
}
|
||||
|
||||
public function getHttpResponseContentType()
|
||||
{
|
||||
return $this->httpResponseContentType;
|
||||
}
|
||||
|
||||
public function getCurlStatus()
|
||||
{
|
||||
return $this->curlStatus;
|
||||
}
|
||||
|
||||
public function curlStatusSuccess()
|
||||
{
|
||||
return $this->curlStatus === Curl::CURL_SUCCESS;
|
||||
}
|
||||
|
||||
public function curlStatusFailed()
|
||||
{
|
||||
return $this->curlStatus === Curl::CURL_FAILED;
|
||||
}
|
||||
|
||||
public function hasCurlErrorMessage()
|
||||
{
|
||||
return $this->curlErrorMessage !== null;
|
||||
}
|
||||
|
||||
public function getCurlErrorMessage()
|
||||
{
|
||||
return $this->curlErrorMessage;
|
||||
}
|
||||
|
||||
public function hasResponseHeader()
|
||||
{
|
||||
return $this->responseHeader !== null;
|
||||
}
|
||||
|
||||
public function getResponseHeader()
|
||||
{
|
||||
return $this->responseHeader;
|
||||
}
|
||||
|
||||
public function hasResponseBody()
|
||||
{
|
||||
return $this->responseBody !== null;
|
||||
}
|
||||
|
||||
public function getResponseBody()
|
||||
{
|
||||
return $this->responseBody;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl\Http;
|
||||
|
||||
class HttpAuthenticationBasicOptions implements HttpAuthenticationInterface
|
||||
{
|
||||
private $username;
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*/
|
||||
public function __construct($username, $password)
|
||||
{
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function getPassword()
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function getAuthenticationType()
|
||||
{
|
||||
return HttpAuthenticationInterface::AUTHENTICATION_TYPE_BASIC;
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl\Http;
|
||||
|
||||
class HttpAuthenticationDigestOptions implements HttpAuthenticationInterface
|
||||
{
|
||||
public function getAuthenticationType()
|
||||
{
|
||||
return HttpAuthenticationInterface::AUTHENTICATION_TYPE_DIGEST;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl\Http;
|
||||
|
||||
interface HttpAuthenticationInterface
|
||||
{
|
||||
const AUTHENTICATION_TYPE_ANY = CURLAUTH_ANY;
|
||||
const AUTHENTICATION_TYPE_BASIC = CURLAUTH_BASIC;
|
||||
const AUTHENTICATION_TYPE_DIGEST = CURLAUTH_DIGEST;
|
||||
|
||||
/**
|
||||
* @return string choice from self::AUTHENTICATION_TYPE_ANY|self::AUTHENTICATION_TYPE_BASIC|self::AUTHENTICATION_TYPE_DIGEST
|
||||
*/
|
||||
public function getAuthenticationType();
|
||||
}
|
64
src/BeSimple/SoapClient/Curl/Http/SslCertificateOptions.php
Normal file
64
src/BeSimple/SoapClient/Curl/Http/SslCertificateOptions.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Curl\Http;
|
||||
|
||||
class SslCertificateOptions
|
||||
{
|
||||
private $certificateLocalPath;
|
||||
private $certificatePassPhrase;
|
||||
private $certificateAuthorityInfo;
|
||||
private $certificateAuthorityPath;
|
||||
|
||||
/**
|
||||
* @param string $certificateLocalPath
|
||||
* @param string $certificatePassPhrase
|
||||
* @param string $certificateAuthorityInfo
|
||||
* @param string $certificateAuthorityPath
|
||||
*/
|
||||
public function __construct(
|
||||
$certificateLocalPath,
|
||||
$certificatePassPhrase = null,
|
||||
$certificateAuthorityInfo = null,
|
||||
$certificateAuthorityPath = null
|
||||
) {
|
||||
$this->certificateLocalPath = $certificateLocalPath;
|
||||
$this->certificatePassPhrase = $certificatePassPhrase;
|
||||
$this->certificateAuthorityInfo = $certificateAuthorityInfo;
|
||||
$this->certificateAuthorityPath = $certificateAuthorityPath;
|
||||
}
|
||||
|
||||
public function getCertificateLocalPath()
|
||||
{
|
||||
return $this->certificateLocalPath;
|
||||
}
|
||||
|
||||
public function getCertificatePassPhrase()
|
||||
{
|
||||
return $this->certificatePassPhrase;
|
||||
}
|
||||
|
||||
public function getCertificateAuthorityInfo()
|
||||
{
|
||||
return $this->certificateAuthorityInfo;
|
||||
}
|
||||
|
||||
public function getCertificateAuthorityPath()
|
||||
{
|
||||
return $this->certificateAuthorityPath;
|
||||
}
|
||||
|
||||
public function hasCertificatePassPhrase()
|
||||
{
|
||||
return $this->certificatePassPhrase !== null;
|
||||
}
|
||||
|
||||
public function hasCertificateAuthorityInfo()
|
||||
{
|
||||
return $this->certificateAuthorityInfo !== null;
|
||||
}
|
||||
|
||||
public function hasCertificateAuthorityPath()
|
||||
{
|
||||
return $this->certificateAuthorityPath !== null;
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ use BeSimple\SoapCommon\Mime\Part as MimePart;
|
||||
use BeSimple\SoapCommon\Mime\Part;
|
||||
use BeSimple\SoapCommon\SoapRequest;
|
||||
use BeSimple\SoapCommon\SoapRequestFilter;
|
||||
use BeSimple\SoapCommon\SoapResponse;
|
||||
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
|
||||
use BeSimple\SoapCommon\SoapResponseFilter;
|
||||
|
||||
/**
|
||||
@ -62,7 +62,7 @@ class MimeFilter implements SoapRequestFilter, SoapResponseFilter
|
||||
return $request;
|
||||
}
|
||||
|
||||
public function filterResponse(SoapResponse $response, $attachmentType)
|
||||
public function filterResponse(CommonSoapResponse $response, $attachmentType)
|
||||
{
|
||||
$multiPartMessage = MimeParser::parseMimeMessage(
|
||||
$response->getContent(),
|
||||
|
@ -12,10 +12,20 @@
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachmentList;
|
||||
use BeSimple\SoapClient\Curl\Curl;
|
||||
use BeSimple\SoapClient\Curl\CurlOptionsBuilder;
|
||||
use BeSimple\SoapClient\Curl\CurlResponse;
|
||||
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
|
||||
use BeSimple\SoapCommon\Fault\SoapFaultEnum;
|
||||
use BeSimple\SoapCommon\Mime\PartFactory;
|
||||
use BeSimple\SoapCommon\SoapKernel;
|
||||
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use BeSimple\SoapCommon\SoapRequest;
|
||||
use BeSimple\SoapCommon\SoapRequestFactory;
|
||||
use Exception;
|
||||
use SoapFault;
|
||||
|
||||
/**
|
||||
* Extended SoapClient that uses a a cURL wrapper for all underlying HTTP
|
||||
@ -24,73 +34,92 @@ use BeSimple\SoapCommon\SoapRequestFactory;
|
||||
* allows caching of all remote referenced items.
|
||||
*
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapClient extends \SoapClient
|
||||
{
|
||||
protected $soapVersion;
|
||||
protected $tracingEnabled;
|
||||
protected $soapClientOptions;
|
||||
protected $soapOptions;
|
||||
protected $curl;
|
||||
private $curl;
|
||||
|
||||
/**
|
||||
* Last request headers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $lastRequestHeaders = '';
|
||||
|
||||
/**
|
||||
* Last request.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $lastRequest = '';
|
||||
|
||||
/**
|
||||
* Last response headers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $lastResponseHeaders = '';
|
||||
|
||||
/**
|
||||
* Last response.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $lastResponse = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param SoapClientOptions $soapClientOptions
|
||||
* @param SoapOptions $soapOptions
|
||||
*/
|
||||
public function __construct(SoapClientOptions $soapClientOptions, SoapOptions $soapOptions)
|
||||
{
|
||||
$this->soapVersion = $soapOptions->getSoapVersion();
|
||||
$this->tracingEnabled = $soapClientOptions->getTrace();
|
||||
$this->soapClientOptions = $soapClientOptions;
|
||||
$this->soapOptions = $soapOptions;
|
||||
|
||||
// @todo: refactor SoapClient: do not use $options as array: refactor Curl
|
||||
$this->curl = new Curl($soapClientOptions->toArray());
|
||||
|
||||
$wsdlFile = $this->loadWsdl(
|
||||
$soapOptions->getWsdlFile(),
|
||||
$soapOptions->getWsdlCacheType()
|
||||
$this->curl = new Curl(
|
||||
CurlOptionsBuilder::buildForSoapClient($soapClientOptions)
|
||||
);
|
||||
|
||||
parent::__construct(
|
||||
$wsdlFile,
|
||||
$soapClientOptions->toArray() + $soapOptions->toArray()
|
||||
try {
|
||||
@parent::__construct(
|
||||
$this->loadWsdl(
|
||||
$this->curl,
|
||||
$soapOptions->getWsdlFile(),
|
||||
$soapOptions->getWsdlCacheType()
|
||||
),
|
||||
$soapClientOptions->toArray() + $soapOptions->toArray()
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
throw new SoapFault(
|
||||
SoapFaultEnum::SOAP_FAULT_SOAP_CLIENT_ERROR,
|
||||
'Could not create SoapClient instance with message: '.$e->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid using __call directly, it's deprecated even in \SoapClient.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public function __call($function_name, $arguments)
|
||||
{
|
||||
throw new Exception(
|
||||
'The __call method is deprecated. Use __soapCall/soapCall instead.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom request method to be able to modify the SOAP messages.
|
||||
* $oneWay parameter is not used at the moment.
|
||||
* Using __soapCall returns only response string, use soapCall instead.
|
||||
*
|
||||
* @param string $functionName
|
||||
* @param array $arguments
|
||||
* @param array|null $options
|
||||
* @param null $inputHeaders
|
||||
* @param array|null $outputHeaders
|
||||
* @return string
|
||||
*/
|
||||
public function __soapCall($functionName, $arguments, $options = null, $inputHeaders = null, &$outputHeaders = null)
|
||||
{
|
||||
return $this->soapCall($functionName, $arguments, $options, $inputHeaders, $outputHeaders)->getContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $functionName
|
||||
* @param array $arguments
|
||||
* @param array|null $options
|
||||
* @param SoapAttachment[] $soapAttachments
|
||||
* @param null $inputHeaders
|
||||
* @param array|null $outputHeaders
|
||||
* @return SoapResponse
|
||||
*/
|
||||
public function soapCall($functionName, array $arguments, array $soapAttachments = [], array $options = null, $inputHeaders = null, array &$outputHeaders = null)
|
||||
{
|
||||
ob_start();
|
||||
parent::__soapCall($functionName, $arguments, $options, $inputHeaders, $outputHeaders);
|
||||
$nativeSoapClientRequest = $this->mapNativeDataJsonToDto(ob_get_clean());
|
||||
|
||||
return $this->performSoapRequest(
|
||||
$nativeSoapClientRequest->request,
|
||||
$nativeSoapClientRequest->location,
|
||||
$nativeSoapClientRequest->action,
|
||||
$nativeSoapClientRequest->version,
|
||||
$soapAttachments
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not performing any HTTP requests, but it is getting data from SoapClient that are needed for this Client
|
||||
*
|
||||
* @param string $request Request string
|
||||
* @param string $location Location
|
||||
@ -102,44 +131,105 @@ class SoapClient extends \SoapClient
|
||||
*/
|
||||
public function __doRequest($request, $location, $action, $version, $oneWay = 0)
|
||||
{
|
||||
$soapRequest = $this->createSoapRequest($location, $action, $version, $request);
|
||||
$soapResponse = $this->getSoapResponseFromRequest($soapRequest);
|
||||
$soapClientNativeDataTransferObject = new SoapClientNativeDataTransferObject(
|
||||
$request,
|
||||
$location,
|
||||
$action,
|
||||
$version
|
||||
);
|
||||
echo json_encode($soapClientNativeDataTransferObject);
|
||||
|
||||
return $soapResponse->getContent();
|
||||
}
|
||||
|
||||
private function createSoapRequest($location, $action, $version, $request)
|
||||
{
|
||||
$soapRequest = SoapRequestFactory::create($location, $action, $version, $request);
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapKernel = new SoapKernel();
|
||||
$soapRequest = $soapKernel->filterRequest(
|
||||
$soapRequest,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
);
|
||||
}
|
||||
|
||||
return $soapRequest;
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the currently registered request filters on the request, performs
|
||||
* the HTTP request and runs the response filters.
|
||||
* Custom request method to be able to modify the SOAP messages.
|
||||
* $oneWay parameter is not used at the moment.
|
||||
*
|
||||
* @param SoapRequest $soapRequest SOAP request object
|
||||
* @param mixed $request Request object
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param int $version SOAP version
|
||||
* @param SoapAttachment[] $soapAttachments SOAP attachments array
|
||||
*
|
||||
* @return SoapResponse
|
||||
*/
|
||||
private function getSoapResponseFromRequest(SoapRequest $soapRequest)
|
||||
public function performSoapRequest($request, $location, $action, $version, array $soapAttachments = [])
|
||||
{
|
||||
$soapResponse = $this->performHttpSoapRequest($soapRequest);
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapKernel = new SoapKernel();
|
||||
$soapKernel->filterResponse($soapResponse, $this->getAttachmentFilters(), $this->soapOptions->getAttachmentType());
|
||||
$soapRequest = $this->createSoapRequest($location, $action, $version, $request, $soapAttachments);
|
||||
|
||||
return $this->performHttpSoapRequest($soapRequest);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public function __getLastRequestHeaders()
|
||||
{
|
||||
$this->checkTracing();
|
||||
|
||||
throw new Exception(
|
||||
'The __getLastRequestHeaders method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public function __getLastRequest()
|
||||
{
|
||||
$this->checkTracing();
|
||||
|
||||
throw new Exception(
|
||||
'The __getLastRequest method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public function __getLastResponseHeaders()
|
||||
{
|
||||
$this->checkTracing();
|
||||
|
||||
throw new Exception(
|
||||
'The __getLastResponseHeaders method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
|
||||
);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
public function __getLastResponse()
|
||||
{
|
||||
$this->checkTracing();
|
||||
|
||||
throw new Exception(
|
||||
'The __getLastResponse method is now deprecated. Use callSoapRequest instead and get the tracing information from SoapResponseTracingData.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param int $version SOAP version
|
||||
* @param string $request SOAP request body
|
||||
* @param SoapAttachment[] $soapAttachments array of SOAP attachments
|
||||
*
|
||||
* @return SoapRequest
|
||||
*/
|
||||
private function createSoapRequest($location, $action, $version, $request, array $soapAttachments = [])
|
||||
{
|
||||
$soapAttachmentList = new SoapAttachmentList($soapAttachments);
|
||||
$soapRequest = SoapRequestFactory::create($location, $action, $version, $request);
|
||||
if (count($soapAttachments) > 0) {
|
||||
if ($this->soapOptions->hasAttachments() === true) {
|
||||
$soapRequest->setAttachments(PartFactory::createAttachmentParts($soapAttachments));
|
||||
$soapRequest = SoapKernel::filterRequest(
|
||||
$soapRequest,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
);
|
||||
} else {
|
||||
throw new Exception(
|
||||
'Non SWA SoapClient cannot handle SOAP action '.$action.' with attachments: '.implode(', ', $soapAttachmentList->getSoapAttachmentIds())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $soapResponse;
|
||||
return $soapRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,147 +237,92 @@ class SoapClient extends \SoapClient
|
||||
*
|
||||
* @param SoapRequest $soapRequest SoapRequest object
|
||||
* @return SoapResponse
|
||||
* @throws SoapFault
|
||||
*/
|
||||
private function performHttpSoapRequest(SoapRequest $soapRequest)
|
||||
{
|
||||
// HTTP headers
|
||||
$soapVersion = $soapRequest->getVersion();
|
||||
$soapAction = $soapRequest->getAction();
|
||||
if (SOAP_1_1 === $soapVersion) {
|
||||
if ($soapRequest->getVersion() === SOAP_1_1) {
|
||||
$headers = [
|
||||
'Content-Type:' . $soapRequest->getContentType(),
|
||||
'SOAPAction: "' . $soapAction . '"',
|
||||
'SOAPAction: "' . $soapRequest->getAction() . '"',
|
||||
];
|
||||
} else {
|
||||
$headers = [
|
||||
'Content-Type:' . $soapRequest->getContentType() . '; action="' . $soapAction . '"',
|
||||
'Content-Type:' . $soapRequest->getContentType() . '; action="' . $soapRequest->getAction() . '"',
|
||||
];
|
||||
}
|
||||
|
||||
$location = $soapRequest->getLocation();
|
||||
$content = $soapRequest->getContent();
|
||||
|
||||
$headers = $this->filterRequestHeaders($soapRequest, $headers);
|
||||
|
||||
$options = $this->filterRequestOptions($soapRequest);
|
||||
|
||||
$responseSuccessful = $this->curl->exec(
|
||||
$location,
|
||||
$content,
|
||||
$headers,
|
||||
$options
|
||||
);
|
||||
|
||||
// tracing enabled: store last request header and body
|
||||
if ($this->tracingEnabled === true) {
|
||||
$this->lastRequestHeaders = $this->curl->getRequestHeaders();
|
||||
$this->lastRequest = $soapRequest->getContent();
|
||||
}
|
||||
// in case of an error while making the http request throw a soapFault
|
||||
if ($responseSuccessful === false) {
|
||||
// get error message from curl
|
||||
$faultstring = $this->curl->getErrorMessage();
|
||||
throw new \SoapFault('HTTP', $faultstring);
|
||||
}
|
||||
// tracing enabled: store last response header and body
|
||||
if ($this->tracingEnabled === true) {
|
||||
$this->lastResponseHeaders = $this->curl->getResponseHeaders();
|
||||
$this->lastResponse = $this->curl->getResponseBody();
|
||||
}
|
||||
// wrap response data in SoapResponse object
|
||||
$soapResponse = SoapResponse::create(
|
||||
$this->curl->getResponseBody(),
|
||||
$curlResponse = $this->curl->executeCurlWithCachedSession(
|
||||
$soapRequest->getLocation(),
|
||||
$soapRequest->getAction(),
|
||||
$soapRequest->getVersion(),
|
||||
$this->curl->getResponseContentType()
|
||||
$soapRequest->getContent(),
|
||||
$headers
|
||||
);
|
||||
$soapResponseTracingData = new SoapResponseTracingData(
|
||||
$curlResponse->getHttpRequestHeaders(),
|
||||
$soapRequest->getContent(),
|
||||
$curlResponse->getResponseHeader(),
|
||||
$curlResponse->getResponseBody()
|
||||
);
|
||||
|
||||
return $soapResponse;
|
||||
if ($curlResponse->curlStatusSuccess()) {
|
||||
$soapResponse = $this->returnSoapResponseByTracing(
|
||||
$this->soapClientOptions->getTrace(),
|
||||
$soapRequest,
|
||||
$curlResponse,
|
||||
$soapResponseTracingData
|
||||
);
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
|
||||
return SoapKernel::filterResponse(
|
||||
$soapResponse,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
return $soapResponse;
|
||||
}
|
||||
} else if ($curlResponse->curlStatusFailed()) {
|
||||
|
||||
return $this->throwSoapFaultByTracing(
|
||||
$this->soapClientOptions->getTrace(),
|
||||
SoapFaultEnum::SOAP_FAULT_HTTP.'-'.$curlResponse->getHttpResponseStatusCode(),
|
||||
$curlResponse->getCurlErrorMessage(),
|
||||
$soapResponseTracingData
|
||||
);
|
||||
} else {
|
||||
|
||||
return $this->throwSoapFaultByTracing(
|
||||
$this->soapClientOptions->getTrace(),
|
||||
SoapFaultEnum::SOAP_FAULT_SOAP_CLIENT_ERROR,
|
||||
'Cannot process curl response with unresolved status: ' . $curlResponse->getCurlStatus(),
|
||||
$soapResponseTracingData
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters HTTP headers which will be sent
|
||||
*
|
||||
* @param SoapRequest $soapRequest SOAP request object
|
||||
* @param array $headers An array of HTTP headers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function filterRequestHeaders(SoapRequest $soapRequest, array $headers)
|
||||
{
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional cURL options for the request
|
||||
*
|
||||
* @param SoapRequest $soapRequest SOAP request object
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function filterRequestOptions(SoapRequest $soapRequest)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last request HTTP headers.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __getLastRequestHeaders()
|
||||
{
|
||||
return $this->lastRequestHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last request HTTP body.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __getLastRequest()
|
||||
{
|
||||
return $this->lastRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last response HTTP headers.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __getLastResponseHeaders()
|
||||
{
|
||||
return $this->lastResponseHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get last response HTTP body.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __getLastResponse()
|
||||
{
|
||||
return $this->lastResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $wsdl
|
||||
* @param int $wsdlCache
|
||||
* @param Curl $curl
|
||||
* @param string $wsdlPath
|
||||
* @param int $wsdlCacheType
|
||||
* @param bool $resolveRemoteIncludes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function loadWsdl($wsdl, $wsdlCache, $resolveRemoteIncludes = true)
|
||||
private function loadWsdl(Curl $curl, $wsdlPath, $wsdlCacheType, $resolveRemoteIncludes = true)
|
||||
{
|
||||
$wsdlDownloader = new WsdlDownloader($this->curl, $resolveRemoteIncludes, $wsdlCache);
|
||||
|
||||
$wsdlDownloader = new WsdlDownloader($curl);
|
||||
try {
|
||||
$cacheFileName = $wsdlDownloader->download($wsdl);
|
||||
} catch (\RuntimeException $e) {
|
||||
throw new \SoapFault('WSDL', "SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl . "'");
|
||||
$loadedWsdlFilePath = $wsdlDownloader->getWsdlPath($curl, $wsdlPath, $wsdlCacheType, $resolveRemoteIncludes);
|
||||
} catch (Exception $e) {
|
||||
throw new SoapFault(
|
||||
SoapFaultEnum::SOAP_FAULT_WSDL,
|
||||
'Unable to load WsdlPath: ' . $e->getMessage()
|
||||
);
|
||||
}
|
||||
|
||||
return $cacheFileName;
|
||||
return $loadedWsdlFilePath;
|
||||
}
|
||||
|
||||
private function getAttachmentFilters()
|
||||
@ -302,4 +337,74 @@ class SoapClient extends \SoapClient
|
||||
|
||||
return $filters;
|
||||
}
|
||||
|
||||
private function mapNativeDataJsonToDto($nativeDataJson)
|
||||
{
|
||||
$nativeData = json_decode($nativeDataJson);
|
||||
|
||||
return new SoapClientNativeDataTransferObject(
|
||||
$nativeData->request,
|
||||
$nativeData->location,
|
||||
$nativeData->action,
|
||||
$nativeData->version
|
||||
);
|
||||
}
|
||||
|
||||
private function returnSoapResponseByTracing(
|
||||
$isTracingEnabled,
|
||||
SoapRequest $soapRequest,
|
||||
CurlResponse $curlResponse,
|
||||
SoapResponseTracingData $soapResponseTracingData,
|
||||
array $soapAttachments = []
|
||||
) {
|
||||
if ($isTracingEnabled === true) {
|
||||
|
||||
return SoapResponseFactory::createWithTracingData(
|
||||
$curlResponse->getResponseBody(),
|
||||
$soapRequest->getLocation(),
|
||||
$soapRequest->getAction(),
|
||||
$soapRequest->getVersion(),
|
||||
$curlResponse->getHttpResponseContentType(),
|
||||
$soapResponseTracingData,
|
||||
$soapAttachments
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
return SoapResponseFactory::create(
|
||||
$curlResponse->getResponseBody(),
|
||||
$soapRequest->getLocation(),
|
||||
$soapRequest->getAction(),
|
||||
$soapRequest->getVersion(),
|
||||
$curlResponse->getHttpResponseContentType(),
|
||||
$soapAttachments
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function throwSoapFaultByTracing($isTracingEnabled, $soapFaultCode, $soapFaultMessage, SoapResponseTracingData $soapResponseTracingData)
|
||||
{
|
||||
if ($isTracingEnabled === true) {
|
||||
|
||||
throw new SoapFaultWithTracingData(
|
||||
$soapFaultCode,
|
||||
$soapFaultMessage,
|
||||
$soapResponseTracingData
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
throw new SoapFault(
|
||||
$soapFaultCode,
|
||||
$soapFaultMessage
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkTracing()
|
||||
{
|
||||
if ($this->soapClientOptions->getTrace() === false) {
|
||||
throw new Exception('SoapClientOptions tracing disabled, turn on trace attribute');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,22 +12,44 @@
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use BeSimple\SoapBundle\Cache;
|
||||
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
|
||||
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use Exception;
|
||||
use SoapHeader;
|
||||
|
||||
/**
|
||||
* Provides a SoapClient instance.
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
* @author Petr Bechyně <petr.bechyne@vodafone.com>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapClientBuilder
|
||||
{
|
||||
public function build(SoapClientOptions $soapClientOptions, SoapOptions $soapOptions)
|
||||
{
|
||||
$cache = new Cache($soapOptions);
|
||||
$cache->validateSettings($soapOptions);
|
||||
|
||||
return new SoapClient(
|
||||
$soapClientOptions,
|
||||
$soapOptions
|
||||
);
|
||||
}
|
||||
|
||||
public function buildWithSoapHeader(
|
||||
SoapClientOptions $soapClientOptions,
|
||||
SoapOptions $soapOptions,
|
||||
SoapHeader $soapHeader
|
||||
) {
|
||||
$soapClient = $this->build($soapClientOptions, $soapOptions);
|
||||
if ($soapClient->__setSoapHeaders($soapHeader) === false) {
|
||||
throw new Exception(
|
||||
'Could not set SoapHeader: '.var_export($soapHeader, true)
|
||||
);
|
||||
}
|
||||
|
||||
return $soapClient;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
class SoapClientMessageWithAttachments
|
||||
{
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
class SoapClientNativeDataTransferObject
|
||||
{
|
||||
public $request;
|
||||
public $location;
|
||||
public $action;
|
||||
public $version;
|
||||
|
||||
public function __construct($request, $location, $action, $version)
|
||||
{
|
||||
$this->request = $request;
|
||||
$this->location = $location;
|
||||
$this->action = $action;
|
||||
$this->version = $version;
|
||||
}
|
||||
}
|
@ -12,12 +12,16 @@
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use BeSimple\SoapClient\Curl\CurlOptions;
|
||||
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
|
||||
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationInterface;
|
||||
|
||||
/**
|
||||
* Provides a SoapClient instance.
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
* @author Petr Bechyně <petr.bechyne@vodafone.com>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapClientOptionsBuilder
|
||||
{
|
||||
@ -26,8 +30,29 @@ class SoapClientOptionsBuilder
|
||||
return new SoapClientOptions(
|
||||
SoapClientOptions::SOAP_CLIENT_TRACE_OFF,
|
||||
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
|
||||
'BeSimpleSoap',
|
||||
CurlOptions::DEFAULT_USER_AGENT,
|
||||
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE
|
||||
);
|
||||
}
|
||||
|
||||
public static function createWithTracing()
|
||||
{
|
||||
return new SoapClientOptions(
|
||||
SoapClientOptions::SOAP_CLIENT_TRACE_ON,
|
||||
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
|
||||
CurlOptions::DEFAULT_USER_AGENT,
|
||||
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE
|
||||
);
|
||||
}
|
||||
|
||||
public static function createWithAuthentication(SoapServerAuthenticationInterface $authentication)
|
||||
{
|
||||
return new SoapClientOptions(
|
||||
SoapClientOptions::SOAP_CLIENT_TRACE_ON,
|
||||
SoapClientOptions::SOAP_CLIENT_EXCEPTIONS_ON,
|
||||
CurlOptions::DEFAULT_USER_AGENT,
|
||||
SoapClientOptions::SOAP_CLIENT_COMPRESSION_NONE,
|
||||
$authentication
|
||||
);
|
||||
}
|
||||
}
|
||||
|
21
src/BeSimple/SoapClient/SoapFaultWithTracingData.php
Normal file
21
src/BeSimple/SoapClient/SoapFaultWithTracingData.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use SoapFault;
|
||||
|
||||
class SoapFaultWithTracingData extends SoapFault
|
||||
{
|
||||
private $soapResponseTracingData;
|
||||
|
||||
public function __construct($code = 0, $message = "", SoapResponseTracingData $soapResponseTracingData)
|
||||
{
|
||||
$this->soapResponseTracingData = $soapResponseTracingData;
|
||||
parent::__construct($code, $message);
|
||||
}
|
||||
|
||||
public function getSoapResponseTracingData()
|
||||
{
|
||||
return $this->soapResponseTracingData;
|
||||
}
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
namespace BeSimple\SoapClient\SoapOptions;
|
||||
|
||||
use BeSimple\SoapClient\Curl\CurlOptions;
|
||||
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationBasic;
|
||||
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationDigest;
|
||||
use BeSimple\SoapClient\SoapServerAuthentication\SoapServerAuthenticationInterface;
|
||||
use BeSimple\SoapClient\SoapServerProxy\SoapServerProxy;
|
||||
|
||||
@ -11,9 +14,9 @@ class SoapClientOptions
|
||||
const SOAP_CLIENT_TRACE_OFF = false;
|
||||
const SOAP_CLIENT_EXCEPTIONS_ON = true;
|
||||
const SOAP_CLIENT_EXCEPTIONS_OFF = false;
|
||||
const SOAP_CLIENT_COMPRESSION_NONE = null;
|
||||
const SOAP_CLIENT_COMPRESSION_GZIP = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP;
|
||||
const SOAP_CLIENT_COMPRESSION_DEFLATE = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE;
|
||||
const SOAP_CLIENT_COMPRESSION_NONE = CurlOptions::SOAP_COMPRESSION_NONE;
|
||||
const SOAP_CLIENT_COMPRESSION_GZIP = CurlOptions::SOAP_COMPRESSION_GZIP;
|
||||
const SOAP_CLIENT_COMPRESSION_DEFLATE = CurlOptions::SOAP_COMPRESSION_DEFLATE;
|
||||
|
||||
private $trace;
|
||||
private $exceptions;
|
||||
@ -70,6 +73,16 @@ class SoapClientOptions
|
||||
return $this->authentication !== null;
|
||||
}
|
||||
|
||||
public function hasAuthenticationBasic()
|
||||
{
|
||||
return $this->hasAuthentication() && $this->getAuthentication() instanceof SoapServerAuthenticationBasic;
|
||||
}
|
||||
|
||||
public function hasAuthenticationDigest()
|
||||
{
|
||||
return $this->hasAuthentication() && $this->getAuthentication() instanceof SoapServerAuthenticationDigest;
|
||||
}
|
||||
|
||||
public function hasProxy()
|
||||
{
|
||||
return $this->proxy !== null;
|
@ -1,46 +1,13 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the BeSimpleSoapClient.
|
||||
*
|
||||
* (c) Christian Kerl <christian-kerl@web.de>
|
||||
* (c) Francis Besset <francis.besset@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
|
||||
|
||||
/**
|
||||
* SoapResponse class for SoapClient. Provides factory function for response object.
|
||||
*
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
*/
|
||||
class SoapResponse extends CommonSoapResponse
|
||||
{
|
||||
/**
|
||||
* Factory function for SoapResponse.
|
||||
*
|
||||
* @param string $content Content
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param string $contentType Content type header
|
||||
*
|
||||
* @return SoapResponse
|
||||
*/
|
||||
public static function create($content, $location, $action, $version, $contentType)
|
||||
public function getResponseContent()
|
||||
{
|
||||
$response = new SoapResponse();
|
||||
$response->setContent($content);
|
||||
$response->setLocation($location);
|
||||
$response->setAction($action);
|
||||
$response->setVersion($version);
|
||||
$response->setContentType($contentType);
|
||||
|
||||
return $response;
|
||||
return $this->getContent();
|
||||
}
|
||||
}
|
||||
|
98
src/BeSimple/SoapClient/SoapResponseFactory.php
Normal file
98
src/BeSimple/SoapClient/SoapResponseFactory.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the BeSimpleSoapClient.
|
||||
*
|
||||
* (c) Christian Kerl <christian-kerl@web.de>
|
||||
* (c) Francis Besset <francis.besset@gmail.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapCommon\Mime\PartFactory;
|
||||
|
||||
/**
|
||||
* SoapResponseFactory for SoapClient. Provides factory function for SoapResponse object.
|
||||
*
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapResponseFactory
|
||||
{
|
||||
/**
|
||||
* Factory method for SoapClient\SoapResponse.
|
||||
*
|
||||
* @param string $content Content
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param string $contentType Content type header
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
* @return SoapResponse
|
||||
*/
|
||||
public static function create(
|
||||
$content,
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
$contentType,
|
||||
array $attachments = []
|
||||
) {
|
||||
$response = new SoapResponse();
|
||||
$response->setContent($content);
|
||||
$response->setLocation($location);
|
||||
$response->setAction($action);
|
||||
$response->setVersion($version);
|
||||
$response->setContentType($contentType);
|
||||
if (count($attachments) > 0) {
|
||||
$response->setAttachments(
|
||||
self::createAttachmentParts($attachments)
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for SoapClient\SoapResponse with SoapResponseTracingData.
|
||||
*
|
||||
* @param string $content Content
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param string $contentType Content type header
|
||||
* @param SoapResponseTracingData $tracingData Data value object suitable for tracing SOAP traffic
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
* @return SoapResponse
|
||||
*/
|
||||
public static function createWithTracingData(
|
||||
$content,
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
$contentType,
|
||||
SoapResponseTracingData $tracingData,
|
||||
array $attachments = []
|
||||
) {
|
||||
$response = new SoapResponse();
|
||||
$response->setContent($content);
|
||||
$response->setLocation($location);
|
||||
$response->setAction($action);
|
||||
$response->setVersion($version);
|
||||
$response->setContentType($contentType);
|
||||
if ($tracingData !== null) {
|
||||
$response->setTracingData($tracingData);
|
||||
}
|
||||
if (count($attachments) > 0) {
|
||||
$response->setAttachments(
|
||||
PartFactory::createAttachmentParts($attachments)
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
39
src/BeSimple/SoapClient/SoapResponseTracingData.php
Normal file
39
src/BeSimple/SoapClient/SoapResponseTracingData.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
class SoapResponseTracingData
|
||||
{
|
||||
private $lastRequestHeaders;
|
||||
private $lastRequest;
|
||||
private $lastResponseHeaders;
|
||||
private $lastResponse;
|
||||
|
||||
public function __construct($lastRequestHeaders, $lastRequest, $lastResponseHeaders, $lastResponse)
|
||||
{
|
||||
$this->lastRequestHeaders = $lastRequestHeaders;
|
||||
$this->lastRequest = $lastRequest;
|
||||
$this->lastResponseHeaders = $lastResponseHeaders;
|
||||
$this->lastResponse = $lastResponse;
|
||||
}
|
||||
|
||||
public function getLastRequestHeaders()
|
||||
{
|
||||
return $this->lastRequestHeaders;
|
||||
}
|
||||
|
||||
public function getLastRequest()
|
||||
{
|
||||
return $this->lastRequest;
|
||||
}
|
||||
|
||||
public function getLastResponseHeaders()
|
||||
{
|
||||
return $this->lastResponseHeaders;
|
||||
}
|
||||
|
||||
public function getLastResponse()
|
||||
{
|
||||
return $this->lastResponse;
|
||||
}
|
||||
}
|
@ -12,7 +12,8 @@
|
||||
|
||||
namespace BeSimple\SoapClient\Tests;
|
||||
|
||||
use BeSimple\SoapClient\Curl;
|
||||
use BeSimple\SoapClient\Curl\Curl;
|
||||
use BeSimple\SoapClient\Curl\CurlOptionsBuilder;
|
||||
|
||||
/**
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
@ -21,11 +22,12 @@ class CurlTest extends AbstractWebserverTest
|
||||
{
|
||||
public function testExec()
|
||||
{
|
||||
$curl = new Curl(array(
|
||||
'proxy_host' => false,
|
||||
));
|
||||
$curlOptions = CurlOptionsBuilder::buildDefault();
|
||||
$curl = new Curl(
|
||||
$curlOptions
|
||||
);
|
||||
|
||||
$this->assertTrue($curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)));
|
||||
$this->assertTrue($curl->executeCurl($curlOptions, sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)));
|
||||
$this->assertTrue($curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)));
|
||||
}
|
||||
|
||||
@ -81,43 +83,4 @@ class CurlTest extends AbstractWebserverTest
|
||||
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals('This is a testfile for cURL.', $curl->getResponseBody());
|
||||
}
|
||||
|
||||
public function testGetResponseContentType()
|
||||
{
|
||||
$curl = new Curl(array(
|
||||
'proxy_host' => false,
|
||||
));
|
||||
|
||||
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals('text/plain; charset=UTF-8', $curl->getResponseContentType());
|
||||
|
||||
$curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals('text/html; charset=UTF-8', $curl->getResponseContentType());
|
||||
}
|
||||
|
||||
public function testGetResponseHeaders()
|
||||
{
|
||||
$curl = new Curl(array(
|
||||
'proxy_host' => false,
|
||||
));
|
||||
|
||||
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals(117 + self::$websererPortLength, strlen($curl->getResponseHeaders()));
|
||||
|
||||
$curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals(124 + self::$websererPortLength, strlen($curl->getResponseHeaders()));
|
||||
}
|
||||
|
||||
public function testGetResponseStatusCode()
|
||||
{
|
||||
$curl = new Curl(array(
|
||||
'proxy_host' => false,
|
||||
));
|
||||
|
||||
$curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals(200, $curl->getResponseStatusCode());
|
||||
|
||||
$curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT));
|
||||
$this->assertEquals(404, $curl->getResponseStatusCode());
|
||||
}
|
||||
}
|
||||
|
8
src/BeSimple/SoapClient/Tests/GenerateTestRequest.php
Normal file
8
src/BeSimple/SoapClient/Tests/GenerateTestRequest.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Tests;
|
||||
|
||||
class GenerateTestRequest
|
||||
{
|
||||
public $salutation;
|
||||
}
|
8
src/BeSimple/SoapClient/Tests/GetUKLocationByCounty.php
Normal file
8
src/BeSimple/SoapClient/Tests/GetUKLocationByCounty.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapClient\Tests;
|
||||
|
||||
class GetUKLocationByCounty
|
||||
{
|
||||
public $County;
|
||||
}
|
23
src/BeSimple/SoapClient/Tests/Mock/.readme
Normal file
23
src/BeSimple/SoapClient/Tests/Mock/.readme
Normal file
@ -0,0 +1,23 @@
|
||||
# HOW TO PREPARE Mock SWA Service
|
||||
|
||||
1. Create an test endpoint by using tools such as mockable.io, that will return response (expect POST requests with SOAP v1.1)
|
||||
similar to the one provided in example file src/BeSimple/SoapClient/Tests/Mock/MockSwaService.example.response
|
||||
and Content-Type headers from src/BeSimple/SoapClient/Tests/Mock/MockSwaService.example.response.headers
|
||||
|
||||
Example Endpoint URL: https://demo0580999.mockable.io/soap/testGenerator
|
||||
|
||||
2. Create a test WSDL endpoint that will return WSDL file from (expect GET requests)
|
||||
an example file src/BeSimple/SoapClient/Tests/Mock/MockSwaService.wsdl
|
||||
|
||||
Example WSDL endpoint URL: https://demo0580999.mockable.io/soap/testGenerator?WSDL
|
||||
|
||||
3. Take the two endpoints and configure SoapClientBuilderTest::TEST_ENDPOINT_SWA
|
||||
and SoapClientBuilderTest::TEST_REMOTE_WSDL_SWA variables
|
||||
|
||||
4. The test BeSimple\SoapClient\Tests\SoapClientBuilderTest::testSoapCallSwaWithAttachmentsOnResponse should work correctly.
|
||||
|
||||
If not, try to catch SoapFaultWithTracingData thrown by the soapCall method:
|
||||
|
||||
$soapClient->soapCall('generateTest', [$generateTestRequest]);
|
||||
|
||||
You can print the SoapFaultWithTracingData attributes in order to investigate the SoapClient request and request headers.
|
@ -0,0 +1,18 @@
|
||||
|
||||
--Part_13_58a1b01a466a6.58a1b01a466e8
|
||||
Content-Type: application/soap+xml; charset=utf-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Content-ID: <part-72f5d209-2631-42ee-81d1-e554af739ce6@response.info>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://schema.testcase"><env:Body xmlns:rpc="http://www.w3.org/2003/05/soap-rpc"><ns1:generateTestResponse><rpc:result>generateTestReturn</rpc:result><generateTestReturn><fileName>dummy-attachment.txt</fileName></generateTestReturn></ns1:generateTestResponse></env:Body></env:Envelope>
|
||||
|
||||
--Part_13_58a1b01a466a6.58a1b01a466e8
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Content-ID: <dummy-attachment.txt>
|
||||
Content-Location: dummy-attachment.txt
|
||||
|
||||
Hello world!
|
||||
|
||||
--Part_13_58a1b01a466a6.58a1b01a466e8--
|
@ -0,0 +1 @@
|
||||
multipart/related; type="application/soap+xml"; charset=utf-8; boundary=Part_13_58a1b01a466a6.58a1b01a466e8; start="<part-72f5d209-2631-42ee-81d1-e554af739ce6@response.info>"
|
61
src/BeSimple/SoapClient/Tests/Mock/MockSwaService.wsdl
Normal file
61
src/BeSimple/SoapClient/Tests/Mock/MockSwaService.wsdl
Normal file
@ -0,0 +1,61 @@
|
||||
<?xml version="1.0"?>
|
||||
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://schema.testcase" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schema.testcase">
|
||||
<wsdl:types>
|
||||
<xsd:schema targetNamespace="http://schema.testcase">
|
||||
<xsd:complexType name="SoapHeaderEntity">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="user" type="xsd:string" minOccurs="1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>User name for authorization</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="SoapHeader" type="tns:SoapHeaderEntity"/>
|
||||
<xsd:complexType name="GenerateTestRequest">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="salutation" type="xsd:string" minOccurs="0"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="GenerateTestResponse">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="fileName" type="xsd:string" minOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
</wsdl:types>
|
||||
<message name="SoapHeader">
|
||||
<part name="SoapHeader" element="tns:SoapHeader"/>
|
||||
</message>
|
||||
<message name="GenerateTestRequest">
|
||||
<part name="request" type="tns:GenerateTestRequest"/>
|
||||
</message>
|
||||
<message name="GenerateTestResponse">
|
||||
<part name="generateTestReturn" type="tns:GenerateTestResponse"/>
|
||||
</message>
|
||||
<wsdl:portType name="TestGeneratorServiceSoapPortType">
|
||||
<wsdl:operation name="generateTest">
|
||||
<wsdl:input message="tns:GenerateTestRequest"/>
|
||||
<wsdl:output message="tns:GenerateTestResponse"/>
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<binding name="TestGeneratorServiceSoapBinding" type="tns:TestGeneratorServiceSoapPortType">
|
||||
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
|
||||
<wsdl:operation name="generateTest">
|
||||
<soap:operation soapAction="TestGeneratorService.generateTest" style="rpc"/>
|
||||
<wsdl:input>
|
||||
<soap:header use="literal" message="tns:SoapHeader" part="SoapHeader" namespace="http://schema.testcase"/>
|
||||
<soap:body use="literal" part="request" namespace="http://schema.testcase"/>
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" namespace="http://schema.testcase"/>
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
</binding>
|
||||
<wsdl:service name="TestGeneratorService">
|
||||
<xsd:documentation>WSDL file for TestGeneratorService</xsd:documentation>
|
||||
<port name="TestGeneratorServiceSoapPortType" binding="tns:TestGeneratorServiceSoapBinding">
|
||||
<soap:address location="https://demo0580999.mockable.io/soap/testGenerator"/>
|
||||
</port>
|
||||
</wsdl:service>
|
||||
</wsdl:definitions>
|
@ -12,113 +12,286 @@
|
||||
|
||||
namespace BeSimple\SoapClient\Tests;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapClient\Curl\CurlOptions;
|
||||
use BeSimple\SoapClient\SoapClientBuilder;
|
||||
use BeSimple\SoapClient\SoapClientOptionsBuilder;
|
||||
use BeSimple\SoapClient\SoapFaultWithTracingData;
|
||||
use BeSimple\SoapClient\SoapOptions\SoapClientOptions;
|
||||
use BeSimple\SoapCommon\ClassMap;
|
||||
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use BeSimple\SoapCommon\SoapOptionsBuilder;
|
||||
use Exception;
|
||||
use SoapHeader;
|
||||
|
||||
class SoapClientBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $defaultOptions = array(
|
||||
'features' => 0,
|
||||
'classmap' => array(),
|
||||
'typemap' => array(),
|
||||
);
|
||||
const CACHE_DIR = __DIR__ . '/../../../../cache';
|
||||
const TEST_ENDPOINT_UK = 'http://www.webservicex.net/uklocation.asmx';
|
||||
const TEST_REMOTE_WSDL_UK = 'http://www.webservicex.net/uklocation.asmx?WSDL';
|
||||
const TEST_LOCAL_WSDL_UK = __DIR__.'/localWsdl.wsdl';
|
||||
const TEST_REMOTE_WSDL_NOT_WORKING = 'http://www.nosuchserverexist.tld/doesnotexist.endpoint?wsdl';
|
||||
const TEST_ENDPOINT_SWA = 'https://demo2815480.mockable.io/soap/testGenerator';
|
||||
const TEST_REMOTE_WSDL_SWA = 'https://demo2815480.mockable.io/soap/testGenerator?WSDL';
|
||||
|
||||
public function testContruct()
|
||||
public function testSoapOptionsCreateWithDefaults()
|
||||
{
|
||||
$options = $this
|
||||
->getSoapBuilder()
|
||||
->getSoapOptions()
|
||||
;
|
||||
$defaultOptions = SoapOptionsBuilder::createWithDefaults(self::TEST_LOCAL_WSDL_UK);
|
||||
|
||||
$this->assertEquals($this->mergeOptions(array()), $options);
|
||||
self::assertInstanceOf(SoapOptions::class, $defaultOptions);
|
||||
self::assertEquals(self::TEST_LOCAL_WSDL_UK, $defaultOptions->getWsdlFile());
|
||||
}
|
||||
|
||||
public function testWithTrace()
|
||||
public function testSoapClientOptionsCreateWithDefaults()
|
||||
{
|
||||
$builder = $this->getSoapBuilder();
|
||||
$defaultOptions = SoapClientOptionsBuilder::createWithDefaults();
|
||||
|
||||
$builder->withTrace();
|
||||
$this->assertEquals($this->mergeOptions(array('trace' => true)), $builder->getSoapOptions());
|
||||
|
||||
$builder->withTrace(false);
|
||||
$this->assertEquals($this->mergeOptions(array('trace' => false)), $builder->getSoapOptions());
|
||||
self::assertInstanceOf(SoapClientOptions::class, $defaultOptions);
|
||||
self::assertEquals(CurlOptions::DEFAULT_USER_AGENT, $defaultOptions->getUserAgent());
|
||||
}
|
||||
|
||||
public function testWithExceptions()
|
||||
public function testConstructSoapClientWithDefaults()
|
||||
{
|
||||
$builder = $this->getSoapBuilder();
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_UK)
|
||||
);
|
||||
|
||||
$builder->withExceptions();
|
||||
$this->assertEquals($this->mergeOptions(array('exceptions' => true)), $builder->getSoapOptions());
|
||||
|
||||
$builder->withExceptions(false);
|
||||
$this->assertEquals($this->mergeOptions(array('exceptions' => false)), $builder->getSoapOptions());
|
||||
self::assertInstanceOf(\SoapClient::class, $soapClient);
|
||||
}
|
||||
|
||||
public function testWithUserAgent()
|
||||
public function testConstructSoapClientWithSwaAndClassMapAndCacheDisk()
|
||||
{
|
||||
$builder = $this->getSoapBuilder();
|
||||
$soapOptions = SoapOptionsBuilder::createSwaWithClassMap(
|
||||
self::TEST_REMOTE_WSDL_UK,
|
||||
new ClassMap(),
|
||||
SoapOptions::SOAP_CACHE_TYPE_DISK,
|
||||
__DIR__.'/../../../../cache'
|
||||
);
|
||||
|
||||
$builder->withUserAgent('BeSimpleSoap Test');
|
||||
$this->assertEquals($this->mergeOptions(array('user_agent' => 'BeSimpleSoap Test')), $builder->getSoapOptions());
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
$soapOptions
|
||||
);
|
||||
|
||||
self::assertInstanceOf(\SoapClient::class, $soapClient);
|
||||
}
|
||||
|
||||
public function testWithCompression()
|
||||
public function testConstructSoapClientWithDefaultsAndLocalWsdlFile()
|
||||
{
|
||||
$builder = $this->getSoapBuilder();
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults(self::TEST_LOCAL_WSDL_UK)
|
||||
);
|
||||
|
||||
$builder->withCompressionGzip();
|
||||
$this->assertEquals($this->mergeOptions(array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP)), $builder->getSoapOptions());
|
||||
|
||||
$builder->withCompressionDeflate();
|
||||
$this->assertEquals($this->mergeOptions(array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE)), $builder->getSoapOptions());
|
||||
self::assertInstanceOf(\SoapClient::class, $soapClient);
|
||||
}
|
||||
|
||||
public function testWithAuthentication()
|
||||
public function testConstructSoapClientWithSwaAndClassMapAndCacheDiskAndLocalWsdlFile()
|
||||
{
|
||||
$builder = $this->getSoapBuilder();
|
||||
$soapOptions = SoapOptionsBuilder::createSwaWithClassMap(
|
||||
self::TEST_LOCAL_WSDL_UK,
|
||||
new ClassMap(),
|
||||
SoapOptions::SOAP_CACHE_TYPE_DISK,
|
||||
__DIR__ .'/../../../../cache'
|
||||
);
|
||||
|
||||
$builder->withDigestAuthentication(__DIR__.'/Fixtures/cert.pem', 'foobar');
|
||||
$this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_DIGEST, 'local_cert' => __DIR__.'/Fixtures/cert.pem', 'passphrase' => 'foobar')), $builder->getSoapOptions());
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
$soapOptions
|
||||
);
|
||||
|
||||
$builder->withDigestAuthentication(__DIR__.'/Fixtures/cert.pem');
|
||||
$this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_DIGEST, 'local_cert' => __DIR__.'/Fixtures/cert.pem')), $builder->getSoapOptions());
|
||||
|
||||
$builder->withBasicAuthentication('foo', 'bar');
|
||||
$this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_BASIC, 'login' => 'foo', 'password' => 'bar')), $builder->getSoapOptions());
|
||||
self::assertInstanceOf(\SoapClient::class, $soapClient);
|
||||
}
|
||||
|
||||
public function testWithProxy()
|
||||
public function testSoapCall()
|
||||
{
|
||||
$builder = $this->getSoapBuilder();
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_UK)
|
||||
);
|
||||
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
|
||||
$getUKLocationByCountyRequest->County = 'London';
|
||||
$soapResponse = $soapClient->soapCall('GetUKLocationByCounty', [$getUKLocationByCountyRequest]);
|
||||
|
||||
$builder->withProxy('localhost', 8080);
|
||||
$this->assertEquals($this->mergeOptions(array('proxy_host' => 'localhost', 'proxy_port' => 8080)), $builder->getSoapOptions());
|
||||
self::assertContains('GetUKLocationByCountyResult', $soapResponse->getContent());
|
||||
self::assertContains('</GetUKLocationByCountyResponse>', $soapResponse->getContent());
|
||||
self::assertEquals(self::TEST_ENDPOINT_UK, $soapResponse->getLocation());
|
||||
}
|
||||
|
||||
$builder->withProxy('127.0.0.1', 8585, 'foo', 'bar');
|
||||
$this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar')), $builder->getSoapOptions());
|
||||
public function testSoapCallWithCacheEndpointDownShouldFail()
|
||||
{
|
||||
$this->setExpectedException(Exception::class, 'Could not write WSDL cache file: Download failed with message');
|
||||
|
||||
$builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', \CURLAUTH_BASIC);
|
||||
$this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar', 'proxy_auth' => \CURLAUTH_BASIC)), $builder->getSoapOptions());
|
||||
$this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults(
|
||||
self::TEST_REMOTE_WSDL_NOT_WORKING,
|
||||
SoapOptions::SOAP_CACHE_TYPE_DISK,
|
||||
__DIR__ .'/../../../../cache'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', \CURLAUTH_NTLM);
|
||||
$this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar', 'proxy_auth' => \CURLAUTH_NTLM)), $builder->getSoapOptions());
|
||||
public function testSoapCallEndpointDownShouldFail()
|
||||
{
|
||||
$this->setExpectedException(Exception::class, 'Parsing WSDL: Couldn\'t load from');
|
||||
|
||||
$this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_NOT_WORKING)
|
||||
);
|
||||
}
|
||||
|
||||
public function testSoapCallNoSwaWithAttachmentMustFail()
|
||||
{
|
||||
$this->setExpectedException(Exception::class, 'Non SWA SoapClient cannot handle SOAP action');
|
||||
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithDefaults(),
|
||||
SoapOptionsBuilder::createWithDefaults(self::TEST_REMOTE_WSDL_UK)
|
||||
);
|
||||
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
|
||||
$getUKLocationByCountyRequest->County = 'London';
|
||||
|
||||
$soapClient->soapCall(
|
||||
'GetUKLocationByCounty',
|
||||
[$getUKLocationByCountyRequest],
|
||||
[
|
||||
new SoapAttachment(
|
||||
'first-file.txt',
|
||||
'text/plain',
|
||||
'unexpected file - no SWA - must fail'
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function testSoapCallSwaWithTwoAttachments()
|
||||
{
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithTracing(),
|
||||
SoapOptionsBuilder::createSwaWithClassMap(
|
||||
self::TEST_REMOTE_WSDL_UK,
|
||||
new ClassMap(),
|
||||
SoapOptions::SOAP_CACHE_TYPE_DISK,
|
||||
__DIR__ .'/../../../../cache'
|
||||
)
|
||||
);
|
||||
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
|
||||
$getUKLocationByCountyRequest->County = 'London';
|
||||
|
||||
try {
|
||||
$builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', -100);
|
||||
|
||||
$this->fail('An expected exception has not been raised.');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('InvalidArgumentException', $e);
|
||||
$soapResponse = $soapClient->soapCall(
|
||||
'GetUKLocationByCounty',
|
||||
[$getUKLocationByCountyRequest],
|
||||
[
|
||||
new SoapAttachment(
|
||||
'first-file.txt',
|
||||
'text/plain',
|
||||
'hello world'
|
||||
),
|
||||
new SoapAttachment(
|
||||
'second-file.txt',
|
||||
'text/plain',
|
||||
'hello world'
|
||||
)
|
||||
]
|
||||
);
|
||||
$tracingData = $soapResponse->getTracingData();
|
||||
} catch (SoapFaultWithTracingData $e) {
|
||||
$tracingData = $e->getSoapResponseTracingData();
|
||||
}
|
||||
|
||||
self::assertEquals(
|
||||
$this->getContentId($tracingData->getLastRequestHeaders()),
|
||||
$this->getContentId($tracingData->getLastRequest()),
|
||||
'Content ID must match in request XML and Content-Type: ...; start header'
|
||||
);
|
||||
self::assertEquals(
|
||||
$this->getMultiPartBoundary($tracingData->getLastRequestHeaders()),
|
||||
$this->getMultiPartBoundary($tracingData->getLastRequest()),
|
||||
'MultiPart boundary must match in request XML and Content-Type: ...; boundary header'
|
||||
);
|
||||
self::assertContains('boundary=Part_', $tracingData->getLastRequestHeaders(), 'Headers should link to boundary');
|
||||
self::assertContains('start="<part-', $tracingData->getLastRequestHeaders(), 'Headers should link to first MultiPart');
|
||||
self::assertContains('action="', $tracingData->getLastRequestHeaders(), 'Headers should contain SOAP action');
|
||||
self::assertEquals(
|
||||
$this->removeOneTimeData(file_get_contents(__DIR__.'/soapRequestWithTwoAttachments.request')),
|
||||
$this->removeOneTimeData($tracingData->getLastRequest()),
|
||||
'Requests must match after onetime data were removed'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCreateWithDefaults()
|
||||
public function testSoapCallSwaWithNoAttachments()
|
||||
{
|
||||
$builder = SoapClientBuilder::createClientWithDefaults();
|
||||
$soapClient = $this->getSoapBuilder()->build(
|
||||
SoapClientOptionsBuilder::createWithTracing(),
|
||||
SoapOptionsBuilder::createSwaWithClassMap(
|
||||
self::TEST_REMOTE_WSDL_UK,
|
||||
new ClassMap(),
|
||||
SoapOptions::SOAP_CACHE_TYPE_DISK,
|
||||
__DIR__ .'/../../../../cache'
|
||||
)
|
||||
);
|
||||
$getUKLocationByCountyRequest = new GetUKLocationByCounty();
|
||||
$getUKLocationByCountyRequest->County = 'London';
|
||||
|
||||
$this->assertInstanceOf('BeSimple\SoapClient\SoapClientBuilder', $builder);
|
||||
try {
|
||||
$soapResponse = $soapClient->soapCall(
|
||||
'GetUKLocationByCounty',
|
||||
[$getUKLocationByCountyRequest]
|
||||
);
|
||||
$tracingData = $soapResponse->getTracingData();
|
||||
} catch (SoapFaultWithTracingData $e) {
|
||||
$tracingData = $e->getSoapResponseTracingData();
|
||||
}
|
||||
|
||||
$this->assertEquals($this->mergeOptions(array('soap_version' => SOAP_1_2, 'encoding' => 'UTF-8', 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, 'user_agent' => 'BeSimpleSoap')), $builder->getSoapOptions());
|
||||
self::assertNotContains('boundary=Part_', $tracingData->getLastRequestHeaders(), 'Headers should link to boundary');
|
||||
self::assertNotContains('start="<part-', $tracingData->getLastRequestHeaders(), 'Headers should link to first MultiPart');
|
||||
self::assertContains('action="', $tracingData->getLastRequestHeaders(), 'Headers should contain SOAP action');
|
||||
self::assertEquals(
|
||||
file_get_contents(__DIR__.'/soapRequestWithNoAttachments.request'),
|
||||
$tracingData->getLastRequest(),
|
||||
'Requests must match'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see This test needs a working SWA endpoint. Examine Tests/Mock directory for details
|
||||
*/
|
||||
public function testSoapCallSwaWithAttachmentsOnResponse()
|
||||
{
|
||||
$soapClient = $this->getSoapBuilder()->buildWithSoapHeader(
|
||||
SoapClientOptionsBuilder::createWithTracing(),
|
||||
SoapOptionsBuilder::createSwaWithClassMapV11(
|
||||
self::TEST_REMOTE_WSDL_SWA,
|
||||
new ClassMap([
|
||||
'GenerateTestRequest' => GenerateTestRequest::class,
|
||||
]),
|
||||
SoapOptions::SOAP_CACHE_TYPE_DISK,
|
||||
__DIR__ . '/../../../../cache'
|
||||
),
|
||||
new SoapHeader('http://schema.testcase', 'SoapHeader', [
|
||||
'user' => 'admin',
|
||||
])
|
||||
);
|
||||
$generateTestRequest = new GenerateTestRequest();
|
||||
$generateTestRequest->salutation = 'World';
|
||||
|
||||
$soapResponse = $soapClient->soapCall('generateTest', [$generateTestRequest]);
|
||||
$attachments = $soapResponse->getAttachments();
|
||||
|
||||
self::assertContains('</generateTestReturn>', $soapResponse->getResponseContent());
|
||||
self::assertTrue($soapResponse->hasAttachments());
|
||||
self::assertCount(1, $attachments);
|
||||
|
||||
$firstAttachment = reset($attachments);
|
||||
|
||||
self::assertEquals('text/plain', $firstAttachment->getHeader('Content-Type'));
|
||||
|
||||
file_put_contents(self::CACHE_DIR . '/testSoapCallSwaWithAttachmentsOnResponse.xml', $soapResponse->getContent());
|
||||
file_put_contents(self::CACHE_DIR . '/testSoapCallSwaWithAttachmentsOnResponse.txt', $firstAttachment->getContent());
|
||||
}
|
||||
|
||||
private function getSoapBuilder()
|
||||
@ -126,8 +299,41 @@ class SoapClientBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
return new SoapClientBuilder();
|
||||
}
|
||||
|
||||
private function mergeOptions(array $options)
|
||||
public function removeOneTimeData($string)
|
||||
{
|
||||
return array_merge($this->defaultOptions, $options);
|
||||
$contentId = $this->getContentId($string);
|
||||
$multiPartBoundary = $this->getMultiPartBoundary($string);
|
||||
|
||||
return str_replace(
|
||||
$contentId,
|
||||
'{content-id-placeholder}',
|
||||
str_replace(
|
||||
$multiPartBoundary,
|
||||
'{multipart-boundary-placeholder}',
|
||||
$string
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function getMultiPartBoundary($string)
|
||||
{
|
||||
$realMultiParts = null;
|
||||
preg_match('/Part\_[0-9]{2}\_[a-zA-Z0-9]{13}\.[a-zA-Z0-9]{13}/', $string, $realMultiParts);
|
||||
if (count($realMultiParts) > 0) {
|
||||
return $realMultiParts[0];
|
||||
}
|
||||
|
||||
throw new Exception('Could not find real MultiPart boundary');
|
||||
}
|
||||
|
||||
private function getContentId($string)
|
||||
{
|
||||
$realContentIds = null;
|
||||
preg_match('/part\-[0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12}\@response\.info/', $string, $realContentIds);
|
||||
if (count($realContentIds) > 0) {
|
||||
return $realContentIds[0];
|
||||
}
|
||||
|
||||
throw new Exception('Could not find real contentId');
|
||||
}
|
||||
}
|
||||
|
380
src/BeSimple/SoapClient/Tests/localWsdl.wsdl
Normal file
380
src/BeSimple/SoapClient/Tests/localWsdl.wsdl
Normal file
@ -0,0 +1,380 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://www.webserviceX.NET" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://www.webserviceX.NET" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK Postcode,Town,County and Validate UK Address</wsdl:documentation>
|
||||
<wsdl:types>
|
||||
<s:schema elementFormDefault="qualified" targetNamespace="http://www.webserviceX.NET">
|
||||
<s:element name="GetUKLocationByCounty">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="County" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="GetUKLocationByCountyResponse">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="GetUKLocationByCountyResult" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="GetUKLocationByTown">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="Town" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="GetUKLocationByTownResponse">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="GetUKLocationByTownResult" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="GetUKLocationByPostCode">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="PostCode" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="GetUKLocationByPostCodeResponse">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="GetUKLocationByPostCodeResult" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="ValidateUKAddress">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="Town" type="s:string" />
|
||||
<s:element minOccurs="0" maxOccurs="1" name="County" type="s:string" />
|
||||
<s:element minOccurs="0" maxOccurs="1" name="PostCode" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="ValidateUKAddressResponse">
|
||||
<s:complexType>
|
||||
<s:sequence>
|
||||
<s:element minOccurs="0" maxOccurs="1" name="ValidateUKAddressResult" type="s:string" />
|
||||
</s:sequence>
|
||||
</s:complexType>
|
||||
</s:element>
|
||||
<s:element name="string" nillable="true" type="s:string" />
|
||||
</s:schema>
|
||||
</wsdl:types>
|
||||
<wsdl:message name="GetUKLocationByCountySoapIn">
|
||||
<wsdl:part name="parameters" element="tns:GetUKLocationByCounty" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByCountySoapOut">
|
||||
<wsdl:part name="parameters" element="tns:GetUKLocationByCountyResponse" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByTownSoapIn">
|
||||
<wsdl:part name="parameters" element="tns:GetUKLocationByTown" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByTownSoapOut">
|
||||
<wsdl:part name="parameters" element="tns:GetUKLocationByTownResponse" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByPostCodeSoapIn">
|
||||
<wsdl:part name="parameters" element="tns:GetUKLocationByPostCode" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByPostCodeSoapOut">
|
||||
<wsdl:part name="parameters" element="tns:GetUKLocationByPostCodeResponse" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ValidateUKAddressSoapIn">
|
||||
<wsdl:part name="parameters" element="tns:ValidateUKAddress" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ValidateUKAddressSoapOut">
|
||||
<wsdl:part name="parameters" element="tns:ValidateUKAddressResponse" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByCountyHttpGetIn">
|
||||
<wsdl:part name="County" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByCountyHttpGetOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByTownHttpGetIn">
|
||||
<wsdl:part name="Town" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByTownHttpGetOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByPostCodeHttpGetIn">
|
||||
<wsdl:part name="PostCode" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByPostCodeHttpGetOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ValidateUKAddressHttpGetIn">
|
||||
<wsdl:part name="Town" type="s:string" />
|
||||
<wsdl:part name="County" type="s:string" />
|
||||
<wsdl:part name="PostCode" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ValidateUKAddressHttpGetOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByCountyHttpPostIn">
|
||||
<wsdl:part name="County" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByCountyHttpPostOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByTownHttpPostIn">
|
||||
<wsdl:part name="Town" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByTownHttpPostOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByPostCodeHttpPostIn">
|
||||
<wsdl:part name="PostCode" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="GetUKLocationByPostCodeHttpPostOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ValidateUKAddressHttpPostIn">
|
||||
<wsdl:part name="Town" type="s:string" />
|
||||
<wsdl:part name="County" type="s:string" />
|
||||
<wsdl:part name="PostCode" type="s:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:message name="ValidateUKAddressHttpPostOut">
|
||||
<wsdl:part name="Body" element="tns:string" />
|
||||
</wsdl:message>
|
||||
<wsdl:portType name="UKLocationSoap">
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial County</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByCountySoapIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByCountySoapOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial Town</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByTownSoapIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByTownSoapOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by Postcode(First Section of Post Code)</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByPostCodeSoapIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByPostCodeSoapOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Validate UK address,Use First Section of Poscode for Postcode atribute</wsdl:documentation>
|
||||
<wsdl:input message="tns:ValidateUKAddressSoapIn" />
|
||||
<wsdl:output message="tns:ValidateUKAddressSoapOut" />
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<wsdl:portType name="UKLocationHttpGet">
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial County</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByCountyHttpGetIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByCountyHttpGetOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial Town</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByTownHttpGetIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByTownHttpGetOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by Postcode(First Section of Post Code)</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByPostCodeHttpGetIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByPostCodeHttpGetOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Validate UK address,Use First Section of Poscode for Postcode atribute</wsdl:documentation>
|
||||
<wsdl:input message="tns:ValidateUKAddressHttpGetIn" />
|
||||
<wsdl:output message="tns:ValidateUKAddressHttpGetOut" />
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<wsdl:portType name="UKLocationHttpPost">
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial County</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByCountyHttpPostIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByCountyHttpPostOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by full /partial Town</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByTownHttpPostIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByTownHttpPostOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK town,Postcode and County by Postcode(First Section of Post Code)</wsdl:documentation>
|
||||
<wsdl:input message="tns:GetUKLocationByPostCodeHttpPostIn" />
|
||||
<wsdl:output message="tns:GetUKLocationByPostCodeHttpPostOut" />
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Validate UK address,Use First Section of Poscode for Postcode atribute</wsdl:documentation>
|
||||
<wsdl:input message="tns:ValidateUKAddressHttpPostIn" />
|
||||
<wsdl:output message="tns:ValidateUKAddressHttpPostOut" />
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<wsdl:binding name="UKLocationSoap" type="tns:UKLocationSoap">
|
||||
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<soap:operation soapAction="http://www.webserviceX.NET/GetUKLocationByCounty" style="document" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<soap:operation soapAction="http://www.webserviceX.NET/GetUKLocationByTown" style="document" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<soap:operation soapAction="http://www.webserviceX.NET/GetUKLocationByPostCode" style="document" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<soap:operation soapAction="http://www.webserviceX.NET/ValidateUKAddress" style="document" />
|
||||
<wsdl:input>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
</wsdl:binding>
|
||||
<wsdl:binding name="UKLocationSoap12" type="tns:UKLocationSoap">
|
||||
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<soap12:operation soapAction="http://www.webserviceX.NET/GetUKLocationByCounty" style="document" />
|
||||
<wsdl:input>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<soap12:operation soapAction="http://www.webserviceX.NET/GetUKLocationByTown" style="document" />
|
||||
<wsdl:input>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<soap12:operation soapAction="http://www.webserviceX.NET/GetUKLocationByPostCode" style="document" />
|
||||
<wsdl:input>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<soap12:operation soapAction="http://www.webserviceX.NET/ValidateUKAddress" style="document" />
|
||||
<wsdl:input>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap12:body use="literal" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
</wsdl:binding>
|
||||
<wsdl:binding name="UKLocationHttpGet" type="tns:UKLocationHttpGet">
|
||||
<http:binding verb="GET" />
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<http:operation location="/GetUKLocationByCounty" />
|
||||
<wsdl:input>
|
||||
<http:urlEncoded />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<http:operation location="/GetUKLocationByTown" />
|
||||
<wsdl:input>
|
||||
<http:urlEncoded />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<http:operation location="/GetUKLocationByPostCode" />
|
||||
<wsdl:input>
|
||||
<http:urlEncoded />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<http:operation location="/ValidateUKAddress" />
|
||||
<wsdl:input>
|
||||
<http:urlEncoded />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
</wsdl:binding>
|
||||
<wsdl:binding name="UKLocationHttpPost" type="tns:UKLocationHttpPost">
|
||||
<http:binding verb="POST" />
|
||||
<wsdl:operation name="GetUKLocationByCounty">
|
||||
<http:operation location="/GetUKLocationByCounty" />
|
||||
<wsdl:input>
|
||||
<mime:content type="application/x-www-form-urlencoded" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByTown">
|
||||
<http:operation location="/GetUKLocationByTown" />
|
||||
<wsdl:input>
|
||||
<mime:content type="application/x-www-form-urlencoded" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="GetUKLocationByPostCode">
|
||||
<http:operation location="/GetUKLocationByPostCode" />
|
||||
<wsdl:input>
|
||||
<mime:content type="application/x-www-form-urlencoded" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="ValidateUKAddress">
|
||||
<http:operation location="/ValidateUKAddress" />
|
||||
<wsdl:input>
|
||||
<mime:content type="application/x-www-form-urlencoded" />
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<mime:mimeXml part="Body" />
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
</wsdl:binding>
|
||||
<wsdl:service name="UKLocation">
|
||||
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">Get UK Postcode,Town,County and Validate UK Address</wsdl:documentation>
|
||||
<wsdl:port name="UKLocationSoap" binding="tns:UKLocationSoap">
|
||||
<soap:address location="http://www.webservicex.net/uklocation.asmx" />
|
||||
</wsdl:port>
|
||||
<wsdl:port name="UKLocationSoap12" binding="tns:UKLocationSoap12">
|
||||
<soap12:address location="http://www.webservicex.net/uklocation.asmx" />
|
||||
</wsdl:port>
|
||||
<wsdl:port name="UKLocationHttpGet" binding="tns:UKLocationHttpGet">
|
||||
<http:address location="http://www.webservicex.net/uklocation.asmx" />
|
||||
</wsdl:port>
|
||||
<wsdl:port name="UKLocationHttpPost" binding="tns:UKLocationHttpPost">
|
||||
<http:address location="http://www.webservicex.net/uklocation.asmx" />
|
||||
</wsdl:port>
|
||||
</wsdl:service>
|
||||
</wsdl:definitions>
|
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.webserviceX.NET"><env:Body><ns1:GetUKLocationByCounty><ns1:County>London</ns1:County></ns1:GetUKLocationByCounty></env:Body></env:Envelope>
|
@ -0,0 +1,24 @@
|
||||
|
||||
--Part_10_589b2dcf4f7fb.589b2dcf4f804
|
||||
Content-Type: application/soap+xml; charset=utf-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Content-ID: <part-7e61b8e0-f84d-4cf7-8043-3c27d90767af@response.info>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://www.webserviceX.NET"><env:Body><ns1:GetUKLocationByCounty><ns1:County>London</ns1:County></ns1:GetUKLocationByCounty></env:Body></env:Envelope>
|
||||
|
||||
--Part_10_589b2dcf4f7fb.589b2dcf4f804
|
||||
Content-Type: application/pdf; charset=utf-8
|
||||
Content-Transfer-Encoding: binary
|
||||
Content-ID: <first-file.txt>
|
||||
Content-Location: first-file.txt
|
||||
|
||||
hello world
|
||||
--Part_10_589b2dcf4f7fb.589b2dcf4f804
|
||||
Content-Type: application/pdf; charset=utf-8
|
||||
Content-Transfer-Encoding: binary
|
||||
Content-ID: <second-file.txt>
|
||||
Content-Location: second-file.txt
|
||||
|
||||
hello world
|
||||
--Part_10_589b2dcf4f7fb.589b2dcf4f804--
|
@ -12,8 +12,13 @@
|
||||
|
||||
namespace BeSimple\SoapClient;
|
||||
|
||||
use BeSimple\SoapClient\Curl\Curl;
|
||||
use BeSimple\SoapCommon\Cache;
|
||||
use BeSimple\SoapCommon\Helper;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use DOMXPath;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Downloads WSDL files with cURL. Uses the WSDL_CACHE_* constants and the
|
||||
@ -25,148 +30,179 @@ use BeSimple\SoapCommon\Helper;
|
||||
*/
|
||||
class WsdlDownloader
|
||||
{
|
||||
protected $curl;
|
||||
protected $resolveRemoteIncludes = true;
|
||||
protected $cacheEnabled;
|
||||
protected $cacheDir;
|
||||
protected $cacheTtl;
|
||||
|
||||
/**
|
||||
* @param Curl $curl
|
||||
* @param int $cacheWsdl = Cache::TYPE_NONE|Cache::WSDL_CACHE_DISK|Cache::WSDL_CACHE_BOTH|Cache::WSDL_CACHE_MEMORY
|
||||
* @param string $wsdlPath WSDL file URL/path
|
||||
* @param int $wsdCacheType = Cache::TYPE_NONE|Cache::WSDL_CACHE_DISK|Cache::WSDL_CACHE_BOTH|Cache::WSDL_CACHE_MEMORY
|
||||
* @param boolean $resolveRemoteIncludes
|
||||
*/
|
||||
public function __construct(Curl $curl, $cacheWsdl, $resolveRemoteIncludes = true)
|
||||
{
|
||||
$this->curl = $curl;
|
||||
$this->resolveRemoteIncludes = $resolveRemoteIncludes;
|
||||
|
||||
$this->cacheEnabled = $cacheWsdl === Cache::TYPE_NONE ? Cache::DISABLED : Cache::ENABLED == Cache::isEnabled();
|
||||
$this->cacheDir = Cache::getDirectory();
|
||||
$this->cacheTtl = Cache::getLifetime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Download given WSDL file and return name of cache file.
|
||||
*
|
||||
* @param string $wsdl WSDL file URL/path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function download($wsdl)
|
||||
public function getWsdlPath(Curl $curl, $wsdlPath, $wsdCacheType, $resolveRemoteIncludes = true)
|
||||
{
|
||||
// download and cache remote WSDL files or local ones where we want to
|
||||
// resolve remote XSD includes
|
||||
$isRemoteFile = $this->isRemoteFile($wsdl);
|
||||
if ($isRemoteFile || $this->resolveRemoteIncludes) {
|
||||
$cacheFilePath = $this->cacheDir.DIRECTORY_SEPARATOR.'wsdl_'.md5($wsdl).'.cache';
|
||||
|
||||
if (!$this->cacheEnabled || !file_exists($cacheFilePath) || (filemtime($cacheFilePath) + $this->cacheTtl) < time()) {
|
||||
if ($isRemoteFile) {
|
||||
// execute request
|
||||
$responseSuccessfull = $this->curl->exec($wsdl);
|
||||
// get content
|
||||
if ($responseSuccessfull) {
|
||||
$response = $this->curl->getResponseBody();
|
||||
|
||||
if ($this->resolveRemoteIncludes) {
|
||||
$this->resolveRemoteIncludes($response, $cacheFilePath, $wsdl);
|
||||
} else {
|
||||
file_put_contents($cacheFilePath, $response);
|
||||
}
|
||||
} else {
|
||||
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'");
|
||||
}
|
||||
} elseif (file_exists($wsdl)) {
|
||||
$response = file_get_contents($wsdl);
|
||||
$this->resolveRemoteIncludes($response, $cacheFilePath);
|
||||
} else {
|
||||
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'");
|
||||
$isRemoteFile = $this->isRemoteFile($wsdlPath);
|
||||
$isCacheEnabled = $wsdCacheType === Cache::TYPE_NONE ? false : Cache::isEnabled();
|
||||
if ($isCacheEnabled === true) {
|
||||
$cacheFilePath = Cache::getDirectory().DIRECTORY_SEPARATOR.'wsdl_'.md5($wsdlPath).'.cache';
|
||||
$isCacheExisting = file_exists($cacheFilePath);
|
||||
if ($isCacheExisting) {
|
||||
$fileModificationTime = filemtime($cacheFilePath);
|
||||
if ($fileModificationTime === false) {
|
||||
throw new Exception('File modification time could not be get for wsdl path: ' . $cacheFilePath);
|
||||
}
|
||||
$isCacheValid = ($fileModificationTime + Cache::getLifetime()) >= time();
|
||||
} else {
|
||||
$isCacheExisting = $isCacheValid = false;
|
||||
}
|
||||
if ($isCacheExisting === false || $isCacheValid === false) {
|
||||
$this->writeCacheFile($curl, $wsdCacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile);
|
||||
}
|
||||
|
||||
return $cacheFilePath;
|
||||
} elseif (file_exists($wsdl)) {
|
||||
return realpath($wsdl);
|
||||
}
|
||||
return $this->getLocalWsdlPath($cacheFilePath);
|
||||
|
||||
throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'");
|
||||
} else {
|
||||
|
||||
if ($isRemoteFile === true) {
|
||||
return $wsdlPath;
|
||||
}
|
||||
|
||||
return $this->getLocalWsdlPath($wsdlPath);
|
||||
}
|
||||
}
|
||||
|
||||
private function writeCacheFile(Curl $curl, $cacheType, $wsdlPath, $cacheFilePath, $resolveRemoteIncludes, $isRemoteFile)
|
||||
{
|
||||
if ($isRemoteFile === true) {
|
||||
$curlResponse = $curl->executeCurlWithCachedSession($wsdlPath);
|
||||
if ($curlResponse->curlStatusSuccess()) {
|
||||
if (mb_strlen($curlResponse->getResponseBody()) === 0) {
|
||||
throw new Exception('Could not write WSDL cache file: curl response empty');
|
||||
}
|
||||
if ($resolveRemoteIncludes === true) {
|
||||
$document = $this->getXmlFileDOMDocument($curl, $cacheType, $curlResponse->getResponseBody(), $wsdlPath);
|
||||
$this->saveXmlDOMDocument($document, $cacheFilePath);
|
||||
} else {
|
||||
file_put_contents($cacheFilePath, $curlResponse->getResponseBody());
|
||||
}
|
||||
} else {
|
||||
throw new Exception('Could not write WSDL cache file: Download failed with message: '.$curlResponse->getCurlErrorMessage());
|
||||
}
|
||||
} else {
|
||||
if (file_exists($wsdlPath)) {
|
||||
$document = $this->getXmlFileDOMDocument($curl, $cacheType, file_get_contents($wsdlPath));
|
||||
$this->saveXmlDOMDocument($document, $cacheFilePath);
|
||||
} else {
|
||||
throw new Exception('Could write WSDL cache file: local file does not exist: '.$wsdlPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getLocalWsdlPath($wsdlPath)
|
||||
{
|
||||
if (file_exists($wsdlPath)) {
|
||||
|
||||
return realpath($wsdlPath);
|
||||
|
||||
} else {
|
||||
throw new Exception('Could not download WSDL: local file does not exist: '.$wsdlPath);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we have a remote file?
|
||||
*
|
||||
* @param string $file File URL/path
|
||||
*
|
||||
* @param string $wsdlPath File URL/path
|
||||
* @return boolean
|
||||
*/
|
||||
private function isRemoteFile($file)
|
||||
private function isRemoteFile($wsdlPath)
|
||||
{
|
||||
// @parse_url to suppress E_WARNING for invalid urls
|
||||
if (false !== $url = @parse_url($file)) {
|
||||
if (isset($url['scheme']) && 'http' === substr($url['scheme'], 0, 4)) {
|
||||
$parsedUrlOrFalse = @parse_url($wsdlPath);
|
||||
if ($parsedUrlOrFalse !== false) {
|
||||
if (isset($parsedUrlOrFalse['scheme']) && substr($parsedUrlOrFalse['scheme'], 0, 4) === 'http') {
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
throw new Exception('Could not determine wsdlPath is remote: '.$wsdlPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves remote WSDL/XSD includes within the WSDL files.
|
||||
*
|
||||
* @param string $xml XML file
|
||||
* @param string $cacheFilePath Cache file name
|
||||
* @param Curl $curl
|
||||
* @param int $cacheType
|
||||
* @param string $xmlFileSource XML file contents
|
||||
* @param boolean $parentFilePath Parent file name
|
||||
*
|
||||
* @return void
|
||||
* @return DOMDocument
|
||||
*/
|
||||
private function resolveRemoteIncludes($xml, $cacheFilePath, $parentFilePath = null)
|
||||
private function getXmlFileDOMDocument(Curl $curl, $cacheType, $xmlFileSource, $parentFilePath = null)
|
||||
{
|
||||
$doc = new \DOMDocument();
|
||||
$doc->loadXML($xml);
|
||||
$document = new DOMDocument('1.0', 'utf-8');
|
||||
if ($document->loadXML($xmlFileSource) === false) {
|
||||
throw new Exception('Could not save downloaded WSDL cache: '.$xmlFileSource);
|
||||
}
|
||||
|
||||
$xpath = new \DOMXPath($doc);
|
||||
$xpath->registerNamespace(Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA);
|
||||
$xpath->registerNamespace(Helper::PFX_WSDL, Helper::NS_WSDL);
|
||||
$xpath = new DOMXPath($document);
|
||||
$this->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_WSDL, Helper::NS_WSDL, 'location', $parentFilePath);
|
||||
$this->updateXmlDocument($curl, $cacheType, $xpath, Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA, 'schemaLocation', $parentFilePath);
|
||||
|
||||
// WSDL include/import
|
||||
$query = './/'.Helper::PFX_WSDL.':include | .//'.Helper::PFX_WSDL.':import';
|
||||
$nodes = $xpath->query($query);
|
||||
return $document;
|
||||
}
|
||||
|
||||
private function saveXmlDOMDocument(DOMDocument $document, $cacheFilePath)
|
||||
{
|
||||
try {
|
||||
$xmlContents = $document->saveXML();
|
||||
if ($xmlContents === '') {
|
||||
throw new Exception('Could not write WSDL cache file: DOMDocument returned empty XML file');
|
||||
}
|
||||
file_put_contents($cacheFilePath, $xmlContents);
|
||||
} catch (Exception $e) {
|
||||
unlink($cacheFilePath);
|
||||
throw new Exception('Could not write WSDL cache file: save method returned error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function updateXmlDocument(
|
||||
Curl $curl,
|
||||
$cacheType,
|
||||
DOMXPath $xpath,
|
||||
$schemaPrefix,
|
||||
$schemaUrl,
|
||||
$locationAttributeName,
|
||||
$parentFilePath = null
|
||||
) {
|
||||
$xpath->registerNamespace($schemaPrefix, $schemaUrl);
|
||||
$nodes = $xpath->query('.//'.$schemaPrefix.':include | .//'.$schemaPrefix.':import');
|
||||
if ($nodes->length > 0) {
|
||||
foreach ($nodes as $node) {
|
||||
$location = $node->getAttribute('location');
|
||||
if ($this->isRemoteFile($location)) {
|
||||
$location = $this->download($location);
|
||||
$node->setAttribute('location', $location);
|
||||
} elseif (null !== $parentFilePath) {
|
||||
$location = $this->resolveRelativePathInUrl($parentFilePath, $location);
|
||||
$location = $this->download($location);
|
||||
$node->setAttribute('location', $location);
|
||||
/** @var DOMElement $node */
|
||||
$locationPath = $node->getAttribute($locationAttributeName);
|
||||
if ($this->isRemoteFile($locationPath)) {
|
||||
$node->setAttribute(
|
||||
$locationAttributeName,
|
||||
$this->getWsdlPath(
|
||||
$curl,
|
||||
$locationPath,
|
||||
$cacheType,
|
||||
true
|
||||
)
|
||||
);
|
||||
} else if ($parentFilePath !== null) {
|
||||
$node->setAttribute(
|
||||
$locationAttributeName,
|
||||
$this->getWsdlPath(
|
||||
$curl,
|
||||
$this->resolveRelativePathInUrl($parentFilePath, $locationPath),
|
||||
$cacheType,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XML schema include/import
|
||||
$query = './/'.Helper::PFX_XML_SCHEMA.':include | .//'.Helper::PFX_XML_SCHEMA.':import';
|
||||
$nodes = $xpath->query($query);
|
||||
if ($nodes->length > 0) {
|
||||
foreach ($nodes as $node) {
|
||||
if ($node->hasAttribute('schemaLocation')) {
|
||||
$schemaLocation = $node->getAttribute('schemaLocation');
|
||||
if ($this->isRemoteFile($schemaLocation)) {
|
||||
$schemaLocation = $this->download($schemaLocation);
|
||||
$node->setAttribute('schemaLocation', $schemaLocation);
|
||||
} elseif (null !== $parentFilePath) {
|
||||
$schemaLocation = $this->resolveRelativePathInUrl($parentFilePath, $schemaLocation);
|
||||
$schemaLocation = $this->download($schemaLocation);
|
||||
$node->setAttribute('schemaLocation', $schemaLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$doc->save($cacheFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,9 +241,8 @@ class WsdlDownloader
|
||||
|
||||
// resolve /../
|
||||
foreach ($parts as $key => $part) {
|
||||
if ('..' === $part) {
|
||||
if ($part === '..') {
|
||||
$keyToDelete = $key - 1;
|
||||
|
||||
while ($keyToDelete > 0) {
|
||||
if (isset($parts[$keyToDelete])) {
|
||||
unset($parts[$keyToDelete]);
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
namespace BeSimple\SoapCommon;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
*/
|
||||
@ -32,22 +34,22 @@ class Cache
|
||||
self::TYPE_DISK_MEMORY,
|
||||
];
|
||||
|
||||
static public function getTypes()
|
||||
public static function getTypes()
|
||||
{
|
||||
return self::$types;
|
||||
}
|
||||
|
||||
static public function hasType($cacheType)
|
||||
public static function hasType($cacheType)
|
||||
{
|
||||
return in_array($cacheType, self::$types);
|
||||
}
|
||||
|
||||
static public function isEnabled()
|
||||
public static function isEnabled()
|
||||
{
|
||||
return self::iniGet('soap.wsdl_cache_enabled');
|
||||
return self::iniGet('soap.wsdl_cache_enabled') === '1';
|
||||
}
|
||||
|
||||
static public function setEnabled($enabled)
|
||||
public static function setEnabled($enabled)
|
||||
{
|
||||
if (!in_array($enabled, array(self::ENABLED, self::DISABLED), true)) {
|
||||
throw new \InvalidArgumentException();
|
||||
@ -56,60 +58,58 @@ class Cache
|
||||
self::iniSet('soap.wsdl_cache_enabled', $enabled);
|
||||
}
|
||||
|
||||
static public function getType()
|
||||
public static function getType()
|
||||
{
|
||||
return self::iniGet('soap.wsdl_cache');
|
||||
}
|
||||
|
||||
static public function setType($type)
|
||||
public static function setType($type)
|
||||
{
|
||||
if (!in_array($type, self::getTypes(), true)) {
|
||||
throw new \InvalidArgumentException('The cache type has to be either Cache::TYPE_NONE, Cache::TYPE_DISK, Cache::TYPE_MEMORY or Cache::TYPE_DISK_MEMORY');
|
||||
throw new InvalidArgumentException(
|
||||
'The cache type has to be either Cache::TYPE_NONE, Cache::TYPE_DISK, Cache::TYPE_MEMORY or Cache::TYPE_DISK_MEMORY'
|
||||
);
|
||||
}
|
||||
|
||||
self::iniSet('soap.wsdl_cache', $type);
|
||||
}
|
||||
|
||||
static public function getDirectory()
|
||||
public static function getDirectory()
|
||||
{
|
||||
return self::iniGet('soap.wsdl_cache_dir');
|
||||
}
|
||||
|
||||
static public function setDirectory($directory)
|
||||
public static function setDirectory($directory)
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
mkdir($directory, 0777, true);
|
||||
}
|
||||
|
||||
self::iniSet('soap.wsdl_cache_dir', $directory);
|
||||
}
|
||||
|
||||
static public function getLifetime()
|
||||
public static function getLifetime()
|
||||
{
|
||||
return self::iniGet('soap.wsdl_cache_ttl');
|
||||
}
|
||||
|
||||
static public function setLifetime($lifetime)
|
||||
public static function setLifetime($lifetime)
|
||||
{
|
||||
self::iniSet('soap.wsdl_cache_ttl', $lifetime);
|
||||
}
|
||||
|
||||
static public function getLimit()
|
||||
public static function getLimit()
|
||||
{
|
||||
return self::iniGet('soap.wsdl_cache_limit');
|
||||
}
|
||||
|
||||
static public function setLimit($limit)
|
||||
public static function setLimit($limit)
|
||||
{
|
||||
self::iniSet('soap.wsdl_cache_limit', $limit);
|
||||
}
|
||||
|
||||
static protected function iniGet($key)
|
||||
protected static function iniGet($key)
|
||||
{
|
||||
return ini_get($key);
|
||||
}
|
||||
|
||||
static protected function iniSet($key, $value)
|
||||
protected static function iniSet($key, $value)
|
||||
{
|
||||
ini_set($key, $value);
|
||||
}
|
||||
|
@ -22,11 +22,6 @@ use BeSimple\SoapCommon\Mime\Part as MimePart;
|
||||
*/
|
||||
class MtomTypeConverter implements TypeConverterInterface
|
||||
{
|
||||
/**
|
||||
* @var \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
|
||||
*/
|
||||
protected $soapKernel = null;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
10
src/BeSimple/SoapCommon/Fault/SoapFaultEnum.php
Normal file
10
src/BeSimple/SoapCommon/Fault/SoapFaultEnum.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapCommon\Fault;
|
||||
|
||||
class SoapFaultEnum
|
||||
{
|
||||
const SOAP_FAULT_WSDL = 'wsdl';
|
||||
const SOAP_FAULT_HTTP = 'http';
|
||||
const SOAP_FAULT_SOAP_CLIENT_ERROR = 'soap-client-error';
|
||||
}
|
@ -181,4 +181,9 @@ class MultiPart extends PartHeader
|
||||
{
|
||||
return 'multipart-boundary-' . Helper::generateUUID() . '@response.info';
|
||||
}
|
||||
|
||||
public function getMainPartContentId()
|
||||
{
|
||||
return $this->mainPartContentId;
|
||||
}
|
||||
}
|
@ -12,183 +12,241 @@
|
||||
|
||||
namespace BeSimple\SoapCommon\Mime;
|
||||
|
||||
use BeSimple\SoapCommon\Mime\Parser\ContentTypeParser;
|
||||
use BeSimple\SoapCommon\Mime\Parser\ParsedPart;
|
||||
use BeSimple\SoapCommon\Mime\Parser\ParsedPartList;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Simple Multipart-Mime parser.
|
||||
*
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
* @author Petr Bechyne <mail@petrbechyne.com>
|
||||
*/
|
||||
class Parser
|
||||
{
|
||||
const HAS_HTTP_REQUEST_HEADERS = true;
|
||||
const HAS_NO_HTTP_REQUEST_HEADERS = false;
|
||||
|
||||
/**
|
||||
* Parse the given Mime-Message and return a \BeSimple\SoapCommon\Mime\MultiPart object.
|
||||
*
|
||||
* @param string $mimeMessage Mime message string
|
||||
* @param array(string=>string) $headers Array of header elements (e.g. coming from http request)
|
||||
* @param string[] $headers array(string=>string) of header elements (e.g. coming from http request)
|
||||
*
|
||||
* @return \BeSimple\SoapCommon\Mime\MultiPart
|
||||
*/
|
||||
public static function parseMimeMessage($mimeMessage, array $headers = [])
|
||||
{
|
||||
$boundary = null;
|
||||
$start = null;
|
||||
$multipart = new MultiPart();
|
||||
$hitFirstBoundary = false;
|
||||
$inHeader = true;
|
||||
$multiPart = new MultiPart();
|
||||
$mimeMessageLines = preg_split("/(\n)/", $mimeMessage);
|
||||
// add given headers, e.g. coming from HTTP headers
|
||||
if (count($headers) > 0) {
|
||||
foreach ($headers as $name => $value) {
|
||||
if ($name === 'Content-Type') {
|
||||
self::parseContentTypeHeader($multipart, $name, $value);
|
||||
$boundary = $multipart->getHeader('Content-Type', 'boundary');
|
||||
$start = $multipart->getHeader('Content-Type', 'start');
|
||||
} else {
|
||||
$multipart->setHeader($name, $value);
|
||||
}
|
||||
}
|
||||
$inHeader = false;
|
||||
self::setMultiPartHeaders($multiPart, $headers);
|
||||
$hasHttpRequestHeaders = self::HAS_HTTP_REQUEST_HEADERS;
|
||||
} else {
|
||||
$hasHttpRequestHeaders = self::HAS_NO_HTTP_REQUEST_HEADERS;
|
||||
}
|
||||
$content = '';
|
||||
$currentPart = $multipart;
|
||||
$lines = preg_split("/(\r\n)|(\n)/", $mimeMessage);
|
||||
if (self::hasBoundary($lines)) {
|
||||
foreach ($lines as $line) {
|
||||
// ignore http status code and POST *
|
||||
if (substr($line, 0, 5) == 'HTTP/' || substr($line, 0, 4) == 'POST') {
|
||||
if (self::hasBoundary($mimeMessageLines)) {
|
||||
$parsedPartList = self::getPartsFromMimeMessageLines(
|
||||
$multiPart,
|
||||
$mimeMessageLines,
|
||||
$hasHttpRequestHeaders
|
||||
);
|
||||
if ($parsedPartList->hasParts() === false) {
|
||||
throw new Exception(
|
||||
'Could not parse MimeMessage: no Parts for MultiPart given'
|
||||
);
|
||||
}
|
||||
if ($parsedPartList->hasExactlyOneMainPart() === false) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
'Could not parse MimeMessage %s HTTP headers: unexpected count of main ParsedParts: %s (total: %d)',
|
||||
$hasHttpRequestHeaders ? 'with' : 'w/o',
|
||||
implode(', ', $parsedPartList->getPartContentIds()),
|
||||
$parsedPartList->getMainPartCount()
|
||||
)
|
||||
);
|
||||
}
|
||||
self::appendPartsToMultiPart(
|
||||
$parsedPartList,
|
||||
$multiPart
|
||||
);
|
||||
} else {
|
||||
self::appendSingleMainPartToMultiPart(new Part($mimeMessage), $multiPart);
|
||||
}
|
||||
|
||||
return $multiPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param MultiPart $multiPart
|
||||
* @param string[] $mimeMessageLines
|
||||
* @param bool $hasHttpHeaders = self::HAS_HTTP_REQUEST_HEADERS|self::HAS_NO_HTTP_REQUEST_HEADERS
|
||||
* @return ParsedPartList
|
||||
*/
|
||||
private static function getPartsFromMimeMessageLines(
|
||||
MultiPart $multiPart,
|
||||
array $mimeMessageLines,
|
||||
$hasHttpHeaders
|
||||
) {
|
||||
$parsedParts = [];
|
||||
$contentTypeBoundary = $multiPart->getHeader('Content-Type', 'boundary');
|
||||
$contentTypeContentIdStart = $multiPart->getHeader('Content-Type', 'start');
|
||||
$currentPart = $multiPart;
|
||||
$messagePartStringContent = '';
|
||||
$inHeader = $hasHttpHeaders;
|
||||
$hitFirstBoundary = false;
|
||||
|
||||
foreach ($mimeMessageLines as $mimeMessageLine) {
|
||||
// ignore http status code and POST *
|
||||
if (substr($mimeMessageLine, 0, 5) == 'HTTP/' || substr($mimeMessageLine, 0, 4) == 'POST') {
|
||||
continue;
|
||||
}
|
||||
if (isset($currentHeader)) {
|
||||
if (isset($mimeMessageLine[0]) && ($mimeMessageLine[0] === ' ' || $mimeMessageLine[0] === "\t")) {
|
||||
$currentHeader .= $mimeMessageLine;
|
||||
continue;
|
||||
}
|
||||
if (isset($currentHeader)) {
|
||||
if (isset($line[0]) && ($line[0] === ' ' || $line[0] === "\t")) {
|
||||
$currentHeader .= $line;
|
||||
continue;
|
||||
if (strpos($currentHeader, ':') !== false) {
|
||||
list($headerName, $headerValue) = explode(':', $currentHeader, 2);
|
||||
$headerValue = iconv_mime_decode($headerValue, 0, Part::CHARSET_UTF8);
|
||||
$parsedMimeHeaders = ContentTypeParser::parseContentTypeHeader($headerName, $headerValue);
|
||||
foreach ($parsedMimeHeaders as $parsedMimeHeader) {
|
||||
$currentPart->setHeader(
|
||||
$parsedMimeHeader->getName(),
|
||||
$parsedMimeHeader->getValue(),
|
||||
$parsedMimeHeader->getSubValue()
|
||||
);
|
||||
}
|
||||
if (strpos($currentHeader, ':') !== false) {
|
||||
list($headerName, $headerValue) = explode(':', $currentHeader, 2);
|
||||
$headerValue = iconv_mime_decode($headerValue, 0, 'utf-8');
|
||||
if (strpos($headerValue, ';') !== false) {
|
||||
self::parseContentTypeHeader($currentPart, $headerName, $headerValue);
|
||||
$boundary = $multipart->getHeader('Content-Type', 'boundary');
|
||||
$start = $multipart->getHeader('Content-Type', 'start');
|
||||
} else {
|
||||
$currentPart->setHeader($headerName, trim($headerValue));
|
||||
}
|
||||
}
|
||||
unset($currentHeader);
|
||||
$contentTypeBoundary = $multiPart->getHeader('Content-Type', 'boundary');
|
||||
$contentTypeContentIdStart = $multiPart->getHeader('Content-Type', 'start');
|
||||
}
|
||||
if ($inHeader) {
|
||||
if (trim($line) == '') {
|
||||
$inHeader = false;
|
||||
continue;
|
||||
}
|
||||
$currentHeader = $line;
|
||||
unset($currentHeader);
|
||||
}
|
||||
if ($inHeader === true) {
|
||||
if (trim($mimeMessageLine) == '') {
|
||||
$inHeader = false;
|
||||
continue;
|
||||
} else {
|
||||
if (self::isBoundary($line)) {
|
||||
if (strcmp(trim($line), '--' . $boundary) === 0) {
|
||||
if ($currentPart instanceof Part) {
|
||||
$content = substr($content, 0, -1);
|
||||
self::decodeContent($currentPart, $content);
|
||||
// check if there is a start parameter given, if not set first part
|
||||
$isMain = (is_null($start) || $start == $currentPart->getHeader('Content-ID')) ? true : false;
|
||||
if ($isMain === true) {
|
||||
$start = $currentPart->getHeader('Content-ID');
|
||||
}
|
||||
$multipart->addPart($currentPart, $isMain);
|
||||
}
|
||||
$currentPart = new Part();
|
||||
$hitFirstBoundary = true;
|
||||
$inHeader = true;
|
||||
$content = '';
|
||||
} elseif (strcmp(trim($line), '--' . $boundary . '--') === 0) {
|
||||
$content = substr($content, 0, -1);
|
||||
self::decodeContent($currentPart, $content);
|
||||
}
|
||||
$currentHeader = $mimeMessageLine;
|
||||
continue;
|
||||
} else {
|
||||
if (self::isBoundary($mimeMessageLine)) {
|
||||
if (self::isMiddleBoundary($mimeMessageLine, $contentTypeBoundary)) {
|
||||
if ($currentPart instanceof Part) {
|
||||
$currentPartContent = self::decodeContent(
|
||||
$currentPart,
|
||||
substr($messagePartStringContent, 0, -1)
|
||||
);
|
||||
$currentPart->setContent($currentPartContent);
|
||||
// check if there is a start parameter given, if not set first part
|
||||
$isMain = (is_null($start) || $start == $currentPart->getHeader('Content-ID')) ? true : false;
|
||||
if ($isMain === true) {
|
||||
$start = $currentPart->getHeader('Content-ID');
|
||||
if ($contentTypeContentIdStart === null || $currentPart->hasContentId($contentTypeContentIdStart) === true) {
|
||||
$contentTypeContentIdStart = $currentPart->getHeader('Content-ID');
|
||||
$parsedParts[] = new ParsedPart($currentPart, ParsedPart::PART_IS_MAIN);
|
||||
} else {
|
||||
$parsedParts[] = new ParsedPart($currentPart, ParsedPart::PART_IS_NOT_MAIN);
|
||||
}
|
||||
$multipart->addPart($currentPart, $isMain);
|
||||
$content = '';
|
||||
}
|
||||
$currentPart = new Part();
|
||||
$hitFirstBoundary = true;
|
||||
$inHeader = true;
|
||||
$messagePartStringContent = '';
|
||||
} else if (self::isLastBoundary($mimeMessageLine, $contentTypeBoundary)) {
|
||||
$currentPartContent = self::decodeContent(
|
||||
$currentPart,
|
||||
substr($messagePartStringContent, 0, -1)
|
||||
);
|
||||
$currentPart->setContent($currentPartContent);
|
||||
// check if there is a start parameter given, if not set first part
|
||||
if ($contentTypeContentIdStart === null || $currentPart->hasContentId($contentTypeContentIdStart) === true) {
|
||||
$contentTypeContentIdStart = $currentPart->getHeader('Content-ID');
|
||||
$parsedParts[] = new ParsedPart($currentPart, ParsedPart::PART_IS_MAIN);
|
||||
} else {
|
||||
$parsedParts[] = new ParsedPart($currentPart, ParsedPart::PART_IS_NOT_MAIN);
|
||||
}
|
||||
$messagePartStringContent = '';
|
||||
} else {
|
||||
if ($hitFirstBoundary === false) {
|
||||
if (trim($line) !== '') {
|
||||
$inHeader = true;
|
||||
$currentHeader = $line;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$content .= $line . "\n";
|
||||
// else block migrated from https://github.com/progmancod/BeSimpleSoap/commit/bf9437e3bcf35c98c6c2f26aca655ec3d3514694
|
||||
// be careful to replace \r\n with \n
|
||||
$messagePartStringContent .= $mimeMessageLine . "\n";
|
||||
}
|
||||
} else {
|
||||
if ($hitFirstBoundary === false) {
|
||||
if (trim($mimeMessageLine) !== '') {
|
||||
$inHeader = true;
|
||||
$currentHeader = $mimeMessageLine;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$messagePartStringContent .= $mimeMessageLine . "\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$multipart->addPart(new Part($mimeMessage), true);
|
||||
}
|
||||
|
||||
return $multipart;
|
||||
return new ParsedPartList($parsedParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a "Content-Type" header with multiple sub values.
|
||||
* e.g. Content-Type: multipart/related; boundary=boundary; type=text/xml;
|
||||
* start="<123@abc>"
|
||||
*
|
||||
* Based on: https://labs.omniti.com/alexandria/trunk/OmniTI/Mail/Parser.php
|
||||
*
|
||||
* @param \BeSimple\SoapCommon\Mime\PartHeader $part Header part
|
||||
* @param string $headerName Header name
|
||||
* @param string $headerValue Header value
|
||||
*
|
||||
* @param ParsedPartList $parsedPartList
|
||||
* @param MultiPart $multiPart
|
||||
*/
|
||||
private static function parseContentTypeHeader(PartHeader $part, $headerName, $headerValue)
|
||||
private static function appendPartsToMultiPart(ParsedPartList $parsedPartList, MultiPart $multiPart)
|
||||
{
|
||||
if (strpos($headerValue, ';')) {
|
||||
list($value, $remainder) = explode(';', $headerValue, 2);
|
||||
$value = trim($value);
|
||||
$part->setHeader($headerName, $value);
|
||||
$remainder = trim($remainder);
|
||||
while (strlen($remainder) > 0) {
|
||||
if (!preg_match('/^([a-zA-Z0-9_-]+)=(.{1})/', $remainder, $matches)) {
|
||||
break;
|
||||
foreach ($parsedPartList->getParts() as $parsedPart) {
|
||||
$multiPart->addPart(
|
||||
$parsedPart->getPart(),
|
||||
$parsedPart->isMain()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static function appendSingleMainPartToMultiPart(Part $part, MultiPart $multiPart)
|
||||
{
|
||||
$multiPart->addPart($part, true);
|
||||
}
|
||||
|
||||
private static function setMultiPartHeaders(MultiPart $multiPart, $headers)
|
||||
{
|
||||
foreach ($headers as $name => $value) {
|
||||
if ($name === 'Content-Type') {
|
||||
$parsedMimeHeaders = ContentTypeParser::parseContentTypeHeader($name, $value);
|
||||
foreach ($parsedMimeHeaders as $parsedMimeHeader) {
|
||||
$multiPart->setHeader(
|
||||
$parsedMimeHeader->getName(),
|
||||
$parsedMimeHeader->getValue(),
|
||||
$parsedMimeHeader->getSubValue()
|
||||
);
|
||||
}
|
||||
$name = $matches[1];
|
||||
$delimiter = $matches[2];
|
||||
$remainder = substr($remainder, strlen($name) + 1);
|
||||
if (!preg_match('/([^;]+)(;)?(\s|$)?/', $remainder, $matches)) {
|
||||
break;
|
||||
}
|
||||
$value = rtrim($matches[1], ';');
|
||||
if ($delimiter == "'" || $delimiter == '"') {
|
||||
$value = trim($value, $delimiter);
|
||||
}
|
||||
$part->setHeader($headerName, $name, $value);
|
||||
$remainder = substr($remainder, strlen($matches[0]));
|
||||
} else {
|
||||
$multiPart->setHeader($name, $value);
|
||||
}
|
||||
} else {
|
||||
$part->setHeader($headerName, $headerValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the content of a Mime part.
|
||||
*
|
||||
* @param \BeSimple\SoapCommon\Mime\Part $part Part to add content
|
||||
* @param string $content Content to decode
|
||||
* Decodes the content of a Mime part
|
||||
*
|
||||
* @param Part $part Part to add content
|
||||
* @param string $partStringContent Content to decode
|
||||
* @return string $partStringContent decodedContent
|
||||
*/
|
||||
private static function decodeContent(Part $part, $content)
|
||||
private static function decodeContent(Part $part, $partStringContent)
|
||||
{
|
||||
$encoding = strtolower($part->getHeader('Content-Transfer-Encoding'));
|
||||
$charset = strtolower($part->getHeader('Content-Type', 'charset'));
|
||||
if ($encoding == Part::ENCODING_BASE64) {
|
||||
$content = base64_decode($content);
|
||||
} elseif ($encoding == Part::ENCODING_QUOTED_PRINTABLE) {
|
||||
$content = quoted_printable_decode($content);
|
||||
|
||||
if ($encoding === Part::ENCODING_BASE64) {
|
||||
$partStringContent = base64_decode($partStringContent);
|
||||
} else if ($encoding === Part::ENCODING_QUOTED_PRINTABLE) {
|
||||
$partStringContent = quoted_printable_decode($partStringContent);
|
||||
}
|
||||
if ($charset != 'utf-8') {
|
||||
$content = iconv($charset, 'utf-8', $content);
|
||||
|
||||
if ($charset !== Part::CHARSET_UTF8) {
|
||||
return iconv($charset, Part::CHARSET_UTF8, $partStringContent);
|
||||
}
|
||||
$part->setContent($content);
|
||||
|
||||
return $partStringContent;
|
||||
}
|
||||
|
||||
private static function hasBoundary(array $lines)
|
||||
@ -203,8 +261,18 @@ class Parser
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function isBoundary($line)
|
||||
private static function isBoundary($mimeMessageLine)
|
||||
{
|
||||
return strlen($line) > 0 && $line[0] === "-";
|
||||
return strlen($mimeMessageLine) > 0 && $mimeMessageLine[0] === "-";
|
||||
}
|
||||
|
||||
private static function isMiddleBoundary($mimeMessageLine, $contentTypeBoundary)
|
||||
{
|
||||
return strcmp(trim($mimeMessageLine), '--'.$contentTypeBoundary) === 0;
|
||||
}
|
||||
|
||||
private static function isLastBoundary($mimeMessageLine, $contentTypeBoundary)
|
||||
{
|
||||
return strcmp(trim($mimeMessageLine), '--'.$contentTypeBoundary.'--') === 0;
|
||||
}
|
||||
}
|
64
src/BeSimple/SoapCommon/Mime/Parser/ContentTypeParser.php
Normal file
64
src/BeSimple/SoapCommon/Mime/Parser/ContentTypeParser.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapCommon\Mime\Parser;
|
||||
|
||||
class ContentTypeParser
|
||||
{
|
||||
/**
|
||||
* Parse a "Content-Type" header with multiple sub values.
|
||||
* e.g. Content-Type: multipart/related; boundary=boundary; type=text/xml;
|
||||
* start="<123@abc>"
|
||||
*
|
||||
* Based on: https://labs.omniti.com/alexandria/trunk/OmniTI/Mail/Parser.php
|
||||
*
|
||||
* @param string $headerName Header name
|
||||
* @param string $headerValue Header value
|
||||
* @return ParsedMimeHeader[]
|
||||
*/
|
||||
public static function parseContentTypeHeader($headerName, $headerValue)
|
||||
{
|
||||
if (self::isCompositeHeaderValue($headerValue)) {
|
||||
$parsedMimeHeaders = self::parseCompositeValue($headerName, $headerValue);
|
||||
} else {
|
||||
$parsedMimeHeaders = [
|
||||
new ParsedMimeHeader($headerName, trim($headerValue))
|
||||
];
|
||||
}
|
||||
|
||||
return $parsedMimeHeaders;
|
||||
}
|
||||
|
||||
private static function parseCompositeValue($headerName, $headerValue)
|
||||
{
|
||||
$parsedMimeHeaders = [];
|
||||
list($value, $remainder) = explode(';', $headerValue, 2);
|
||||
$value = trim($value);
|
||||
$parsedMimeHeaders[] = new ParsedMimeHeader($headerName, $value);
|
||||
$remainder = trim($remainder);
|
||||
while (strlen($remainder) > 0) {
|
||||
if (!preg_match('/^([a-zA-Z0-9_-]+)=(.{1})/', $remainder, $matches)) {
|
||||
break;
|
||||
}
|
||||
$name = $matches[1];
|
||||
$delimiter = $matches[2];
|
||||
$remainder = substr($remainder, strlen($name) + 1);
|
||||
// preg_match migrated from https://github.com/progmancod/BeSimpleSoap/commit/6bc8f6a467616c934b0a9792f0efece55054db97
|
||||
if (!preg_match('/([^;]+)(;\s*|\s*$)/', $remainder, $matches)) {
|
||||
break;
|
||||
}
|
||||
$value = rtrim($matches[1], ';');
|
||||
if ($delimiter == "'" || $delimiter == '"') {
|
||||
$value = trim($value, $delimiter);
|
||||
}
|
||||
$remainder = substr($remainder, strlen($matches[0]));
|
||||
$parsedMimeHeaders[] = new ParsedMimeHeader($headerName, $name, $value);
|
||||
}
|
||||
|
||||
return $parsedMimeHeaders;
|
||||
}
|
||||
|
||||
private static function isCompositeHeaderValue($headerValue)
|
||||
{
|
||||
return strpos($headerValue, ';');
|
||||
}
|
||||
}
|
37
src/BeSimple/SoapCommon/Mime/Parser/ParsedMimeHeader.php
Normal file
37
src/BeSimple/SoapCommon/Mime/Parser/ParsedMimeHeader.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapCommon\Mime\Parser;
|
||||
|
||||
class ParsedMimeHeader
|
||||
{
|
||||
private $name;
|
||||
private $value;
|
||||
private $subValue;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param string|null $subValue
|
||||
*/
|
||||
public function __construct($name, $value, $subValue = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->subValue = $subValue;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getSubValue()
|
||||
{
|
||||
return $this->subValue;
|
||||
}
|
||||
}
|
34
src/BeSimple/SoapCommon/Mime/Parser/ParsedPart.php
Normal file
34
src/BeSimple/SoapCommon/Mime/Parser/ParsedPart.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapCommon\Mime\Parser;
|
||||
|
||||
use BeSimple\SoapCommon\Mime\Part;
|
||||
|
||||
class ParsedPart
|
||||
{
|
||||
const PART_IS_MAIN = true;
|
||||
const PART_IS_NOT_MAIN = false;
|
||||
|
||||
private $part;
|
||||
private $isMain;
|
||||
|
||||
/**
|
||||
* @param Part $part
|
||||
* @param bool $isMain
|
||||
*/
|
||||
public function __construct(Part $part, $isMain)
|
||||
{
|
||||
$this->part = $part;
|
||||
$this->isMain = $isMain;
|
||||
}
|
||||
|
||||
public function getPart()
|
||||
{
|
||||
return $this->part;
|
||||
}
|
||||
|
||||
public function isMain()
|
||||
{
|
||||
return $this->isMain;
|
||||
}
|
||||
}
|
60
src/BeSimple/SoapCommon/Mime/Parser/ParsedPartList.php
Normal file
60
src/BeSimple/SoapCommon/Mime/Parser/ParsedPartList.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapCommon\Mime\Parser;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ParsedPartList
|
||||
{
|
||||
private $parts;
|
||||
|
||||
/**
|
||||
* @param ParsedPart[] $parts
|
||||
*/
|
||||
public function __construct(array $parts)
|
||||
{
|
||||
$this->parts = $parts;
|
||||
}
|
||||
|
||||
public function getMainPartCount()
|
||||
{
|
||||
$mainPartsCount = 0;
|
||||
foreach ($this->getParts() as $parsedPart) {
|
||||
if ($parsedPart->isMain() === true) {
|
||||
$mainPartsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return $mainPartsCount;
|
||||
}
|
||||
|
||||
public function hasExactlyOneMainPart()
|
||||
{
|
||||
return $this->getMainPartCount() === 1;
|
||||
}
|
||||
|
||||
public function getPartContentIds()
|
||||
{
|
||||
$partContentIds = [];
|
||||
foreach ($this->getParts() as $parsedPart) {
|
||||
$partContentIds[] = $parsedPart->getPart()->getContentId();
|
||||
}
|
||||
|
||||
return $partContentIds;
|
||||
}
|
||||
|
||||
public function getParts()
|
||||
{
|
||||
return $this->parts;
|
||||
}
|
||||
|
||||
public function getPartCount()
|
||||
{
|
||||
return count($this->parts);
|
||||
}
|
||||
|
||||
public function hasParts()
|
||||
{
|
||||
return $this->getPartCount() > 0;
|
||||
}
|
||||
}
|
@ -28,57 +28,38 @@ use BeSimple\SoapCommon\Helper;
|
||||
*/
|
||||
class Part extends PartHeader
|
||||
{
|
||||
/**
|
||||
* Encoding type base 64
|
||||
*/
|
||||
const ENCODING_BASE64 = 'base64';
|
||||
|
||||
/**
|
||||
* Encoding type binary
|
||||
*/
|
||||
const ENCODING_BINARY = 'binary';
|
||||
|
||||
/**
|
||||
* Encoding type eight bit
|
||||
*/
|
||||
const ENCODING_EIGHT_BIT = '8bit';
|
||||
|
||||
/**
|
||||
* Encoding type seven bit
|
||||
*/
|
||||
const ENCODING_SEVEN_BIT = '7bit';
|
||||
|
||||
/**
|
||||
* Encoding type quoted printable
|
||||
*/
|
||||
const ENCODING_QUOTED_PRINTABLE = 'quoted-printable';
|
||||
|
||||
/**
|
||||
* Content.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
const CHARSET_UTF8 = 'utf-8';
|
||||
|
||||
const CONTENT_TYPE_STREAM = 'application/octet-stream';
|
||||
const CONTENT_TYPE_PDF = 'application/pdf';
|
||||
|
||||
/** @var mixed */
|
||||
protected $content;
|
||||
|
||||
/**
|
||||
* Construct new mime object.
|
||||
*
|
||||
* @param mixed $content Content
|
||||
* @param string $contentType Content type
|
||||
* @param string $charset Charset
|
||||
* @param string $encoding Encoding
|
||||
* @param string $contentId Content id
|
||||
*
|
||||
*/
|
||||
public function __construct($content = null, $contentType = 'application/octet-stream', $charset = null, $encoding = self::ENCODING_BINARY, $contentId = null)
|
||||
{
|
||||
public function __construct(
|
||||
$content = null,
|
||||
$contentType = self::CONTENT_TYPE_STREAM,
|
||||
$charset = self::CHARSET_UTF8,
|
||||
$encoding = self::ENCODING_BINARY,
|
||||
$contentId = null
|
||||
) {
|
||||
$this->content = $content;
|
||||
|
||||
$this->setHeader('Content-Type', $contentType);
|
||||
if (!is_null($charset)) {
|
||||
$this->setHeader('Content-Type', 'charset', $charset);
|
||||
} else {
|
||||
$this->setHeader('Content-Type', 'charset', 'utf-8');
|
||||
}
|
||||
$this->setHeader('Content-Type', 'charset', $charset);
|
||||
$this->setHeader('Content-Transfer-Encoding', $encoding);
|
||||
if (is_null($contentId)) {
|
||||
$contentId = $this->generateContentId();
|
||||
@ -106,6 +87,16 @@ class Part extends PartHeader
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function hasContentId($contentTypeContentId)
|
||||
{
|
||||
return $contentTypeContentId === $this->getContentId();
|
||||
}
|
||||
|
||||
public function getContentId()
|
||||
{
|
||||
return $this->getHeader('Content-ID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set mime content.
|
||||
*
|
||||
@ -137,10 +128,10 @@ class Part extends PartHeader
|
||||
{
|
||||
$encoding = strtolower($this->getHeader('Content-Transfer-Encoding'));
|
||||
$charset = strtolower($this->getHeader('Content-Type', 'charset'));
|
||||
if ($charset != 'utf-8') {
|
||||
$content = iconv('utf-8', $charset . '//TRANSLIT', $this->content);
|
||||
if ($charset !== self::CHARSET_UTF8) {
|
||||
$content = iconv(self::CHARSET_UTF8, $charset.'//TRANSLIT', $this->getContent());
|
||||
} else {
|
||||
$content = $this->content;
|
||||
$content = $this->getContent();
|
||||
}
|
||||
switch ($encoding) {
|
||||
case self::ENCODING_BASE64:
|
||||
|
33
src/BeSimple/SoapCommon/Mime/PartFactory.php
Normal file
33
src/BeSimple/SoapCommon/Mime/PartFactory.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapCommon\Mime;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
|
||||
class PartFactory
|
||||
{
|
||||
public static function createFromSoapAttachment(SoapAttachment $attachment)
|
||||
{
|
||||
return new Part(
|
||||
$attachment->getContent(),
|
||||
Part::CONTENT_TYPE_PDF,
|
||||
Part::CHARSET_UTF8,
|
||||
Part::ENCODING_BINARY,
|
||||
$attachment->getId()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
* @return Part[]
|
||||
*/
|
||||
public static function createAttachmentParts(array $attachments = [])
|
||||
{
|
||||
$parts = [];
|
||||
foreach ($attachments as $attachment) {
|
||||
$parts[] = self::createFromSoapAttachment($attachment);
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ namespace BeSimple\SoapCommon;
|
||||
* the chain-of-responsibility pattern).
|
||||
*
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
* @author Petr Bechyně <petr.bechyne@vodafone.com>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapKernel
|
||||
{
|
||||
@ -20,7 +20,7 @@ class SoapKernel
|
||||
* @param int $attachmentType = SoapOptions::SOAP_ATTACHMENTS_TYPE_SWA|SoapOptions::ATTACHMENTS_TYPE_MTOM|SoapOptions::ATTACHMENTS_TYPE_BASE64
|
||||
* @return SoapRequest
|
||||
*/
|
||||
public function filterRequest(SoapRequest $request, array $filters, $attachmentType)
|
||||
public static function filterRequest(SoapRequest $request, array $filters, $attachmentType)
|
||||
{
|
||||
foreach ($filters as $filter) {
|
||||
if ($filter instanceof SoapRequestFilter) {
|
||||
@ -37,9 +37,9 @@ class SoapKernel
|
||||
* @param SoapResponse $response SOAP response
|
||||
* @param SoapRequestFilter[]|SoapResponseFilter[] $filters
|
||||
* @param int $attachmentType = SoapOptions::SOAP_ATTACHMENTS_TYPE_SWA|SoapOptions::ATTACHMENTS_TYPE_MTOM|SoapOptions::ATTACHMENTS_TYPE_BASE64
|
||||
* @return SoapResponse
|
||||
* @return \BeSimple\SoapClient\SoapResponse|\BeSimple\SoapServer\SoapResponse
|
||||
*/
|
||||
public function filterResponse(SoapResponse $response, array $filters, $attachmentType)
|
||||
public static function filterResponse(SoapResponse $response, array $filters, $attachmentType)
|
||||
{
|
||||
foreach ($filters as $filter) {
|
||||
if ($filter instanceof SoapResponseFilter) {
|
||||
|
@ -62,7 +62,7 @@ abstract class SoapMessage
|
||||
/**
|
||||
* Mime attachments.
|
||||
*
|
||||
* @var array(\BeSimple\SoapCommon\Mime\Part)
|
||||
* @var \BeSimple\SoapCommon\Mime\Part[]
|
||||
*/
|
||||
protected $attachments;
|
||||
|
||||
|
@ -66,6 +66,7 @@ class SoapOptions
|
||||
$this->soapFeatures = $features;
|
||||
$this->wsdlFile = $wsdlFile;
|
||||
$this->wsdlCacheType = $wsdlCacheType;
|
||||
$this->wsdlCacheDir = $wsdlCacheDir;
|
||||
$this->classMap = $classMap;
|
||||
$this->typeConverterCollection = $typeConverterCollection;
|
||||
$this->attachmentType = $attachmentType;
|
||||
|
@ -18,11 +18,11 @@ use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* @author Petr Bechyně <petr.bechyne@vodafone.com>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapOptionsBuilder
|
||||
{
|
||||
static public function createWithDefaults(
|
||||
public static function createWithDefaults(
|
||||
$wsdlFile,
|
||||
$wsdlCacheType = SoapOptions::SOAP_CACHE_TYPE_NONE,
|
||||
$wsdlCacheDir = null
|
||||
@ -30,16 +30,37 @@ class SoapOptionsBuilder
|
||||
return self::createWithClassMap($wsdlFile, new ClassMap(), $wsdlCacheType, $wsdlCacheDir);
|
||||
}
|
||||
|
||||
static public function createSwaWithClassMap(
|
||||
public static function createSwaWithClassMap(
|
||||
$wsdlFile,
|
||||
ClassMap $classMap,
|
||||
$wsdlCacheType = SoapOptions::SOAP_CACHE_TYPE_NONE,
|
||||
$wsdlCacheDir = null
|
||||
) {
|
||||
return self::createWithClassMap($wsdlFile, $classMap, $wsdlCacheType, $wsdlCacheDir, SoapOptions::SOAP_ATTACHMENTS_TYPE_SWA);
|
||||
return self::createWithClassMap(
|
||||
$wsdlFile,
|
||||
$classMap,
|
||||
$wsdlCacheType,
|
||||
$wsdlCacheDir,
|
||||
SoapOptions::SOAP_ATTACHMENTS_TYPE_SWA
|
||||
);
|
||||
}
|
||||
|
||||
static public function createWithClassMap(
|
||||
public static function createSwaWithClassMapV11(
|
||||
$wsdlFile,
|
||||
ClassMap $classMap,
|
||||
$wsdlCacheType = SoapOptions::SOAP_CACHE_TYPE_NONE,
|
||||
$wsdlCacheDir = null
|
||||
) {
|
||||
return self::createWithClassMapV11(
|
||||
$wsdlFile,
|
||||
$classMap,
|
||||
$wsdlCacheType,
|
||||
$wsdlCacheDir,
|
||||
SoapOptions::SOAP_ATTACHMENTS_TYPE_SWA
|
||||
);
|
||||
}
|
||||
|
||||
public static function createWithClassMap(
|
||||
$wsdlFile,
|
||||
ClassMap $classMap,
|
||||
$wsdlCacheType = SoapOptions::SOAP_CACHE_TYPE_NONE,
|
||||
@ -54,7 +75,8 @@ class SoapOptionsBuilder
|
||||
throw new InvalidArgumentException('Cache dir must be set for this wsdl cache type');
|
||||
}
|
||||
}
|
||||
$soapOptions = new SoapOptions(
|
||||
|
||||
return new SoapOptions(
|
||||
SoapOptions::SOAP_VERSION_1_2,
|
||||
SoapOptions::SOAP_ENCODING_UTF8,
|
||||
SoapOptions::SOAP_CONNECTION_KEEP_ALIVE_OFF,
|
||||
@ -68,7 +90,37 @@ class SoapOptionsBuilder
|
||||
new TypeConverterCollection(),
|
||||
$attachmentType
|
||||
);
|
||||
}
|
||||
|
||||
return $soapOptions;
|
||||
public static function createWithClassMapV11(
|
||||
$wsdlFile,
|
||||
ClassMap $classMap,
|
||||
$wsdlCacheType = SoapOptions::SOAP_CACHE_TYPE_NONE,
|
||||
$wsdlCacheDir = null,
|
||||
$attachmentType = null
|
||||
) {
|
||||
if (!Cache::hasType($wsdlCacheType)) {
|
||||
throw new InvalidArgumentException('Invalid cache type');
|
||||
}
|
||||
if ($wsdlCacheType !== SoapOptions::SOAP_CACHE_TYPE_NONE) {
|
||||
if ($wsdlCacheDir === null) {
|
||||
throw new InvalidArgumentException('Cache dir must be set for this wsdl cache type');
|
||||
}
|
||||
}
|
||||
|
||||
return new SoapOptions(
|
||||
SoapOptions::SOAP_VERSION_1_1,
|
||||
SoapOptions::SOAP_ENCODING_UTF8,
|
||||
SoapOptions::SOAP_CONNECTION_KEEP_ALIVE_OFF,
|
||||
new SoapFeatures([
|
||||
SoapFeatures::SINGLE_ELEMENT_ARRAYS
|
||||
]),
|
||||
$wsdlFile,
|
||||
$wsdlCacheType,
|
||||
$wsdlCacheDir,
|
||||
$classMap,
|
||||
new TypeConverterCollection(),
|
||||
$attachmentType
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,19 +7,22 @@ class SoapRequestFactory
|
||||
/**
|
||||
* Factory function for SoapRequest.
|
||||
*
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param string $contentType Content Type
|
||||
* @param string $content Content
|
||||
*
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param string $contentType Content Type
|
||||
* @param string $content Content
|
||||
* @return SoapRequest
|
||||
*/
|
||||
public static function create($location, $action, $version, $contentType, $content = null)
|
||||
{
|
||||
public static function createWithContentType(
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
$contentType,
|
||||
$content = null
|
||||
) {
|
||||
$request = new SoapRequest();
|
||||
// $content is if unmodified from SoapClient not a php string type!
|
||||
$request->setContent((string) $content);
|
||||
$request->setContent($content);
|
||||
$request->setLocation($location);
|
||||
$request->setAction($action);
|
||||
$request->setVersion($version);
|
||||
@ -27,4 +30,29 @@ class SoapRequestFactory
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function for SoapRequest.
|
||||
*
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param string $content Content
|
||||
* @return SoapRequest
|
||||
*/
|
||||
public static function create(
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
$content = null
|
||||
) {
|
||||
|
||||
return self::createWithContentType(
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
SoapRequest::getContentTypeForVersion($version),
|
||||
$content
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -13,14 +13,31 @@
|
||||
|
||||
namespace BeSimple\SoapCommon;
|
||||
|
||||
use BeSimple\SoapCommon\SoapMessage;
|
||||
use BeSimple\SoapClient\SoapResponseTracingData;
|
||||
|
||||
/**
|
||||
* SOAP response message.
|
||||
*
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapResponse extends SoapMessage
|
||||
{
|
||||
/** @var SoapResponseTracingData */
|
||||
protected $tracingData;
|
||||
|
||||
}
|
||||
public function hasTracingData()
|
||||
{
|
||||
return $this->tracingData !== null;
|
||||
}
|
||||
|
||||
public function getTracingData()
|
||||
{
|
||||
return $this->tracingData;
|
||||
}
|
||||
|
||||
public function setTracingData(SoapResponseTracingData $tracingData)
|
||||
{
|
||||
$this->tracingData = $tracingData;
|
||||
}
|
||||
}
|
||||
|
@ -23,43 +23,43 @@ class ClassMapTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testAll()
|
||||
{
|
||||
$classmap = new ClassMap();
|
||||
$classMap = new ClassMap();
|
||||
|
||||
$this->assertSame(array(), $classmap->getAll());
|
||||
$this->assertSame([], $classMap->getAll());
|
||||
}
|
||||
|
||||
public function testAdd()
|
||||
{
|
||||
$classmap = new ClassMap();
|
||||
$classMap = new ClassMap();
|
||||
|
||||
$classmap->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
$classMap->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$classmap->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
$classMap->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
}
|
||||
|
||||
public function testGet()
|
||||
{
|
||||
$classmap = new ClassMap();
|
||||
$classMap = new ClassMap();
|
||||
|
||||
$classmap->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
$this->assertSame('BeSimple\SoapCommon\ClassMap', $classmap->get('foobar'));
|
||||
$classMap->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
$this->assertSame('BeSimple\SoapCommon\ClassMap', $classMap->get('foobar'));
|
||||
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$classmap->get('bar');
|
||||
$this->setExpectedException('Exception');
|
||||
$classMap->get('bar');
|
||||
}
|
||||
|
||||
public function testAddClassMap()
|
||||
{
|
||||
$classmap1 = new ClassMap();
|
||||
$classmap2 = new ClassMap();
|
||||
$classMap1 = new ClassMap();
|
||||
$classMap2 = new ClassMap();
|
||||
|
||||
$classmap2->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
$classmap1->addClassMap($classmap2);
|
||||
$classMap2->add('foobar', 'BeSimple\SoapCommon\ClassMap');
|
||||
$classMap1->addClassMap($classMap2);
|
||||
|
||||
$this->assertEquals(array('foobar' => 'BeSimple\SoapCommon\ClassMap'), $classmap1->getAll());
|
||||
$this->assertEquals(['foobar' => 'BeSimple\SoapCommon\ClassMap'], $classMap1->getAll());
|
||||
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$classmap1->addClassMap($classmap2);
|
||||
$this->setExpectedException('Exception');
|
||||
$classMap1->addClassMap($classMap2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use BeSimple\SoapCommon\Mime\Part as MimePart;
|
||||
use BeSimple\SoapCommon\Mime\Part;
|
||||
use BeSimple\SoapCommon\SoapRequest;
|
||||
use BeSimple\SoapCommon\SoapRequestFilter;
|
||||
use BeSimple\SoapCommon\SoapResponse;
|
||||
use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse;
|
||||
use BeSimple\SoapCommon\SoapResponseFilter;
|
||||
|
||||
/**
|
||||
@ -47,7 +47,7 @@ class MimeFilter implements SoapRequestFilter, SoapResponseFilter
|
||||
return $request;
|
||||
}
|
||||
|
||||
public function filterResponse(SoapResponse $response, $attachmentType)
|
||||
public function filterResponse(CommonSoapResponse $response, $attachmentType)
|
||||
{
|
||||
$attachmentsToSend = $response->getAttachments();
|
||||
if (count($attachmentsToSend) > 0) {
|
||||
|
@ -13,24 +13,30 @@
|
||||
namespace BeSimple\SoapServer;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapCommon\Mime\Part;
|
||||
use BeSimple\SoapClient\SoapResponseTracingData;
|
||||
use BeSimple\SoapCommon\Mime\PartFactory;
|
||||
use BeSimple\SoapCommon\SoapMessage;
|
||||
|
||||
class SoapResponseFactory
|
||||
{
|
||||
/**
|
||||
* Factory function for SoapResponse.
|
||||
* Factory function for SoapServer\SoapResponse.
|
||||
*
|
||||
* @param string $content Content
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
* @param string $content Content
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
*
|
||||
* @return SoapResponse
|
||||
*/
|
||||
public static function create($content, $location, $action, $version, $attachments = [])
|
||||
{
|
||||
public static function create(
|
||||
$content,
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
array $attachments = []
|
||||
) {
|
||||
$response = new SoapResponse();
|
||||
$response->setContent($content);
|
||||
$response->setLocation($location);
|
||||
@ -38,10 +44,9 @@ class SoapResponseFactory
|
||||
$response->setVersion($version);
|
||||
$contentType = SoapMessage::getContentTypeForVersion($version);
|
||||
$response->setContentType($contentType);
|
||||
|
||||
if (count($attachments) > 0) {
|
||||
$response->setAttachments(
|
||||
self::createAttachmentParts($attachments)
|
||||
PartFactory::createAttachmentParts($attachments)
|
||||
);
|
||||
}
|
||||
|
||||
@ -49,23 +54,39 @@ class SoapResponseFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
* @return Part[]
|
||||
* Factory function for SoapServer\SoapResponse.
|
||||
*
|
||||
* @param string $content Content
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param SoapResponseTracingData $tracingData Data value object suitable for tracing SOAP traffic
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
*
|
||||
* @return SoapResponse
|
||||
*/
|
||||
private static function createAttachmentParts(array $attachments = [])
|
||||
{
|
||||
$parts = [];
|
||||
foreach ($attachments as $attachment) {
|
||||
$part = new Part(
|
||||
$attachment->getContent(),
|
||||
'application/pdf',
|
||||
'utf-8',
|
||||
Part::ENCODING_BINARY,
|
||||
$attachment->getId()
|
||||
public static function createWithTracingData(
|
||||
$content,
|
||||
$location,
|
||||
$action,
|
||||
$version,
|
||||
SoapResponseTracingData $tracingData,
|
||||
array $attachments = []
|
||||
) {
|
||||
$response = new SoapResponse();
|
||||
$response->setContent($content);
|
||||
$response->setLocation($location);
|
||||
$response->setAction($action);
|
||||
$response->setVersion($version);
|
||||
$response->setTracingData($tracingData);
|
||||
$contentType = SoapMessage::getContentTypeForVersion($version);
|
||||
$response->setContentType($contentType);
|
||||
if (count($attachments) > 0) {
|
||||
$response->setAttachments(
|
||||
PartFactory::createAttachmentParts($attachments)
|
||||
);
|
||||
$parts[] = $part;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ use InvalidArgumentException;
|
||||
*
|
||||
* @author Andreas Schamberger <mail@andreass.net>
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
* @author Petr Bechyně <petr.bechyne@vodafone.com>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapServer extends \SoapServer
|
||||
{
|
||||
@ -85,16 +85,15 @@ class SoapServer extends \SoapServer
|
||||
*/
|
||||
public function createRequest($requestUrl, $soapAction, $requestContentType, $requestContent = null)
|
||||
{
|
||||
$soapRequest = SoapRequestFactory::create(
|
||||
$soapRequest = SoapRequestFactory::createWithContentType(
|
||||
$requestUrl,
|
||||
$soapAction,
|
||||
$this->soapVersion,
|
||||
$requestContentType,
|
||||
$requestContent
|
||||
);
|
||||
$soapKernel = new SoapKernel();
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapRequest = $soapKernel->filterRequest(
|
||||
$soapRequest = SoapKernel::filterRequest(
|
||||
$soapRequest,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
@ -180,7 +179,7 @@ class SoapServer extends \SoapServer
|
||||
* @param SoapAttachment[] $attachments
|
||||
* @return SoapResponse
|
||||
*/
|
||||
private function createResponse($requestLocation, $soapAction, $soapVersion, $responseContent = null, $attachments = [])
|
||||
private function createResponse($requestLocation, $soapAction, $soapVersion, $responseContent = null, array $attachments = [])
|
||||
{
|
||||
$soapResponse = SoapResponseFactory::create(
|
||||
$responseContent,
|
||||
@ -189,9 +188,8 @@ class SoapServer extends \SoapServer
|
||||
$soapVersion,
|
||||
$attachments
|
||||
);
|
||||
$soapKernel = new SoapKernel();
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapResponse = $soapKernel->filterResponse(
|
||||
$soapResponse = SoapKernel::filterResponse(
|
||||
$soapResponse,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
|
@ -18,7 +18,7 @@ use BeSimple\SoapServer\SoapOptions\SoapServerOptions;
|
||||
/**
|
||||
* SoapServerBuilder provides a SoapServer instance from SoapServerOptions and SoapOptions.
|
||||
*
|
||||
* @author Petr Bechyně <petr.bechyne@vodafone.com>
|
||||
* @author Petr Bechyně <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapServerBuilder
|
||||
{
|
||||
|
35
src/BeSimple/SoapServer/Tests/Attachment/Attachment.php
Normal file
35
src/BeSimple/SoapServer/Tests/Attachment/Attachment.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests\Attachment;
|
||||
|
||||
class Attachment
|
||||
{
|
||||
/**
|
||||
* @var string $fileName
|
||||
*/
|
||||
public $fileName;
|
||||
|
||||
/**
|
||||
* @var string $content
|
||||
*/
|
||||
public $contentType;
|
||||
|
||||
/**
|
||||
* @var string $content
|
||||
*/
|
||||
public $content;
|
||||
|
||||
/**
|
||||
* Attachment constructor.
|
||||
*
|
||||
* @param string $fileName
|
||||
* @param string $contentType
|
||||
* @param string $content
|
||||
*/
|
||||
public function __construct($fileName, $contentType, $content)
|
||||
{
|
||||
$this->fileName = $fileName;
|
||||
$this->contentType = $contentType;
|
||||
$this->content = $content;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests\Attachment;
|
||||
|
||||
class AttachmentCollection
|
||||
{
|
||||
/**
|
||||
* @var Attachment[] $attachments
|
||||
*/
|
||||
public $attachments;
|
||||
|
||||
public function __construct(array $attachments = null)
|
||||
{
|
||||
$this->attachments = $attachments;
|
||||
}
|
||||
|
||||
public function hasAttachments()
|
||||
{
|
||||
return $this->attachments !== null && count($this->attachments) > 0;
|
||||
}
|
||||
}
|
106
src/BeSimple/SoapServer/Tests/DummyService.php
Normal file
106
src/BeSimple/SoapServer/Tests/DummyService.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapCommon\AttachmentsHandlerInterface;
|
||||
use BeSimple\SoapCommon\Storage\RequestHandlerAttachmentsStorage;
|
||||
use BeSimple\SoapServer\Tests\Attachment\Attachment;
|
||||
use BeSimple\SoapServer\Tests\Attachment\AttachmentCollection;
|
||||
use ReflectionClass;
|
||||
|
||||
class DummyService implements AttachmentsHandlerInterface
|
||||
{
|
||||
/** @var RequestHandlerAttachmentsStorage */
|
||||
private $requestHandlerAttachmentsStorage;
|
||||
|
||||
public function addAttachmentStorage(RequestHandlerAttachmentsStorage $requestHandlerAttachmentsStorage)
|
||||
{
|
||||
$this->requestHandlerAttachmentsStorage = $requestHandlerAttachmentsStorage;
|
||||
}
|
||||
|
||||
public function getAttachmentStorage()
|
||||
{
|
||||
return $this->requestHandlerAttachmentsStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
return [
|
||||
'DummyServiceResponse' => DummyServiceResponse::class,
|
||||
'DummyServiceResponseWithAttachments' => DummyServiceResponseWithAttachments::class,
|
||||
'DummyServiceRequest' => DummyServiceRequest::class,
|
||||
'DummyServiceRequestWithAttachments' => DummyServiceRequestWithAttachments::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @exclude
|
||||
* @return string
|
||||
*/
|
||||
public function getWsdlPath()
|
||||
{
|
||||
$class = new ReflectionClass(static::class);
|
||||
|
||||
return __DIR__.DIRECTORY_SEPARATOR.$class->getShortName().'.wsdl';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getEndpoint()
|
||||
{
|
||||
return 'http://my.test/soap/dummyService';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DummyServiceRequest $dummyServiceRequest
|
||||
* @return DummyServiceResponse
|
||||
*/
|
||||
public function dummyServiceMethod(DummyServiceRequest $dummyServiceRequest)
|
||||
{
|
||||
$dummyServiceHandler = new DummyServiceHandler();
|
||||
|
||||
return $dummyServiceHandler->handle($dummyServiceRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DummyServiceRequestWithAttachments $dummyServiceRequestWithAttachments
|
||||
* @return DummyServiceResponseWithAttachments
|
||||
*/
|
||||
public function dummyServiceMethodWithAttachments(DummyServiceRequestWithAttachments $dummyServiceRequestWithAttachments)
|
||||
{
|
||||
if ($dummyServiceRequestWithAttachments->hasAttachments() === true) {
|
||||
$attachmentStorage = $this->getAttachmentStorage();
|
||||
$attachments = [];
|
||||
foreach ($attachmentStorage->getAttachments() as $soapAttachment) {
|
||||
$attachments[] = new Attachment(
|
||||
$soapAttachment->getId(),
|
||||
$soapAttachment->getType(),
|
||||
$soapAttachment->getContent()
|
||||
);
|
||||
}
|
||||
$dummyServiceRequestWithAttachments->attachmentCollection = new AttachmentCollection($attachments);
|
||||
}
|
||||
|
||||
$dummyServiceHandlerWithAttachments = new DummyServiceHandlerWithAttachments();
|
||||
$dummyServiceResponseWithAttachments = $dummyServiceHandlerWithAttachments->handle($dummyServiceRequestWithAttachments);
|
||||
|
||||
if ($dummyServiceResponseWithAttachments->hasAttachments() === true) {
|
||||
$soapAttachments = [];
|
||||
foreach ($dummyServiceResponseWithAttachments->attachmentCollection->attachments as $attachment) {
|
||||
$soapAttachments[] = new SoapAttachment(
|
||||
$attachment->fileName,
|
||||
$attachment->contentType,
|
||||
$attachment->content
|
||||
);
|
||||
}
|
||||
$this->addAttachmentStorage(new RequestHandlerAttachmentsStorage($soapAttachments));
|
||||
}
|
||||
|
||||
return $dummyServiceResponseWithAttachments;
|
||||
}
|
||||
}
|
92
src/BeSimple/SoapServer/Tests/DummyService.wsdl
Normal file
92
src/BeSimple/SoapServer/Tests/DummyService.wsdl
Normal file
@ -0,0 +1,92 @@
|
||||
<?xml version="1.0"?>
|
||||
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://schema.testcase" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://schema.testcase">
|
||||
<wsdl:types>
|
||||
<xsd:schema targetNamespace="http://schema.testcase">
|
||||
<xsd:complexType name="SoapHeaderEntity">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="user" type="xsd:string" minOccurs="1">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>User name for authorization</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="SoapHeader" type="tns:SoapHeaderEntity"/>
|
||||
<xsd:complexType name="DummyServiceRequest">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="dummyAttribute" type="xsd:int" minOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="DummyServiceResponse">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="status" type="xsd:boolean" minOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="DummyServiceRequestWithAttachments">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="dummyAttribute" type="xsd:int" minOccurs="1"/>
|
||||
<xsd:element name="includeAttachments" type="xsd:boolean" minOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="DummyServiceResponseWithAttachments">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="status" type="xsd:boolean" minOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
||||
</wsdl:types>
|
||||
<message name="SoapHeader">
|
||||
<part name="SoapHeader" element="tns:SoapHeader"/>
|
||||
</message>
|
||||
<message name="DummyServiceRequest">
|
||||
<part name="request" type="tns:DummyServiceRequest"/>
|
||||
</message>
|
||||
<message name="DummyServiceRequestWithAttachments">
|
||||
<part name="request" type="tns:DummyServiceRequestWithAttachments"/>
|
||||
</message>
|
||||
<message name="DummyServiceResponse">
|
||||
<part name="dummyServiceReturn" type="tns:DummyServiceResponse"/>
|
||||
</message>
|
||||
<message name="DummyServiceResponseWithAttachments">
|
||||
<part name="dummyServiceReturn" type="tns:DummyServiceResponseWithAttachments"/>
|
||||
</message>
|
||||
<wsdl:portType name="DummyServiceSoapPortType">
|
||||
<wsdl:operation name="dummyServiceMethod">
|
||||
<wsdl:input message="tns:DummyServiceRequest"/>
|
||||
<wsdl:output message="tns:DummyServiceResponse"/>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="dummyServiceMethodWithAttachments">
|
||||
<wsdl:input message="tns:DummyServiceRequestWithAttachments"/>
|
||||
<wsdl:output message="tns:DummyServiceResponseWithAttachments"/>
|
||||
</wsdl:operation>
|
||||
</wsdl:portType>
|
||||
<binding name="DummyServiceSoapBinding" type="tns:DummyServiceSoapPortType">
|
||||
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
|
||||
<wsdl:operation name="dummyServiceMethod">
|
||||
<soap:operation soapAction="DummyService.dummyServiceMethod" style="rpc"/>
|
||||
<wsdl:input>
|
||||
<soap:header use="literal" message="tns:SoapHeader" part="SoapHeader" namespace="http://schema.testcase"/>
|
||||
<soap:body use="literal" part="request" namespace="http://schema.testcase"/>
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" namespace="http://schema.testcase"/>
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
<wsdl:operation name="dummyServiceMethodWithAttachments">
|
||||
<soap:operation soapAction="DummyService.dummyServiceMethodWithAttachments" style="rpc"/>
|
||||
<wsdl:input>
|
||||
<soap:header use="literal" message="tns:SoapHeader" part="SoapHeader" namespace="http://schema.testcase"/>
|
||||
<soap:body use="literal" part="request" namespace="http://schema.testcase"/>
|
||||
</wsdl:input>
|
||||
<wsdl:output>
|
||||
<soap:body use="literal" namespace="http://schema.testcase"/>
|
||||
</wsdl:output>
|
||||
</wsdl:operation>
|
||||
</binding>
|
||||
<wsdl:service name="DummyService">
|
||||
<xsd:documentation>WSDL file for DummyService</xsd:documentation>
|
||||
<port name="DummyServiceSoapPortType" binding="tns:DummyServiceSoapBinding">
|
||||
<soap:address location="http://schema.testcase"/>
|
||||
</port>
|
||||
</wsdl:service>
|
||||
</wsdl:definitions>
|
18
src/BeSimple/SoapServer/Tests/DummyServiceHandler.php
Normal file
18
src/BeSimple/SoapServer/Tests/DummyServiceHandler.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
class DummyServiceHandler
|
||||
{
|
||||
/**
|
||||
* @param DummyServiceRequest
|
||||
* @return DummyServiceResponse
|
||||
*/
|
||||
public function handle(DummyServiceRequest $request)
|
||||
{
|
||||
$response = new DummyServiceResponse();
|
||||
$response->status = true;
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
use BeSimple\SoapServer\Tests\Attachment\Attachment;
|
||||
use BeSimple\SoapServer\Tests\Attachment\AttachmentCollection;
|
||||
|
||||
class DummyServiceHandlerWithAttachments
|
||||
{
|
||||
/**
|
||||
* @param DummyServiceRequestWithAttachments $request
|
||||
* @return DummyServiceResponseWithAttachments
|
||||
*/
|
||||
public function handle(DummyServiceRequestWithAttachments $request)
|
||||
{
|
||||
$response = new DummyServiceResponseWithAttachments();
|
||||
$response->status = true;
|
||||
if ($request->includeAttachments === true) {
|
||||
if ($request->hasAttachments() === true) {
|
||||
$attachments = [];
|
||||
foreach ($request->attachmentCollection->attachments as $attachment) {
|
||||
$attachments[] = new Attachment($attachment->fileName, $attachment->contentType, $attachment->content);
|
||||
}
|
||||
$response->attachmentCollection = new AttachmentCollection($attachments);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
11
src/BeSimple/SoapServer/Tests/DummyServiceRequest.php
Normal file
11
src/BeSimple/SoapServer/Tests/DummyServiceRequest.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
class DummyServiceRequest
|
||||
{
|
||||
/**
|
||||
* @var int $dummyAttribute
|
||||
*/
|
||||
public $dummyAttribute;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
use BeSimple\SoapServer\Tests\Attachment\AttachmentCollection;
|
||||
|
||||
class DummyServiceRequestWithAttachments
|
||||
{
|
||||
/**
|
||||
* @var int $dummyAttribute
|
||||
*/
|
||||
public $dummyAttribute;
|
||||
|
||||
/**
|
||||
* @var bool $includeAttachments
|
||||
*/
|
||||
public $includeAttachments;
|
||||
|
||||
/**
|
||||
* @var AttachmentCollection $attachmentCollection
|
||||
*/
|
||||
public $attachmentCollection;
|
||||
|
||||
public function hasAttachments()
|
||||
{
|
||||
return $this->attachmentCollection !== null && $this->attachmentCollection->hasAttachments();
|
||||
}
|
||||
}
|
11
src/BeSimple/SoapServer/Tests/DummyServiceResponse.php
Normal file
11
src/BeSimple/SoapServer/Tests/DummyServiceResponse.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
class DummyServiceResponse
|
||||
{
|
||||
/**
|
||||
* @var bool $status
|
||||
*/
|
||||
public $status;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
use BeSimple\SoapServer\Tests\Attachment\AttachmentCollection;
|
||||
|
||||
class DummyServiceResponseWithAttachments
|
||||
{
|
||||
/**
|
||||
* @var bool $status
|
||||
*/
|
||||
public $status;
|
||||
|
||||
/**
|
||||
* @var AttachmentCollection $attachmentCollection
|
||||
*/
|
||||
public $attachmentCollection;
|
||||
|
||||
public function hasAttachments()
|
||||
{
|
||||
return $this->attachmentCollection !== null && $this->attachmentCollection->hasAttachments();
|
||||
}
|
||||
}
|
@ -12,30 +12,139 @@
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
use BeSimple\SoapClient\Tests\SoapClientBuilderTest;
|
||||
use BeSimple\SoapCommon\ClassMap;
|
||||
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use BeSimple\SoapCommon\SoapOptionsBuilder;
|
||||
use BeSimple\SoapServer\SoapOptions\SoapServerOptions;
|
||||
use BeSimple\SoapServer\SoapServerBuilder;
|
||||
use BeSimple\SoapServer\SoapServerOptionsBuilder;
|
||||
|
||||
/**
|
||||
* UnitTest for \BeSimple\SoapServer\SoapServerBuilder
|
||||
*
|
||||
* @author Christian Kerl <christian-kerl@web.de>
|
||||
* @author Petr Bechyne <mail@petrbechyne.com>
|
||||
*/
|
||||
class SoapServerBuilderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testUnconfiguredWsdl()
|
||||
{
|
||||
$builder = $this->getSoapServerBuilder();
|
||||
const TEST_LOCAL_WSDL_UK = SoapClientBuilderTest::TEST_LOCAL_WSDL_UK;
|
||||
const CACHE_DIR = __DIR__ . '/../../../../cache';
|
||||
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$builder->build();
|
||||
public function testSoapOptionsCreateWithDefaults()
|
||||
{
|
||||
$defaultOptions = SoapOptionsBuilder::createWithDefaults(self::TEST_LOCAL_WSDL_UK);
|
||||
|
||||
self::assertInstanceOf(SoapOptions::class, $defaultOptions);
|
||||
self::assertEquals(self::TEST_LOCAL_WSDL_UK, $defaultOptions->getWsdlFile());
|
||||
}
|
||||
|
||||
public function testUnconfiguredHandler()
|
||||
public function testSoapClientOptionsCreateWithDefaults()
|
||||
{
|
||||
$builder = $this->getSoapServerBuilder();
|
||||
$builder->withWsdl('my.wsdl');
|
||||
$defaultOptions = SoapServerOptionsBuilder::createWithDefaults(new SoapServerHandler);
|
||||
|
||||
$this->setExpectedException('InvalidArgumentException');
|
||||
$builder->build();
|
||||
self::assertInstanceOf(SoapServerOptions::class, $defaultOptions);
|
||||
self::assertInstanceOf(SoapServerHandler::class, $defaultOptions->getHandlerInstance());
|
||||
}
|
||||
|
||||
public function testSoapServerBuilderBuild()
|
||||
{
|
||||
$soapServer = $this->getSoapServerBuilder()->build(
|
||||
SoapServerOptionsBuilder::createWithDefaults(new SoapServerHandler),
|
||||
SoapOptionsBuilder::createWithDefaults(self::TEST_LOCAL_WSDL_UK)
|
||||
);
|
||||
$soapRequest = $soapServer->createRequest('request-url', 'soap-action', 'content/type', 'request-content');
|
||||
|
||||
self::assertEquals('content/type', $soapRequest->getContentType());
|
||||
self::assertEquals('soap-action', $soapRequest->getAction());
|
||||
self::assertEquals('request-content', $soapRequest->getContent());
|
||||
self::assertFalse($soapRequest->hasAttachments());
|
||||
self::assertNull($soapRequest->getAttachments());
|
||||
}
|
||||
|
||||
public function testHandleRequest()
|
||||
{
|
||||
$dummyService = new DummyService();
|
||||
$classMap = new ClassMap();
|
||||
foreach ($dummyService->getClassMap() as $type => $className) {
|
||||
$classMap->add($type, $className);
|
||||
}
|
||||
$soapServerBuilder = new SoapServerBuilder();
|
||||
$soapServerOptions = SoapServerOptionsBuilder::createWithDefaults($dummyService);
|
||||
$soapOptions = SoapOptionsBuilder::createWithClassMap($dummyService->getWsdlPath(), $classMap);
|
||||
$soapServer = $soapServerBuilder->build($soapServerOptions, $soapOptions);
|
||||
|
||||
$request = $soapServer->createRequest(
|
||||
$dummyService->getEndpoint(),
|
||||
'DummyService.dummyServiceMethod',
|
||||
'text/xml;charset=UTF-8',
|
||||
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'testHandleRequest.message')
|
||||
);
|
||||
$response = $soapServer->handleRequest($request);
|
||||
|
||||
file_put_contents(self::CACHE_DIR . '/SoapServerTestResponse.xml', $response->getContent());
|
||||
|
||||
self::assertNotContains("\r\n", $response->getContent(), 'Response cannot contain CRLF line endings');
|
||||
self::assertContains('dummyServiceMethodResponse', $response->getContent());
|
||||
self::assertSame('DummyService.dummyServiceMethod', $response->getAction());
|
||||
self::assertFalse($response->hasAttachments(), 'Response should not contain attachments');
|
||||
}
|
||||
|
||||
public function testHandleRequestWithSwa()
|
||||
{
|
||||
$dummyService = new DummyService();
|
||||
$classMap = new ClassMap();
|
||||
foreach ($dummyService->getClassMap() as $type => $className) {
|
||||
$classMap->add($type, $className);
|
||||
}
|
||||
$soapServerBuilder = new SoapServerBuilder();
|
||||
$soapServerOptions = SoapServerOptionsBuilder::createWithDefaults($dummyService);
|
||||
$soapOptions = SoapOptionsBuilder::createSwaWithClassMap($dummyService->getWsdlPath(), $classMap);
|
||||
$soapServer = $soapServerBuilder->build($soapServerOptions, $soapOptions);
|
||||
|
||||
$request = $soapServer->createRequest(
|
||||
$dummyService->getEndpoint(),
|
||||
'DummyService.dummyServiceMethodWithAttachments',
|
||||
'text/xml;charset=UTF-8',
|
||||
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'testHandleRequestWithSwa.message')
|
||||
);
|
||||
$response = $soapServer->handleRequest($request);
|
||||
|
||||
file_put_contents(self::CACHE_DIR . '/SoapServerTestResponseFromSwaRequestWithNoAttachments.xml', $response->getContent());
|
||||
|
||||
self::assertNotContains("\r\n", $response->getContent(), 'Response cannot contain CRLF line endings');
|
||||
self::assertContains('dummyServiceMethodWithAttachmentsResponse', $response->getContent());
|
||||
self::assertSame('DummyService.dummyServiceMethodWithAttachments', $response->getAction());
|
||||
self::assertFalse($response->hasAttachments(), 'Response should contain attachments');
|
||||
}
|
||||
|
||||
public function testHandleRequestWithSwaResponse()
|
||||
{
|
||||
$dummyService = new DummyService();
|
||||
$classMap = new ClassMap();
|
||||
foreach ($dummyService->getClassMap() as $type => $className) {
|
||||
$classMap->add($type, $className);
|
||||
}
|
||||
$soapServerBuilder = new SoapServerBuilder();
|
||||
$soapServerOptions = SoapServerOptionsBuilder::createWithDefaults($dummyService);
|
||||
$soapOptions = SoapOptionsBuilder::createSwaWithClassMap($dummyService->getWsdlPath(), $classMap);
|
||||
$soapServer = $soapServerBuilder->build($soapServerOptions, $soapOptions);
|
||||
|
||||
$request = $soapServer->createRequest(
|
||||
$dummyService->getEndpoint(),
|
||||
'DummyService.dummyServiceMethodWithAttachments',
|
||||
'multipart/related; type="text/xml"; start="<rootpart@soapui.org>"; boundary="----=_Part_6_2094841787.1482231370463"',
|
||||
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'testHandleRequestWithSwa.mimepart.message')
|
||||
);
|
||||
$response = $soapServer->handleRequest($request);
|
||||
|
||||
file_put_contents(self::CACHE_DIR . '/SoapServerTestSwaResponseWithAttachments.xml', $response->getContent());
|
||||
|
||||
self::assertNotContains("\r\n", $response->getContent(), 'Response cannot contain CRLF line endings');
|
||||
self::assertContains('dummyServiceMethodWithAttachmentsResponse', $response->getContent());
|
||||
self::assertSame('DummyService.dummyServiceMethodWithAttachments', $response->getAction());
|
||||
self::assertTrue($response->hasAttachments(), 'Response should contain attachments');
|
||||
self::assertCount(2, $response->getAttachments());
|
||||
}
|
||||
|
||||
public function getSoapServerBuilder()
|
||||
|
7
src/BeSimple/SoapServer/Tests/SoapServerHandler.php
Normal file
7
src/BeSimple/SoapServer/Tests/SoapServerHandler.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace BeSimple\SoapServer\Tests;
|
||||
|
||||
class SoapServerHandler
|
||||
{
|
||||
}
|
14
src/BeSimple/SoapServer/Tests/testHandleRequest.message
Normal file
14
src/BeSimple/SoapServer/Tests/testHandleRequest.message
Normal file
@ -0,0 +1,14 @@
|
||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://schema.testcase">
|
||||
<soapenv:Header>
|
||||
<sch:SoapHeader>
|
||||
<user>admin</user>
|
||||
</sch:SoapHeader>
|
||||
</soapenv:Header>
|
||||
<soapenv:Body>
|
||||
<sch:dummyServiceMethod>
|
||||
<request>
|
||||
<dummyAttribute>1</dummyAttribute>
|
||||
</request>
|
||||
</sch:dummyServiceMethod>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
@ -0,0 +1,15 @@
|
||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://schema.testcase">
|
||||
<soapenv:Header>
|
||||
<sch:SoapHeader>
|
||||
<user>admin</user>
|
||||
</sch:SoapHeader>
|
||||
</soapenv:Header>
|
||||
<soapenv:Body>
|
||||
<sch:dummyServiceMethodWithAttachments>
|
||||
<request>
|
||||
<dummyAttribute>2</dummyAttribute>
|
||||
<includeAttachments>false</includeAttachments>
|
||||
</request>
|
||||
</sch:dummyServiceMethodWithAttachments>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
@ -0,0 +1,62 @@
|
||||
|
||||
------=_Part_6_2094841787.1482231370463
|
||||
Content-Type: text/xml; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Content-ID: <rootpart@soapui.org>
|
||||
|
||||
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://schema.testcase">
|
||||
<soapenv:Header>
|
||||
<sch:SoapHeader>
|
||||
<user>admin</user>
|
||||
</sch:SoapHeader>
|
||||
</soapenv:Header>
|
||||
<soapenv:Body>
|
||||
<sch:dummyServiceMethodWithAttachments>
|
||||
<request>
|
||||
<dummyAttribute>3</dummyAttribute>
|
||||
<includeAttachments>true</includeAttachments>
|
||||
</request>
|
||||
</sch:dummyServiceMethodWithAttachments>
|
||||
</soapenv:Body>
|
||||
</soapenv:Envelope>
|
||||
------=_Part_6_2094841787.1482231370463
|
||||
Content-Type: text/html; charset=us-ascii; name=test-page.html
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Content-ID: <test-page.html>
|
||||
Content-Disposition: attachment; name="test-page.html"; filename="test-page.html"
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Test file page</title>
|
||||
<style type="text/css">
|
||||
<!--
|
||||
h1 {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-size: 11pt;
|
||||
}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
------=_Part_6_2094841787.1482231370463
|
||||
Content-Type: application/x-sh; name=testscript.sh
|
||||
Content-Transfer-Encoding: binary
|
||||
Content-ID: <testscript.sh>
|
||||
Content-Disposition: attachment; name="testscript.sh"; filename="testscript.sh"
|
||||
|
||||
#!/bin/sh
|
||||
### ====================================================================== ###
|
||||
## ##
|
||||
## Test Script ##
|
||||
## ##
|
||||
### ====================================================================== ###
|
||||
|
||||
------=_Part_6_2094841787.1482231370463--
|
Loading…
Reference in New Issue
Block a user