Add 'src/BeSimple/SoapCommon/' from commit 'db885b2be7328fd8e663ee256df2d8570daeac3c'

git-subtree-dir: src/BeSimple/SoapCommon
git-subtree-mainline: fa8139be14
git-subtree-split: db885b2be7
This commit is contained in:
Francis Besset 2013-07-19 16:53:31 +02:00
commit 714346c2fc
63 changed files with 4687 additions and 0 deletions

5
src/BeSimple/SoapCommon/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
vendor
/phpunit.xml
.buildpath
.project
.settings

View File

@ -0,0 +1,7 @@
language: php
php:
- 5.3
- 5.4
before_script: composer install --dev --prefer-source

View File

@ -0,0 +1,34 @@
{
"name": "besimple/soap-common",
"type": "library",
"description": "Build and consume SOAP Common based web services",
"keywords": [ "soap", "soap-common" ],
"homepage": "https://github.com/BeSimple/BeSimpleSoapCommon",
"license": "MIT",
"authors": [
{
"name": "Francis Besset",
"email": "francis.besset@gmail.com"
},
{
"name": "Christian Kerl",
"email": "christian-kerl@web.de"
},
{
"name": "Andreas Schamberger",
"email": "mail@andreass.net"
}
],
"require": {
"php": ">=5.3.0",
"ass/xmlsecurity": "dev-master"
},
"require-dev": {
"mikey179/vfsStream": "dev-master"
},
"autoload": {
"psr-0": {
"BeSimple\\SoapCommon": "src/"
}
}
}

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="BeSimple\SoapCommon Test Suite">
<directory>./tests/BeSimple/</directory>
</testsuite>
</testsuites>
<groups>
<exclude>
<group>benchmark</group>
</exclude>
</groups>
<filter>
<whitelist>
<directory>./src/BeSimple/</directory>
</whitelist>
</filter>
</phpunit>

View File

@ -0,0 +1,246 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\SoapCommon;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/**
* @author Christian Kerl <christian-kerl@web.de>
* @author Francis Besset <francis.besset@gmail.com>
*/
abstract class AbstractSoapBuilder
{
protected $wsdl;
protected $soapOptions = array();
/**
* @return AbstractSoapBuilder
*/
static public function createWithDefaults()
{
$builder = new static();
return $builder
->withSoapVersion12()
->withEncoding('UTF-8')
->withSingleElementArrays()
;
}
public function __construct()
{
$this->soapOptions['features'] = 0;
$this->soapOptions['classmap'] = new Classmap();
$this->soapOptions['typemap'] = new TypeConverterCollection();
}
public function getWsdl()
{
return $this->wsdl;
}
public function getSoapOptions()
{
$options = $this->soapOptions;
$options['classmap'] = $this->soapOptions['classmap']->all();
$options['typemap'] = $this->soapOptions['typemap']->getTypemap();
return $options;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdl($wsdl)
{
$this->wsdl = $wsdl;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withSoapVersion11()
{
$this->soapOptions['soap_version'] = SOAP_1_1;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withSoapVersion12()
{
$this->soapOptions['soap_version'] = SOAP_1_2;
return $this;
}
public function withEncoding($encoding)
{
$this->soapOptions['encoding'] = $encoding;
return $this;
}
public function withWsdlCache($cache)
{
if (!in_array($cache, Cache::getTypes(), true)) {
throw new \InvalidArgumentException();
}
$this->soapOptions['cache_wsdl'] = $cache;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheNone()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_NONE;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheDisk()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_DISK;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheMemory()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_MEMORY;
return $this;
}
/**
* @return AbstractSoapBuilder
*/
public function withWsdlCacheDiskAndMemory()
{
$this->soapOptions['cache_wsdl'] = Cache::TYPE_DISK_MEMORY;
return $this;
}
/**
* Enables the SOAP_SINGLE_ELEMENT_ARRAYS feature.
* If enabled arrays containing only one element will be passed as arrays otherwise the single element is extracted and directly passed.
*
* @return AbstractSoapBuilder
*/
public function withSingleElementArrays()
{
$this->soapOptions['features'] |= SOAP_SINGLE_ELEMENT_ARRAYS;
return $this;
}
/**
* Enables the SOAP_WAIT_ONE_WAY_CALLS feature.
*
* @return AbstractSoapBuilder
*/
public function withWaitOneWayCalls()
{
$this->soapOptions['features'] |= SOAP_WAIT_ONE_WAY_CALLS;
return $this;
}
/**
* Enables the SOAP_USE_XSI_ARRAY_TYPE feature.
*
* @return AbstractSoapBuilder
*/
public function withUseXsiArrayType()
{
$this->soapOptions['features'] |= SOAP_USE_XSI_ARRAY_TYPE;
return $this;
}
public function withTypeConverter(TypeConverterInterface $converter)
{
$this->soapOptions['typemap']->add($converter);
return $this;
}
public function withTypeConverters(TypeConverterCollection $converters, $merge = true)
{
if ($merge) {
$this->soapOptions['typemap']->addCollection($converters);
} else {
$this->soapOptions['typemap']->set($converters->all());
}
return $this;
}
/**
* Adds a class mapping to the classmap.
*
* @param string $xmlType
* @param string $phpType
*
* @return AbstractSoapBuilder
*/
public function withClassMapping($xmlType, $phpType)
{
$this->soapOptions['classmap']->add($xmlType, $phpType);
return $this;
}
/**
* Sets the classmap.
*
* @param array $classmap The classmap.
* @param boolean $merge If true the given classmap is merged into the existing one, otherwise the existing one is overwritten.
*
* @return AbstractSoapBuilder
*/
public function withClassmap(Classmap $classmap, $merge = true)
{
if ($merge) {
$this->soapOptions['classmap']->addClassmap($classmap);
} else {
$this->soapOptions['classmap']->set($classmap->all());
}
return $this;
}
protected function validateWsdl()
{
if (null === $this->wsdl) {
throw new \InvalidArgumentException('The WSDL has to be configured!');
}
}
}

View File

@ -0,0 +1,111 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\SoapCommon;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class Cache
{
const DISABLED = 0;
const ENABLED = 1;
const TYPE_NONE = WSDL_CACHE_NONE;
const TYPE_DISK = WSDL_CACHE_DISK;
const TYPE_MEMORY = WSDL_CACHE_MEMORY;
const TYPE_DISK_MEMORY = WSDL_CACHE_BOTH;
static protected $types = array(
self::TYPE_NONE,
self::TYPE_DISK,
self::TYPE_MEMORY,
self::TYPE_DISK_MEMORY,
);
static public function getTypes()
{
return self::$types;
}
static public function isEnabled()
{
return self::iniGet('soap.wsdl_cache_enabled');
}
static public function setEnabled($enabled)
{
if (!in_array($enabled, array(self::ENABLED, self::DISABLED), true)) {
throw new \InvalidArgumentException();
}
self::iniSet('soap.wsdl_cache_enabled', $enabled);
}
static public function getType()
{
return self::iniGet('soap.wsdl_cache');
}
static public 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');
}
self::iniSet('soap.wsdl_cache', $type);
}
static public function getDirectory()
{
return self::iniGet('soap.wsdl_cache_dir');
}
static public function setDirectory($directory)
{
if (!is_dir($directory)) {
mkdir($directory, 0777, true);
}
self::iniSet('soap.wsdl_cache_dir', $directory);
}
static public function getLifetime()
{
return self::iniGet('soap.wsdl_cache_ttl');
}
static public function setLifetime($lifetime)
{
self::iniSet('soap.wsdl_cache_ttl', $lifetime);
}
static public function getLimit()
{
return self::iniGet('soap.wsdl_cache_limit');
}
static public function setLimit($limit)
{
self::iniSet('soap.wsdl_cache_limit', $limit);
}
static protected function iniGet($key)
{
return ini_get($key);
}
static protected function iniSet($key, $value)
{
ini_set($key, $value);
}
}

View File

@ -0,0 +1,93 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class Classmap
{
/**
* @var array
*/
protected $classmap = array();
/**
* @return array
*/
public function all()
{
return $this->classmap;
}
/**
* @param string $type
*
* @return string
*
* @throws \InvalidArgumentException
*/
public function get($type)
{
if (!$this->has($type)) {
throw new \InvalidArgumentException(sprintf('The type "%s" does not exists', $type));
}
return $this->classmap[$type];
}
/**
* @param string $type
* @param string $classname
*
* @throws \InvalidArgumentException
*/
public function add($type, $classname)
{
if ($this->has($type)) {
throw new \InvalidArgumentException(sprintf('The type "%s" already exists', $type));
}
$this->classmap[$type] = $classname;
}
/**
* @param array $classmap
*/
public function set(array $classmap)
{
$this->classmap = array();
foreach ($classmap as $type => $classname) {
$this->add($type, $classname);
}
}
/**
* @param string $type
*
* @return boolean
*/
public function has($type)
{
return isset($this->classmap[$type]);
}
public function addClassmap(Classmap $classmap)
{
foreach ($classmap->all() as $type => $classname) {
$this->add($type, $classname);
}
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Converter;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class DateTimeTypeConverter implements TypeConverterInterface
{
public function getTypeNamespace()
{
return 'http://www.w3.org/2001/XMLSchema';
}
public function getTypeName()
{
return 'dateTime';
}
public function convertXmlToPhp($data)
{
$doc = new \DOMDocument();
$doc->loadXML($data);
if ('' === $doc->textContent) {
return null;
}
return new \DateTime($doc->textContent);
}
public function convertPhpToXml($data)
{
return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d\TH:i:sP'));
}
}

View File

@ -0,0 +1,47 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Converter;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class DateTypeConverter implements TypeConverterInterface
{
public function getTypeNamespace()
{
return 'http://www.w3.org/2001/XMLSchema';
}
public function getTypeName()
{
return 'date';
}
public function convertXmlToPhp($data)
{
$doc = new \DOMDocument();
$doc->loadXML($data);
if ('' === $doc->textContent) {
return null;
}
return new \DateTime($doc->textContent);
}
public function convertPhpToXml($data)
{
return sprintf('<%1$s>%2$s</%1$s>', $this->getTypeName(), $data->format('Y-m-d'));
}
}

View File

@ -0,0 +1,108 @@
<?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\SoapCommon\Converter;
use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\SoapKernel;
use BeSimple\SoapCommon\Converter\SoapKernelAwareInterface;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/**
* MTOM type converter.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class MtomTypeConverter implements TypeConverterInterface, SoapKernelAwareInterface
{
/**
* @var \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
*/
protected $soapKernel = null;
/**
* {@inheritDoc}
*/
public function getTypeNamespace()
{
return 'http://www.w3.org/2001/XMLSchema';
}
/**
* {@inheritDoc}
*/
public function getTypeName()
{
return 'base64Binary';
}
/**
* {@inheritDoc}
*/
public function convertXmlToPhp($data)
{
$doc = new \DOMDocument();
$doc->loadXML($data);
$includes = $doc->getElementsByTagNameNS(Helper::NS_XOP, 'Include');
$include = $includes->item(0);
// convert href -> myhref for external references as PHP throws exception in this case
// http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436
$ref = $include->getAttribute('myhref');
if ('cid:' === substr($ref, 0, 4)) {
$contentId = urldecode(substr($ref, 4));
if (null !== ($part = $this->soapKernel->getAttachment($contentId))) {
return $part->getContent();
} else {
return null;
}
}
return $data;
}
/**
* {@inheritDoc}
*/
public function convertPhpToXml($data)
{
$part = new MimePart($data);
$contentId = trim($part->getHeader('Content-ID'), '<>');
$this->soapKernel->addAttachment($part);
$doc = new \DOMDocument();
$node = $doc->createElement($this->getTypeName());
$doc->appendChild($node);
// add xop:Include element
$xinclude = $doc->createElementNS(Helper::NS_XOP, Helper::PFX_XOP . ':Include');
$xinclude->setAttribute('href', 'cid:' . $contentId);
$node->appendChild($xinclude);
return $doc->saveXML();
}
/**
* {@inheritDoc}
*/
public function setKernel(SoapKernel $soapKernel)
{
$this->soapKernel = $soapKernel;
}
}

View File

@ -0,0 +1,32 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Converter;
use BeSimple\SoapCommon\SoapKernel;
/**
* Internal type converter interface.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
interface SoapKernelAwareInterface
{
/**
* Set SoapKernel instance.
*
* @param \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
*
* @return void
*/
function setKernel(SoapKernel $soapKernel);
}

View File

@ -0,0 +1,96 @@
<?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\SoapCommon\Converter;
use BeSimple\SoapCommon\Helper;
use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\SoapKernel;
use BeSimple\SoapCommon\Converter\SoapKernelAwareInterface;
use BeSimple\SoapCommon\Converter\TypeConverterInterface;
/**
* SwA type converter.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class SwaTypeConverter implements TypeConverterInterface, SoapKernelAwareInterface
{
/**
* @var \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance
*/
protected $soapKernel = null;
/**
* {@inheritDoc}
*/
public function getTypeNamespace()
{
return 'http://www.w3.org/2001/XMLSchema';
}
/**
* {@inheritDoc}
*/
public function getTypeName()
{
return 'base64Binary';
}
/**
* {@inheritDoc}
*/
public function convertXmlToPhp($data)
{
$doc = new \DOMDocument();
$doc->loadXML($data);
// convert href -> myhref for external references as PHP throws exception in this case
// http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436
$ref = $doc->documentElement->getAttribute('myhref');
if ('cid:' === substr($ref, 0, 4)) {
$contentId = urldecode(substr($ref, 4));
if (null !== ($part = $this->soapKernel->getAttachment($contentId))) {
return $part->getContent();
} else {
return null;
}
}
return $data;
}
/**
* {@inheritDoc}
*/
public function convertPhpToXml($data)
{
$part = new MimePart($data);
$contentId = trim($part->getHeader('Content-ID'), '<>');
$this->soapKernel->addAttachment($part);
return sprintf('<%s href="%s"/>', $this->getTypeName(), $contentId);
}
/**
* {@inheritDoc}
*/
public function setKernel(SoapKernel $soapKernel)
{
$this->soapKernel = $soapKernel;
}
}

View File

@ -0,0 +1,88 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Converter;
/**
* @author Christian Kerl <christian-kerl@web.de>
*/
class TypeConverterCollection
{
private $converters = array();
public function all()
{
return array_values($this->converters);
}
public function get($namespace, $name)
{
if (!$this->has($namespace, $name)) {
throw new \InvalidArgumentException(sprintf('The converter "%s %s" does not exists', $namespace, $name));
}
return $this->converters[$namespace.':'.$name];
}
public function add(TypeConverterInterface $converter)
{
if ($this->has($converter->getTypeNamespace(), $converter->getTypeName())) {
throw new \InvalidArgumentException(sprintf('The converter "%s %s" already exists', $converter->getTypeNamespace(), $converter->getTypeName()));
}
$this->converters[$converter->getTypeNamespace().':'.$converter->getTypeName()] = $converter;
}
public function set(array $converters)
{
$this->converters = array();
foreach ($converters as $converter) {
$this->add($converter);
}
}
public function has($namespace, $name)
{
return isset($this->converters[$namespace.':'.$name]);
}
public function addCollection(TypeConverterCollection $converterCollection)
{
foreach ($converterCollection->all() as $converter) {
$this->add($converter);
}
}
/**
* @return array
*/
public function getTypemap()
{
$typemap = array();
foreach ($this->converters as $converter) {
$typemap[] = array(
'type_name' => $converter->getTypeName(),
'type_ns' => $converter->getTypeNamespace(),
'from_xml' => function($input) use ($converter) {
return $converter->convertXmlToPhp($input);
},
'to_xml' => function($input) use ($converter) {
return $converter->convertPhpToXml($input);
},
);
}
return $typemap;
}
}

View File

@ -0,0 +1,53 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Converter;
/**
* Type converter interface.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
interface TypeConverterInterface
{
/**
* Get type namespace.
*
* @return string
*/
function getTypeNamespace();
/**
* Get type name.
*
* @return string
*/
function getTypeName();
/**
* Convert given XML string to PHP type.
*
* @param string $data XML string
*
* @return mixed
*/
function convertXmlToPhp($data);
/**
* Convert PHP type to XML string.
*
* @param mixed $data PHP type
*
* @return string
*/
function convertPhpToXml($data);
}

View File

@ -0,0 +1,178 @@
<?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\SoapCommon;
/**
* Soap request/response filter helper for manipulating SOAP messages.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class FilterHelper
{
/**
* DOMDocument on which the helper functions operate.
*
* @var \DOMDocument
*/
protected $domDocument = null;
/**
* Namespaces added.
*
* @var array(string=>string)
*/
protected $namespaces = array();
/**
* Constructor.
*
* @param \DOMDocument $domDocument SOAP document
*/
public function __construct(\DOMDocument $domDocument)
{
$this->domDocument = $domDocument;
}
/**
* Add new soap header.
*
* @param \DOMElement $node DOMElement to add
* @param boolean $mustUnderstand SOAP header mustUnderstand attribute
* @param string $actor SOAP actor/role
* @param string $soapVersion SOAP version SOAP_1_1|SOAP_1_2
*
* @return void
*/
public function addHeaderElement(\DOMElement $node, $mustUnderstand = null, $actor = null, $soapVersion = SOAP_1_1)
{
$root = $this->domDocument->documentElement;
$namespace = $root->namespaceURI;
$prefix = $root->prefix;
if (null !== $mustUnderstand) {
$node->appendChild(new \DOMAttr($prefix . ':mustUnderstand', (int) $mustUnderstand));
}
if (null !== $actor) {
$attributeName = ($soapVersion == SOAP_1_1) ? 'actor' : 'role';
$node->appendChild(new \DOMAttr($prefix . ':' . $attributeName, $actor));
}
$nodeListHeader = $root->getElementsByTagNameNS($namespace, 'Header');
// add header if not there
if ($nodeListHeader->length == 0) {
// new header element
$header = $this->domDocument->createElementNS($namespace, $prefix . ':Header');
// try to add it before body
$nodeListBody = $root->getElementsByTagNameNS($namespace, 'Body');
if ($nodeListBody->length == 0) {
$root->appendChild($header);
} else {
$body = $nodeListBody->item(0);
$header = $body->parentNode->insertBefore($header, $body);
}
$header->appendChild($node);
} else {
$nodeListHeader->item(0)->appendChild($node);
}
}
/**
* Add new soap body element.
*
* @param \DOMElement $node DOMElement to add
*
* @return void
*/
public function addBodyElement(\DOMElement $node)
{
$root = $this->domDocument->documentElement;
$namespace = $root->namespaceURI;
$prefix = $root->prefix;
$nodeList = $this->domDocument->getElementsByTagNameNS($namespace, 'Body');
// add body if not there
if ($nodeList->length == 0) {
// new body element
$body = $this->domDocument->createElementNS($namespace, $prefix . ':Body');
$root->appendChild($body);
$body->appendChild($node);
} else {
$nodeList->item(0)->appendChild($node);
}
}
/**
* Add new namespace to root tag.
*
* @param string $prefix Namespace prefix
* @param string $namespaceURI Namespace URI
*
* @return void
*/
public function addNamespace($prefix, $namespaceURI)
{
if (!isset($this->namespaces[$namespaceURI])) {
$root = $this->domDocument->documentElement;
$root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:' . $prefix, $namespaceURI);
$this->namespaces[$namespaceURI] = $prefix;
}
}
/**
* Create new element for given namespace.
*
* @param string $namespaceURI Namespace URI
* @param string $name Element name
* @param string $value Element value
*
* @return \DOMElement
*/
public function createElement($namespaceURI, $name, $value = null)
{
$prefix = $this->namespaces[$namespaceURI];
return $this->domDocument->createElementNS($namespaceURI, $prefix . ':' . $name, $value);
}
/**
* Add new attribute to element with given namespace.
*
* @param \DOMElement $element DOMElement to edit
* @param string $namespaceURI Namespace URI
* @param string $name Attribute name
* @param string $value Attribute value
*
* @return void
*/
public function setAttribute(\DOMElement $element, $namespaceURI, $name, $value)
{
if (null !== $namespaceURI) {
$prefix = $this->namespaces[$namespaceURI];
$element->setAttributeNS($namespaceURI, $prefix . ':' . $name, $value);
} else {
$element->setAttribute($name, $value);
}
}
/**
* Register namespace.
*
* @param string $prefix Namespace prefix
* @param string $namespaceURI Namespace URI
*
* @return void
*/
public function registerNamespace($prefix, $namespaceURI)
{
if (!isset($this->namespaces[$namespaceURI])) {
$this->namespaces[$namespaceURI] = $prefix;
}
}
}

View File

@ -0,0 +1,221 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon;
/**
* Soap helper class with static functions that are used in the client and
* server implementations. It also provides namespace and configuration
* constants.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class Helper
{
/**
* Attachment type: xsd:base64Binary (native in ext/soap).
*/
const ATTACHMENTS_TYPE_BASE64 = 1;
/**
* Attachment type: MTOM (SOAP Message Transmission Optimization Mechanism).
*/
const ATTACHMENTS_TYPE_MTOM = 2;
/**
* Attachment type: SWA (SOAP Messages with Attachments).
*/
const ATTACHMENTS_TYPE_SWA = 4;
/**
* Web Services Security: SOAP Message Security 1.0 (WS-Security 2004)
*/
const NAME_WSS_SMS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0';
/**
* Web Services Security: SOAP Message Security 1.1 (WS-Security 2004)
*/
const NAME_WSS_SMS_1_1 = 'http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1';
/**
* Web Services Security UsernameToken Profile 1.0
*/
const NAME_WSS_UTP = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0';
/**
* Web Services Security X.509 Certificate Token Profile
*/
const NAME_WSS_X509 = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0';
/**
* Soap 1.1 namespace.
*/
const NS_SOAP_1_1 = 'http://schemas.xmlsoap.org/soap/envelope/';
/**
* Soap 1.1 namespace.
*/
const NS_SOAP_1_2 = 'http://www.w3.org/2003/05/soap-envelope/';
/**
* Web Services Addressing 1.0 namespace.
*/
const NS_WSA = 'http://www.w3.org/2005/08/addressing';
/**
* WSDL 1.1 namespace.
*/
const NS_WSDL = 'http://schemas.xmlsoap.org/wsdl/';
/**
* WSDL MIME namespace.
*/
const NS_WSDL_MIME = 'http://schemas.xmlsoap.org/wsdl/mime/';
/**
* WSDL SOAP 1.1 namespace.
*/
const NS_WSDL_SOAP_1_1 = 'http://schemas.xmlsoap.org/wsdl/soap/';
/**
* WSDL SOAP 1.2 namespace.
*/
const NS_WSDL_SOAP_1_2 = 'http://schemas.xmlsoap.org/wsdl/soap12/';
/**
* Web Services Security Extension namespace.
*/
const NS_WSS = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
/**
* Web Services Security Utility namespace.
*/
const NS_WSU = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
/**
* Describing Media Content of Binary Data in XML namespace.
*/
const NS_XMLMIME = 'http://www.w3.org/2004/11/xmlmime';
/**
* XML Schema namespace.
*/
const NS_XML_SCHEMA = 'http://www.w3.org/2001/XMLSchema';
/**
* XML Schema instance namespace.
*/
const NS_XML_SCHEMA_INSTANCE = 'http://www.w3.org/2001/XMLSchema-instance';
/**
* XML-binary Optimized Packaging namespace.
*/
const NS_XOP = 'http://www.w3.org/2004/08/xop/include';
/**
* Web Services Addressing 1.0 prefix.
*/
const PFX_WSA = 'wsa';
/**
* WSDL 1.1 namespace. prefix.
*/
const PFX_WSDL = 'wsdl';
/**
* Web Services Security Extension namespace.
*/
const PFX_WSS = 'wsse';
/**
* Web Services Security Utility namespace prefix.
*/
const PFX_WSU = 'wsu';
/**
* Describing Media Content of Binary Data in XML namespace prefix.
*/
const PFX_XMLMIME = 'xmlmime';
/**
* XML Schema namespace prefix.
*/
const PFX_XML_SCHEMA = 'xsd';
/**
* XML Schema instance namespace prefix.
*/
const PFX_XML_SCHEMA_INSTANCE = 'xsi';
/**
* XML-binary Optimized Packaging namespace prefix.
*/
const PFX_XOP = 'xop';
/**
* Generate a pseudo-random version 4 UUID.
*
* @see http://de.php.net/manual/en/function.uniqid.php#94959
* @return string
*/
public static function generateUUID()
{
return sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
// 32 bits for "time_low"
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
// 16 bits for "time_mid"
mt_rand(0, 0xffff),
// 16 bits for "time_hi_and_version",
// four most significant bits holds version number 4
mt_rand(0, 0x0fff) | 0x4000,
// 16 bits, 8 bits for "clk_seq_hi_res",
// 8 bits for "clk_seq_low",
// two most significant bits holds zero and one for variant DCE1.1
mt_rand(0, 0x3fff) | 0x8000,
// 48 bits for "node"
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
/**
* Get SOAP namespace for the given $version.
*
* @param int $version SOAP_1_1|SOAP_1_2
*
* @return string
*/
public static function getSoapNamespace($version)
{
if ($version === SOAP_1_2) {
return self::NS_SOAP_1_2;
} else {
return self::NS_SOAP_1_1;
}
}
/**
* Get SOAP version from namespace URI.
*
* @param string $namespace NS_SOAP_1_1|NS_SOAP_1_2
*
* @return int SOAP_1_1|SOAP_1_2
*/
public static function getSoapVersionFromNamespace($namespace)
{
if ($namespace === self::NS_SOAP_1_2) {
return SOAP_1_2;
} else {
return SOAP_1_1;
}
}
}

View File

@ -0,0 +1,175 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon\Mime;
use BeSimple\SoapCommon\Helper;
/**
* Mime multi part container.
*
* Headers:
* - MIME-Version
* - Content-Type
* - Content-ID
* - Content-Location
* - Content-Description
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class MultiPart extends PartHeader
{
/**
* Content-ID of main part.
*
* @var string
*/
protected $mainPartContentId;
/**
* Mime parts.
*
* @var array(\BeSimple\SoapCommon\Mime\Part)
*/
protected $parts = array();
/**
* Construct new mime object.
*
* @param string $boundary Boundary string
*
* @return void
*/
public function __construct($boundary = null)
{
$this->setHeader('MIME-Version', '1.0');
$this->setHeader('Content-Type', 'multipart/related');
$this->setHeader('Content-Type', 'type', 'text/xml');
$this->setHeader('Content-Type', 'charset', 'utf-8');
if (is_null($boundary)) {
$boundary = $this->generateBoundary();
}
$this->setHeader('Content-Type', 'boundary', $boundary);
}
/**
* Get mime message of this object (without headers).
*
* @param boolean $withHeaders Returned mime message contains headers
*
* @return string
*/
public function getMimeMessage($withHeaders = false)
{
$message = ($withHeaders === true) ? $this->generateHeaders() : "";
// add parts
foreach ($this->parts as $part) {
$message .= "\r\n" . '--' . $this->getHeader('Content-Type', 'boundary') . "\r\n";
$message .= $part->getMessagePart();
}
$message .= "\r\n" . '--' . $this->getHeader('Content-Type', 'boundary') . '--';
return $message;
}
/**
* Get string array with MIME headers for usage in HTTP header (with CURL).
* Only 'Content-Type' and 'Content-Description' headers are returned.
*
* @return arrray(string)
*/
public function getHeadersForHttp()
{
$allowed = array(
'Content-Type',
'Content-Description',
);
$headers = array();
foreach ($this->headers as $fieldName => $value) {
if (in_array($fieldName, $allowed)) {
$fieldValue = $this->generateHeaderFieldValue($value);
// for http only ISO-8859-1
$headers[] = $fieldName . ': '. iconv('utf-8', 'ISO-8859-1//TRANSLIT', $fieldValue);
}
}
return $headers;
}
/**
* Add new part to MIME message.
*
* @param \BeSimple\SoapCommon\Mime\Part $part Part that is added
* @param boolean $isMain Is the given part the main part of mime message
*
* @return void
*/
public function addPart(Part $part, $isMain = false)
{
$contentId = trim($part->getHeader('Content-ID'), '<>');
if ($isMain === true) {
$this->mainPartContentId = $contentId;
$this->setHeader('Content-Type', 'start', $part->getHeader('Content-ID'));
}
$this->parts[$contentId] = $part;
}
/**
* Get part with given content id. If there is no content id given it
* returns the main part that is defined through the content-id start
* parameter.
*
* @param string $contentId Content id of desired part
*
* @return \BeSimple\SoapCommon\Mime\Part|null
*/
public function getPart($contentId = null)
{
if (is_null($contentId)) {
$contentId = $this->mainPartContentId;
}
if (isset($this->parts[$contentId])) {
return $this->parts[$contentId];
}
return null;
}
/**
* Get all parts.
*
* @param boolean $includeMainPart Should main part be in result set
*
* @return array(\BeSimple\SoapCommon\Mime\Part)
*/
public function getParts($includeMainPart = false)
{
if ($includeMainPart === true) {
$parts = $this->parts;
} else {
$parts = array();
foreach ($this->parts as $cid => $part) {
if ($cid != $this->mainPartContentId) {
$parts[$cid] = $part;
}
}
}
return $parts;
}
/**
* Returns a unique boundary string.
*
* @return string
*/
protected function generateBoundary()
{
return 'urn:uuid:' . Helper::generateUUID();
}
}

View File

@ -0,0 +1,187 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon\Mime;
/**
* Simple Multipart-Mime parser.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class Parser
{
/**
* 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)
*
* @return \BeSimple\SoapCommon\Mime\MultiPart
*/
public static function parseMimeMessage($mimeMessage, array $headers = array())
{
$boundary = null;
$start = null;
$multipart = new MultiPart();
$hitFirstBoundary = false;
$inHeader = true;
// 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;
}
$content = '';
$currentPart = $multipart;
$lines = preg_split("/(\r\n)/", $mimeMessage);
foreach ($lines as $line) {
// ignore http status code and POST *
if (substr($line, 0, 5) == 'HTTP/' || substr($line, 0, 4) == 'POST') {
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, '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);
}
if ($inHeader) {
if (trim($line) == '') {
$inHeader = false;
continue;
}
$currentHeader = $line;
continue;
} else {
// check if we hit any of the boundaries
if (strlen($line) > 0 && $line[0] == "-") {
if (strcmp(trim($line), '--' . $boundary) === 0) {
if ($currentPart instanceof Part) {
$content = substr($content, 0, -2);
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, -2);
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);
$content = '';
}
} else {
if ($hitFirstBoundary === false) {
if (trim($line) != '') {
$inHeader = true;
$currentHeader = $line;
continue;
}
}
$content .= $line . "\r\n";
}
}
}
return $multipart;
}
/**
* 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
*
* @return null
*/
private static function parseContentTypeHeader(PartHeader $part, $headerName, $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;
}
$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]));
}
}
/**
* Decodes the content of a Mime part.
*
* @param \BeSimple\SoapCommon\Mime\Part $part Part to add content
* @param string $content Content to decode
*
* @return null
*/
private static function decodeContent(Part $part, $content)
{
$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 ($charset != 'utf-8') {
$content = iconv($charset, 'utf-8', $content);
}
$part->setContent($content);
}
}

View File

@ -0,0 +1,169 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon\Mime;
use BeSimple\SoapCommon\Helper;
/**
* Mime part. Everything must be UTF-8. Default charset for text is UTF-8.
*
* Headers:
* - Content-Type
* - Content-Transfer-Encoding
* - Content-ID
* - Content-Location
* - Content-Description
*
* @author Andreas Schamberger <mail@andreass.net>
*/
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
*/
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
*
* @return void
*/
public function __construct($content = null, $contentType = 'application/octet-stream', $charset = null, $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-Transfer-Encoding', $encoding);
if (is_null($contentId)) {
$contentId = $this->generateContentId();
}
$this->setHeader('Content-ID', '<' . $contentId . '>');
}
/**
* __toString.
*
* @return mixed
*/
public function __toString()
{
return $this->content;
}
/**
* Get mime content.
*
* @return mixed
*/
public function getContent()
{
return $this->content;
}
/**
* Set mime content.
*
* @param mixed $content Content to set
*
* @return void
*/
public function setContent($content)
{
$this->content = $content;
}
/**
* Get complete mime message of this object.
*
* @return string
*/
public function getMessagePart()
{
return $this->generateHeaders() . "\r\n" . $this->generateBody();
}
/**
* Generate body.
*
* @return string
*/
protected function generateBody()
{
$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);
} else {
$content = $this->content;
}
switch ($encoding) {
case self::ENCODING_BASE64:
return substr(chunk_split(base64_encode($content), 76, "\r\n"), -2);
case self::ENCODING_QUOTED_PRINTABLE:
return quoted_printable_encode($content);
case self::ENCODING_BINARY:
return $content;
case self::ENCODING_SEVEN_BIT:
case self::ENCODING_EIGHT_BIT:
default:
return preg_replace("/\r\n|\r|\n/", "\r\n", $content);
}
}
/**
* Returns a unique ID to be used for the Content-ID header.
*
* @return string
*/
protected function generateContentId()
{
return 'urn:uuid:' . Helper::generateUUID();
}
}

View File

@ -0,0 +1,146 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon\Mime;
/**
* Mime part base class.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
abstract class PartHeader
{
/**
* Mime headers.
*
* @var array(string=>mixed|array(mixed))
*/
protected $headers = array();
/**
* Add a new header to the mime part.
*
* @param string $name Header name
* @param string $value Header value
* @param string $subValue Is sub value?
*
* @return void
*/
public function setHeader($name, $value, $subValue = null)
{
if (isset($this->headers[$name]) && !is_null($subValue)) {
if (!is_array($this->headers[$name])) {
$this->headers[$name] = array(
'@' => $this->headers[$name],
$value => $subValue,
);
} else {
$this->headers[$name][$value] = $subValue;
}
} elseif (isset($this->headers[$name]) && is_array($this->headers[$name]) && isset($this->headers[$name]['@'])) {
$this->headers[$name]['@'] = $value;
} else {
$this->headers[$name] = $value;
}
}
/**
* Get given mime header.
*
* @param string $name Header name
* @param string $subValue Sub value name
*
* @return mixed|array(mixed)
*/
public function getHeader($name, $subValue = null)
{
if (isset($this->headers[$name])) {
if (!is_null($subValue)) {
if (is_array($this->headers[$name]) && isset($this->headers[$name][$subValue])) {
return $this->headers[$name][$subValue];
} else {
return null;
}
} elseif (is_array($this->headers[$name]) && isset($this->headers[$name]['@'])) {
return $this->headers[$name]['@'];
} else {
return $this->headers[$name];
}
}
return null;
}
/**
* Generate headers.
*
* @return string
*/
protected function generateHeaders()
{
$charset = strtolower($this->getHeader('Content-Type', 'charset'));
$preferences = array(
'scheme' => 'Q',
'input-charset' => 'utf-8',
'output-charset' => $charset,
);
$headers = '';
foreach ($this->headers as $fieldName => $value) {
$fieldValue = $this->generateHeaderFieldValue($value);
// do not use proper encoding as Apache Axis does not understand this
// $headers .= iconv_mime_encode($field_name, $field_value, $preferences) . "\r\n";
$headers .= $fieldName . ': ' . $fieldValue . "\r\n";
}
return $headers;
}
/**
* Generates a header field value from the given value paramater.
*
* @param array(string=>string)|string $value Header value
*
* @return string
*/
protected function generateHeaderFieldValue($value)
{
$fieldValue = '';
if (is_array($value)) {
if (isset($value['@'])) {
$fieldValue .= $value['@'];
}
foreach ($value as $subName => $subValue) {
if ($subName != '@') {
$fieldValue .= '; ' . $subName . '=' . $this->quoteValueString($subValue);
}
}
} else {
$fieldValue .= $value;
}
return $fieldValue;
}
/**
* Quote string with '"' if it contains one of the special characters:
* "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "="
*
* @param string $string String to quote
*
* @return string
*/
private function quoteValueString($string)
{
if (preg_match('~[()<>@,;:\\"/\[\]?=]~', $string)) {
return '"' . $string . '"';
} else {
return $string;
}
}
}

View File

@ -0,0 +1,132 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\Mime\Part as MimePart;
use BeSimple\SoapCommon\Converter\MtomTypeConverter;
use BeSimple\SoapCommon\Converter\SwaTypeConverter;
use BeSimple\SoapCommon\SoapRequest;
use BeSimple\SoapCommon\SoapResponse;
use BeSimple\SoapCommon\SoapRequestFilter;
use BeSimple\SoapCommon\SoapResponseFilter;
/**
* SoapKernel provides methods to pre- and post-process SoapRequests and SoapResponses using
* chains of SoapRequestFilter and SoapResponseFilter objects (roughly following
* the chain-of-responsibility pattern).
*
* @author Christian Kerl <christian-kerl@web.de>
*/
class SoapKernel
{
/**
* Mime attachments.
*
* @var array(\BeSimple\SoapCommon\Mime\Part)
*/
protected $attachments = array();
/**
* Request filters.
*
* @var array(SoapRequestFilter)
*/
private $requestFilters = array();
/**
* Response filters.
*
* @var array(SoapResponseFilter)
*/
private $responseFilters = array();
/**
* Add attachment.
*
* @param \BeSimple\SoapCommon\Mime\Part $attachment New attachment
*
* @return void
*/
public function addAttachment(MimePart $attachment)
{
$contentId = trim($attachment->getHeader('Content-ID'), '<>');
$this->attachments[$contentId] = $attachment;
}
/**
* Get attachment and remove from array.
*
* @param string $contentId Content ID of attachment
*
* @return \BeSimple\SoapCommon\Mime\Part|null
*/
public function getAttachment($contentId)
{
if (isset($this->attachments[$contentId])) {
$part = $this->attachments[$contentId];
unset($this->attachments[$contentId]);
return $part;
}
return null;
}
/**
* Registers the given object either as filter for SoapRequests or as filter for SoapResponses
* or as filter for both depending on the implemented interfaces. Inner filters have to be registered
* before outer filters. This means the order is as follows: RequestFilter2->RequestFilter1 and
* ResponseFilter1->ResponseFilter2.
*
* TODO: add priority mechanism to ensure correct order of filters
*
* @param SoapRequestFilter|SoapResponseFilter $filter Filter to register
*/
public function registerFilter($filter)
{
if ($filter instanceof SoapRequestFilter) {
array_unshift($this->requestFilters, $filter);
}
if ($filter instanceof SoapResponseFilter) {
array_push($this->responseFilters, $filter);
}
}
/**
* Applies all registered SoapRequestFilter to the given SoapRequest.
*
* @param SoapRequest $request Soap request
*/
public function filterRequest(SoapRequest $request)
{
foreach ($this->requestFilters as $filter) {
$filter->filterRequest($request);
}
}
/**
* Applies all registered SoapResponseFilter to the given SoapResponse.
*
* @param SoapResponse $response SOAP response
*/
public function filterResponse(SoapResponse $response)
{
foreach ($this->responseFilters as $filter) {
$filter->filterResponse($response);
}
}
}

View File

@ -0,0 +1,257 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\Mime\Part as MimePart;
/**
* Base class for SoapRequest and SoapResponse.
*
* @author Christian Kerl <christian-kerl@web.de>
* @author Andreas Schamberger <mail@andreass.net>
*/
abstract class SoapMessage
{
/**
* $_SERVER key for 'Content-Type' header.
*
* @var string
*/
const CONTENT_TYPE_HEADER = 'CONTENT_TYPE';
/**
* $_SERVER key for 'SOAPAction' header.
*
* @var string
*/
const SOAP_ACTION_HEADER = 'HTTP_SOAPACTION';
/**
* Content types for SOAP versions.
*
* @var array(string=>string)
*/
static protected $versionToContentTypeMap = array(
SOAP_1_1 => 'text/xml; charset=utf-8',
SOAP_1_2 => 'application/soap+xml; charset=utf-8'
);
/**
* SOAP action.
*
* @var string
*/
protected $action;
/**
* Mime attachments.
*
* @var array(\BeSimple\SoapCommon\Mime\Part)
*/
protected $attachments = array();
/**
* Message content (MIME Message or SOAP Envelope).
*
* @var string
*/
protected $content;
/**
*
* Enter description here ...
* @var \DOMDocument
*/
protected $contentDomDocument = null;
/**
* Message content type.
*
* @var string
*/
protected $contentType;
/**
* Service location.
*
* @var string
*/
protected $location;
/**
* SOAP version (SOAP_1_1|SOAP_1_2)
*
* @var string
*/
protected $version;
/**
* Get content type for given SOAP version.
*
* @param string $version SOAP version constant SOAP_1_1|SOAP_1_2
*
* @return string
* @throws \InvalidArgumentException
*/
public static function getContentTypeForVersion($version)
{
if (!in_array($version, array(SOAP_1_1, SOAP_1_2))) {
throw new \InvalidArgumentException("The 'version' argument has to be either 'SOAP_1_1' or 'SOAP_1_2'!");
}
return self::$versionToContentTypeMap[$version];
}
/**
* Get SOAP action.
*
* @return string
*/
public function getAction()
{
return $this->action;
}
/**
* Set SOAP action.
*
* @param string $action SOAP action
*/
public function setAction($action)
{
$this->action = $action;
}
/**
* Get attachments.
*
* @return array(\BeSimple\SoapCommon\Mime\Part)
*/
public function getAttachments()
{
return $this->attachments;
}
/**
* Set SOAP action.
*
* @param array(\BeSimple\SoapCommon\Mime\Part) $attachments Attachment array
*/
public function setAttachments(array $attachments)
{
$this->attachments = $attachments;
}
/**
* Get message content (MIME Message or SOAP Envelope).
*
* @return string
*/
public function getContent()
{
if (null !== $this->contentDomDocument) {
$this->content = $this->contentDomDocument->saveXML();
$this->contentDomDocument = null;
}
return $this->content;
}
/**
* Set message content (MIME Message or SOAP Envelope).
*
* @param string $content SOAP message
*/
public function setContent($content)
{
$this->content = $content;
if (null !== $this->contentDomDocument) {
$this->contentDomDocument->loadXML($this->content);
}
}
/**
* Get SOAP message as \DOMDocument
*
* @return \DOMDocument
*/
public function getContentDocument()
{
if (null === $this->contentDomDocument) {
$this->contentDomDocument = new \DOMDocument();
$this->contentDomDocument->loadXML($this->content);
}
return $this->contentDomDocument;
}
/**
* Get content type.
*
* @return string
*/
public function getContentType()
{
return $this->contentType;
}
/**
* Set content type.
*
* @param string $contentType Content type header
*/
public function setContentType($contentType)
{
$this->contentType = $contentType;
}
/**
* Get location.
*
* @return string
*/
public function getLocation()
{
return $this->location;
}
/**
* Set location.
*
* @param string $location Location string
*/
public function setLocation($location)
{
$this->location = $location;
}
/**
* Get version.
*
* @return string
*/
public function getVersion()
{
return $this->version;
}
/**
* Set version.
*
* @param string $version SOAP version SOAP_1_1|SOAP_1_2
*/
public function setVersion($version)
{
$this->version = $version;
}
}

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\SoapMessage;
/**
* SOAP request message.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
class SoapRequest extends SoapMessage
{
}

View File

@ -0,0 +1,31 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\SoapRequest;
/**
* SOAP request filter interface.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
interface SoapRequestFilter
{
/**
* Modify SOAP response.
*
* @param SoapRequest $request SOAP request
*/
public function filterRequest(SoapRequest $request);
}

View File

@ -0,0 +1,26 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\SoapMessage;
/**
* SOAP response message.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
class SoapResponse extends SoapMessage
{
}

View File

@ -0,0 +1,31 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (c) Christian Kerl <christian-kerl@web.de>
* (c) Francis Besset <francis.besset@gmail.com>
* (c) Andreas Schamberger <mail@andreass.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace BeSimple\SoapCommon;
use BeSimple\SoapCommon\SoapResponse;
/**
* SOAP response filter interface.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
interface SoapResponseFilter
{
/**
* Modify SOAP response.
*
* @param SoapResponse $response SOAP response
*/
public function filterResponse(SoapResponse $response);
}

View File

@ -0,0 +1,34 @@
<?php
namespace BeSimple\SoapCommon\Type;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
abstract class AbstractKeyValue
{
/**
* @Soap\ComplexType("string")
*/
protected $key;
/**
* The Soap type of this variable must be defined in child class
*/
protected $value;
public function __construct($key, $value)
{
$this->key = $key;
$this->value = $value;
}
public function getKey()
{
return $this->key;
}
public function getValue()
{
return $this->value;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace BeSimple\SoapCommon\Type\KeyValue;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use BeSimple\SoapCommon\Type\AbstractKeyValue;
class Boolean extends AbstractKeyValue
{
/**
* @Soap\ComplexType("boolean")
*/
protected $value;
}

View File

@ -0,0 +1,14 @@
<?php
namespace BeSimple\SoapCommon\Type\KeyValue;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use BeSimple\SoapCommon\Type\AbstractKeyValue;
class Date extends AbstractKeyValue
{
/**
* @Soap\ComplexType("date")
*/
protected $value;
}

View File

@ -0,0 +1,14 @@
<?php
namespace BeSimple\SoapCommon\Type\KeyValue;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use BeSimple\SoapCommon\Type\AbstractKeyValue;
class DateTime extends AbstractKeyValue
{
/**
* @Soap\ComplexType("dateTime")
*/
protected $value;
}

View File

@ -0,0 +1,14 @@
<?php
namespace BeSimple\SoapCommon\Type\KeyValue;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use BeSimple\SoapCommon\Type\AbstractKeyValue;
class Float extends AbstractKeyValue
{
/**
* @Soap\ComplexType("float")
*/
protected $value;
}

View File

@ -0,0 +1,14 @@
<?php
namespace BeSimple\SoapCommon\Type\KeyValue;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use BeSimple\SoapCommon\Type\AbstractKeyValue;
class Int extends AbstractKeyValue
{
/**
* @Soap\ComplexType("int")
*/
protected $value;
}

View File

@ -0,0 +1,14 @@
<?php
namespace BeSimple\SoapCommon\Type\KeyValue;
use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap;
use BeSimple\SoapCommon\Type\AbstractKeyValue;
class String extends AbstractKeyValue
{
/**
* @Soap\ComplexType("string")
*/
protected $value;
}

View File

@ -0,0 +1,101 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Util;
/**
* @author Francis Besset <francis.besset@gmail.com>
*/
class MessageBinder
{
/**
* @var Object
*/
protected $message;
/**
* @var \ReflectionClass
*/
protected $reflectionClass;
public function __construct($message)
{
if (!is_object($message)) {
throw new \InvalidArgumentException(sprintf('The message must be an object, %s given', gettype($message)));
}
$this->message = $message;
$this->reflectionClass = new \ReflectionClass($this->message);
}
public function readProperty($property)
{
if ($this->reflectionClass->hasMethod($getter = 'get'.$property)) {
if (!$this->reflectionClass->getMethod($getter)->isPublic()) {
throw new \RuntimeException(sprintf('Method "%s()" is not public in class "%s"', $getter, $this->reflectionClass->name));
}
$value = $this->message->{$getter}();
} elseif ($this->reflectionClass->hasMethod($isser = 'is'.$property)) {
if (!$this->reflectionClass->getMethod($isser)->isPublic()) {
throw new \RuntimeException(sprintf('Method "%s()" is not public in class "%s"', $isser, $this->reflectionClass->name));
}
$value = $this->message->{$isser}();
} elseif ($this->reflectionClass->hasMethod($hasser = 'has'.$property)) {
if (!$this->reflectionClass->getMethod($hasser)->isPublic()) {
throw new \RuntimeException(sprintf('Method "%s()" is not public in class "%s"', $hasser, $this->reflectionClass->name));
}
$value = $this->message->{$hasser}();
} elseif ($this->reflectionClass->hasMethod('__get')) {
// needed to support magic method __get
$value = $this->message->{$property};
} elseif ($this->reflectionClass->hasProperty($property)) {
$p = $this->reflectionClass->getProperty($property);
if (!$p->isPublic()) {
$p->setAccessible(true);
}
$value = $p->getValue($this->message);
} elseif (property_exists($this->message, $property)) {
// needed to support \stdClass instances
$value = $this->message->{$property};
}
return $value;
}
public function writeProperty($property, $value)
{
if ($this->reflectionClass->hasMethod($setter = 'set'.$property)) {
if (!$this->reflectionClass->getMethod($setter)->isPublic()) {
throw new \RuntimeException(sprintf('Method "%s()" is not public in class "%s"', $setter, $this->reflectionClass->name));
}
$this->message->{$setter}($value);
} elseif ($this->reflectionClass->hasMethod('__set')) {
// needed to support magic method __set
$this->message->{$property} = $value;
} elseif ($this->reflectionClass->hasProperty($property)) {
$p = $this->reflectionClass->getProperty($property);
if (!$p->isPublic()) {
$p->setAccessible(true);
}
$p->setValue($this->message, $value);
} elseif (property_exists($this->message, $property)) {
// needed to support \stdClass instances
$this->message->{$property} = $value;
}
}
}

View File

@ -0,0 +1,116 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon;
use ass\XmlSecurity\Key as XmlSecurityKey;
/**
* This class represents a security key for WS-Security (WSS).
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class WsSecurityKey
{
/**
* Private key.
*
* @var \ass\XmlSecurity\Key
*/
protected $privateKey = null;
/**
* Public key.
*
* @var \ass\XmlSecurity\Key
*/
protected $publicKey = null;
/**
* Add private key.
*
* @param string $encryptionType Encryption type
* @param string $key Private key
* @param boolean $keyIsFile Given key parameter is path to key file
* @param string $passphrase Passphrase for key
*
* @return void
*/
public function addPrivateKey($encryptionType, $key = null, $keyIsFile = true, $passphrase = null)
{
$this->privateKey = XmlSecurityKey::factory($encryptionType, $key, $keyIsFile, XmlSecurityKey::TYPE_PRIVATE, $passphrase);
}
/**
* Add public key.
*
* @param string $encryptionType Encryption type
* @param string $key Public key
* @param boolean $keyIsFile Given key parameter is path to key file
*
* @return void
*/
public function addPublicKey($encryptionType, $key = null, $keyIsFile = true)
{
$this->publicKey = XmlSecurityKey::factory($encryptionType, $key, $keyIsFile, XmlSecurityKey::TYPE_PUBLIC);
}
/**
* Get private key.
*
* @return \ass\XmlSecurity\Key
*/
public function getPrivateKey()
{
return $this->privateKey;
}
/**
* Get public key.
*
* @return \ass\XmlSecurity\Key
*/
public function getPublicKey()
{
return $this->publicKey;
}
/**
* Has private and public key?
*
* @return boolean
*/
public function hasKeys()
{
return null !== $this->privateKey && null !== $this->publicKey;
}
/**
* Has private key?
*
* @return boolean
*/
public function hasPrivateKey()
{
return null !== $this->privateKey;
}
/**
* Has public key?
*
* @return boolean
*/
public function hasPublicKey()
{
return null !== $this->publicKey;
}
}

View File

@ -0,0 +1,205 @@
<?php
/*
* This file is part of BeSimpleSoapCommon.
*
* (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\SoapCommon;
use BeSimple\SoapCommon\Helper;
/**
* This class loads the given WSDL file and allows to check MIME binding
* information.
*
* @author Andreas Schamberger <mail@andreass.net>
*/
class WsdlHandler
{
/**
* Binding type 'input' .
*/
const BINDING_OPERATION_INPUT = 'input';
/**
* Binding type 'output' .
*/
const BINDING_OPERATION_OUTPUT = 'output';
/**
* WSDL file name.
*
* @var string
*/
private $wsdlFile;
/**
* DOMDocument WSDL file.
*
* @var \DOMDocument
*/
private $domDocument;
/**
* DOMXPath WSDL file.
*
* @var DOMXPath
*/
private $domXpath;
/**
* Array of mime type information.
*
* @var array(string=>array(string=>array(string=>array(string))))
*/
private $mimeTypes = array();
/**
* WSDL namespace of current WSDL file.
*
* @var string
*/
private $wsdlSoapNamespace;
/**
* Constructor.
*
* @param string $wsdlFile WSDL file name
* @param string $soapVersion SOAP version constant
*/
public function __construct($wsdlFile, $soapVersion)
{
$this->wsdlFile = $wsdlFile;
if ($soapVersion == SOAP_1_1) {
$this->wsdlSoapNamespace = Helper::NS_WSDL_SOAP_1_1;
} else {
$this->wsdlSoapNamespace = Helper::NS_WSDL_SOAP_1_2;
}
}
/**
* Gets the mime type information from the WSDL file.
*
* @param string $soapAction Soap action to analyse
*
* @return array(string=>array(string=>array(string)))
*/
private function getMimeTypesForSoapAction($soapAction)
{
$query = '/wsdl:definitions/wsdl:binding/wsdl:operation/soap:operation[@soapAction="'.$soapAction.'"]/..';
$nodes = $this->domXpath->query($query);
$mimeTypes = array();
if (null !== $wsdlOperation = $nodes->item(0)) {
//$wsdlOperationName = $wsdlOperation->getAttribute('name');
foreach ($wsdlOperation->childNodes as $soapOperationChild) {
// wsdl:input or wsdl:output
if ($soapOperationChild->localName == 'input' || $soapOperationChild->localName == 'output') {
$operationType = $soapOperationChild->localName;
// mime:multipartRelated/mime:part
$mimeParts = $soapOperationChild->getElementsByTagNameNS(Helper::NS_WSDL_MIME, 'part');
if ($mimeParts->length > 0) {
foreach ($mimeParts as $mimePart) {
foreach ($mimePart->childNodes as $child) {
switch ($child->localName) {
case 'body':
$parts = $child->getAttribute('parts');
$parts = ($parts == '') ? '[body]' : $parts;
$mimeTypes[$operationType][$parts] = array('text/xml');
break;
case 'content':
$part = $child->getAttribute('part');
$part = ($part == '') ? null : $part;
$type = $child->getAttribute('type');
$type = ($type == '') ? '*/*' : $type;
if (!isset($mimeTypes[$operationType][$part])) {
$mimeTypes[$operationType][$part] = array();
}
$mimeTypes[$operationType][$part][] = $type;
break;
case 'mimeXml':
// this does not conform to the spec
$part = $child->getAttribute('part');
$part = ($part == '') ? null : $part;
$mimeTypes[$operationType][$part] = array('text/xml');
break;
}
}
}
} else {
$child = $soapOperationChild->getElementsByTagNameNS($this->wsdlSoapNamespace, 'body')->item(0);
if (null !== $child) {
$parts = $child->getAttribute('parts');
$parts = ($parts == '') ? '[body]' : $parts;
$mimeTypes[$operationType][$parts] = array('text/xml');
}
}
}
}
}
return $mimeTypes;
}
/**
* Checks the mime type of the part for the given operation.
*
* @param string $soapAction Soap action
* @param string $operationType Operation type
* @param string $part Part name
* @param string $currentMimeType Current mime type
*
* @return boolean
*/
public function isValidMimeTypeType($soapAction, $operationType, $part, $currentMimeType)
{
// create DOMDocument from WSDL file
$this->loadWsdlInDom();
// load data from WSDL
if (!isset($this->mimeTypes[$soapAction])) {
$this->mimeTypes[$soapAction] = $this->getMimeTypesForSoapAction($soapAction);
}
// part is valid as we do not have an explicit entry for current part
if (!isset($this->mimeTypes[$soapAction][$operationType][$part])) {
return true;
}
$mimeTypes = $this->mimeTypes[$soapAction][$operationType][$part];
// wildcard or exact match
if (in_array('*/*', $mimeTypes) || in_array($currentMimeType, $mimeTypes)) {
return true;
// type/* match
} else {
list($ctype, $csubtype) = explode('/', $currentMimeType);
foreach ($mimeTypes as $mimeType) {
list($type, $subtype) = explode('/', $mimeType);
if ($subtype == '*' && $type == $ctype) {
return true;
}
}
}
return false;
}
/**
* Loads the WSDL file into a DOM
*
* @return void
*/
private function loadWsdlInDom()
{
if (null === $this->domDocument) {
$this->domDocument = new \DOMDocument('1.0', 'utf-8');
$this->domDocument->load($this->wsdlFile);
$this->domXpath = new \DOMXPath($this->domDocument);
$this->domXpath->registerNamespace('wsdl', Helper::NS_WSDL);
$this->domXpath->registerNamespace('mime', Helper::NS_WSDL_MIME);
$this->domXpath->registerNamespace('soap', $this->wsdlSoapNamespace);
}
}
}

View File

@ -0,0 +1,211 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\Cache;
use BeSimple\SoapCommon\Classmap;
use BeSimple\SoapCommon\Converter\DateTimeTypeConverter;
use BeSimple\SoapCommon\Converter\DateTypeConverter;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\Tests\SoapCommon\Fixtures\SoapBuilder;
class AbstractSoapBuilderTest extends \PHPUnit_Framework_TestCase
{
private $defaultOptions = array(
'features' => 0,
'classmap' => array(),
'typemap' => array(),
);
public function testContruct()
{
$options = $this
->getSoapBuilder()
->getSoapOptions()
;
$this->assertEquals($this->mergeOptions(array()), $options);
}
public function testWithWsdl()
{
$builder = $this->getSoapBuilder();
$this->assertNull($builder->getWsdl());
$builder->withWsdl('http://myWsdl/?wsdl');
$this->assertEquals('http://myWsdl/?wsdl', $builder->getWsdl());
}
public function testWithSoapVersion()
{
$builder = $this->getSoapBuilder();
$builder->withSoapVersion11();
$this->assertEquals($this->mergeOptions(array('soap_version' => SOAP_1_1)), $builder->getSoapOptions());
$builder->withSoapVersion12();
$this->assertEquals($this->mergeOptions(array('soap_version' => SOAP_1_2)), $builder->getSoapOptions());
}
public function testWithEncoding()
{
$builder = $this
->getSoapBuilder()
->withEncoding('ISO 8859-15')
;
$this->assertEquals($this->mergeOptions(array('encoding' => 'ISO 8859-15')), $builder->getSoapOptions());
}
public function testWithWsdlCache()
{
$builder = $this->getSoapBuilder();
$builder->withWsdlCache(Cache::TYPE_DISK_MEMORY);
$this->assertEquals($this->mergeOptions(array('cache_wsdl' => Cache::TYPE_DISK_MEMORY)), $builder->getSoapOptions());
$builder->withWsdlCacheNone();
$this->assertEquals($this->mergeOptions(array('cache_wsdl' => Cache::TYPE_NONE)), $builder->getSoapOptions());
$builder->withWsdlCacheDisk();
$this->assertEquals($this->mergeOptions(array('cache_wsdl' => Cache::TYPE_DISK)), $builder->getSoapOptions());
$builder->withWsdlCacheMemory();
$this->assertEquals($this->mergeOptions(array('cache_wsdl' => Cache::TYPE_MEMORY)), $builder->getSoapOptions());
$builder->withWsdlCacheDiskAndMemory();
$this->assertEquals($this->mergeOptions(array('cache_wsdl' => Cache::TYPE_DISK_MEMORY)), $builder->getSoapOptions());
}
public function testWithWsdlCacheBadValue()
{
$builder = $this->getSoapBuilder();
$this->setExpectedException('InvalidArgumentException');
$builder->withWsdlCache('foo');
}
public function testWithSingleElementArrays()
{
$options = $this
->getSoapBuilder()
->withSingleElementArrays()
->getSoapOptions()
;
$this->assertEquals($this->mergeOptions(array('features' => SOAP_SINGLE_ELEMENT_ARRAYS)), $options);
}
public function testWithWaitOneWayCalls()
{
$options = $this
->getSoapBuilder()
->withWaitOneWayCalls()
->getSoapOptions()
;
$this->assertEquals($this->mergeOptions(array('features' => SOAP_WAIT_ONE_WAY_CALLS)), $options);
}
public function testWithUseXsiArrayType()
{
$options = $this
->getSoapBuilder()
->withUseXsiArrayType()
->getSoapOptions()
;
$this->assertEquals($this->mergeOptions(array('features' => SOAP_USE_XSI_ARRAY_TYPE)), $options);
}
public function testFeatures()
{
$builder = $this->getSoapBuilder();
$features = 0;
$builder->withSingleElementArrays();
$features |= SOAP_SINGLE_ELEMENT_ARRAYS;
$this->assertEquals($this->mergeOptions(array('features' => $features)), $builder->getSoapOptions());
$builder->withWaitOneWayCalls();
$features |= SOAP_WAIT_ONE_WAY_CALLS;
$this->assertEquals($this->mergeOptions(array('features' => $features)), $builder->getSoapOptions());
$builder->withUseXsiArrayType();
$features |= SOAP_USE_XSI_ARRAY_TYPE;
$this->assertEquals($this->mergeOptions(array('features' => $features)), $builder->getSoapOptions());
}
public function testWithTypeConverters()
{
$builder = $this->getSoapBuilder();
$builder->withTypeConverter(new DateTypeConverter());
$options = $builder->getSoapOptions();
$this->assertEquals(1, count($options['typemap']));
$converters = new TypeConverterCollection();
$converters->add(new DateTimeTypeConverter());
$builder->withTypeConverters($converters);
$options = $builder->getSoapOptions();
$this->assertEquals(2, count($options['typemap']));
$builder->withTypeConverters($converters, false);
$options = $builder->getSoapOptions();
$this->assertEquals(1, count($options['typemap']));
}
public function testClassmap()
{
$builder = $this->getSoapBuilder();
$builder->withClassMapping('foo', __CLASS__);
$options = $builder->getSoapOptions();
$this->assertEquals(1, count($options['classmap']));
$classmap = new Classmap();
$classmap->add('bar', __CLASS__);
$builder->withClassmap($classmap);
$options = $builder->getSoapOptions();
$this->assertEquals(2, count($options['classmap']));
$builder->withClassmap($classmap, false);
$options = $builder->getSoapOptions();
$this->assertEquals(1, count($options['classmap']));
}
public function testCreateWithDefaults()
{
$builder = SoapBuilder::createWithDefaults();
$this->assertInstanceOf('BeSimple\Tests\SoapCommon\Fixtures\SoapBuilder', $builder);
$this->assertEquals($this->mergeOptions(array('soap_version' => SOAP_1_2, 'encoding' => 'UTF-8', 'features' => SOAP_SINGLE_ELEMENT_ARRAYS)), $builder->getSoapOptions());
}
private function getSoapBuilder()
{
return new SoapBuilder();
}
private function mergeOptions(array $options)
{
return array_merge($this->defaultOptions, $options);
}
}

View File

@ -0,0 +1,94 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\Cache;
use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\vfsStreamWrapper;
class SoapRequestTest extends \PHPUnit_Framework_TestCase
{
public function testSetEnabled()
{
Cache::setEnabled(Cache::ENABLED);
$this->assertEquals(Cache::ENABLED, Cache::isEnabled());
Cache::setEnabled(Cache::DISABLED);
$this->assertEquals(Cache::DISABLED, Cache::isEnabled());
}
public function testSetEnabledBadValue()
{
$this->setExpectedException('InvalidArgumentException');
Cache::setEnabled('foo');
}
public function testSetType()
{
Cache::setType(Cache::TYPE_DISK);
$this->assertEquals(Cache::TYPE_DISK, Cache::getType());
Cache::setType(Cache::TYPE_NONE);
$this->assertEquals(Cache::TYPE_NONE, Cache::getType());
}
public function testSetTypeBadValue()
{
$this->setExpectedException('InvalidArgumentException');
Cache::setType('foo');
}
public function testSetDirectory()
{
vfsStream::setup('Fixtures');
$this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('foo'));
$dir = vfsStream::url('Fixtures/foo');
Cache::setDirectory($dir);
$this->assertEquals($dir, Cache::getDirectory());
$this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('foo'));
$this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('bar'));
$dir = vfsStream::url('Fixtures/bar');
Cache::setDirectory($dir);
$this->assertEquals($dir, Cache::getDirectory());
$this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('bar'));
}
public function testSetLifetime()
{
Cache::setLifetime(1234);
$this->assertEquals(1234, Cache::getLifetime());
Cache::setLifetime(4321);
$this->assertEquals(4321, Cache::getLifetime());
}
public function testSetLimit()
{
Cache::setLimit(10);
$this->assertEquals(10, Cache::getLimit());
Cache::setLimit(1);
$this->assertEquals(1, Cache::getLimit());
}
public function setUp()
{
ini_restore('soap.wsdl_cache_enabled');
ini_restore('soap.wsdl_cache');
ini_restore('soap.wsdl_cache_dir');
ini_restore('soap.wsdl_cache_ttl');
ini_restore('soap.wsdl_cache_limit');
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Tests;
use BeSimple\SoapCommon\Classmap;
/**
* UnitTest for \BeSimple\SoapCommon\Classmap.
*
* @author Francis Besset <francis.besset@gmail.com>
*/
class ClassmapTest extends \PHPUnit_Framework_TestCase
{
public function testAll()
{
$classmap = new Classmap();
$this->assertSame(array(), $classmap->all());
}
public function testAdd()
{
$classmap = new Classmap();
$classmap->add('foobar', 'BeSimple\SoapCommon\Classmap');
$this->setExpectedException('InvalidArgumentException');
$classmap->add('foobar', 'BeSimple\SoapCommon\Classmap');
}
public function testGet()
{
$classmap = new Classmap();
$classmap->add('foobar', 'BeSimple\SoapCommon\Classmap');
$this->assertSame('BeSimple\SoapCommon\Classmap', $classmap->get('foobar'));
$this->setExpectedException('InvalidArgumentException');
$classmap->get('bar');
}
public function testSet()
{
$classmap = new Classmap();
$classmap->add('foobar', 'BeSimple\SoapCommon\Tests\ClassmapTest');
$classmap->add('foo', 'BeSimple\SoapCommon\Tests\Classmap');
$map = array(
'foobar' => 'BeSimple\SoapCommon\Classmap',
'barfoo' => 'BeSimple\SoapCommon\Tests\ClassmapTest',
);
$classmap->set($map);
$this->assertSame($map, $classmap->all());
}
public function testAddClassmap()
{
$classmap1 = new Classmap();
$classmap2 = new Classmap();
$classmap2->add('foobar', 'BeSimple\SoapCommon\Classmap');
$classmap1->addClassmap($classmap2);
$this->assertEquals(array('foobar' => 'BeSimple\SoapCommon\Classmap'), $classmap1->all());
$this->setExpectedException('InvalidArgumentException');
$classmap1->addClassmap($classmap2);
}
}

View File

@ -0,0 +1,54 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Tests\Converter;
use BeSimple\SoapCommon\Converter\DateTimeTypeConverter;
/**
* UnitTest for \BeSimple\SoapCommon\Converter\DateTimeTypeConverter.
*
* @author Christian Kerl <christian-kerl@web.de>
*/
class DateTimeTypeConverterTest extends \PHPUnit_Framework_TestCase
{
public function testConvertXmlToPhp()
{
$converter = new DateTimeTypeConverter();
$dateXml = '<sometag>2002-10-10T12:00:00-05:00</sometag>';
$date = $converter->convertXmlToPhp($dateXml);
$this->assertEquals(new \DateTime('2002-10-10T12:00:00-05:00'), $date);
}
public function testConvertPhpToXml()
{
$converter = new DateTimeTypeConverter();
$date = new \DateTime('2002-10-10T12:00:00-05:00');
$dateXml = $converter->convertPhpToXml($date);
$this->assertEquals('<dateTime>2002-10-10T12:00:00-05:00</dateTime>', $dateXml);
}
public function testConvertNullDateTimeXmlToPhp()
{
$converter = new DateTimeTypeConverter();
$dateXml = '<sometag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>';
$date = $converter->convertXmlToPhp($dateXml);
$this->assertNull($date);
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Tests\Converter;
use BeSimple\SoapCommon\Converter\DateTypeConverter;
/**
* UnitTest for \BeSimple\SoapCommon\Converter\DateTypeConverter.
*/
class DateTypeConverterTest extends \PHPUnit_Framework_TestCase
{
public function testConvertXmlToPhp()
{
$converter = new DateTypeConverter();
$dateXml = '<sometag>2002-10-10</sometag>';
$date = $converter->convertXmlToPhp($dateXml);
$this->assertEquals(new \DateTime('2002-10-10'), $date);
}
public function testConvertPhpToXml()
{
$converter = new DateTypeConverter();
$date = new \DateTime('2002-10-10');
$dateXml = $converter->convertPhpToXml($date);
$this->assertEquals('<date>2002-10-10</date>', $dateXml);
}
public function testConvertNullDateTimeXmlToPhp()
{
$converter = new DateTypeConverter();
$dateXml = '<sometag xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>';
$date = $converter->convertXmlToPhp($dateXml);
$this->assertNull($date);
}
}

View File

@ -0,0 +1,93 @@
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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\SoapCommon\Tests\Converter;
use BeSimple\SoapCommon\Converter\TypeConverterCollection;
use BeSimple\SoapCommon\Converter\DateTimeTypeConverter;
use BeSimple\SoapCommon\Converter\DateTypeConverter;
/**
* UnitTest for \BeSimple\SoapCommon\Converter\TypeConverterCollection.
*
* @author Francis Besset <francis.besset@gmail.com>
*/
class TypeConverterCollectionTest extends \PHPUnit_Framework_TestCase
{
public function testAdd()
{
$converters = new TypeConverterCollection();
$dateTimeTypeConverter = new DateTimeTypeConverter();
$converters->add($dateTimeTypeConverter);
$this->assertSame(array($dateTimeTypeConverter), $converters->all());
$dateTypeConverter = new DateTypeConverter();
$converters->add($dateTypeConverter);
$this->assertSame(array($dateTimeTypeConverter, $dateTypeConverter), $converters->all());
}
public function testGetTypemap()
{
$converters = new TypeConverterCollection();
$this->assertEquals(array(), $converters->getTypemap());
$dateTimeTypeConverter = new DateTimeTypeConverter();
$converters->add($dateTimeTypeConverter);
$dateTypeConverter = new DateTypeConverter();
$converters->add($dateTypeConverter);
$typemap = $converters->getTypemap();
$this->assertEquals('http://www.w3.org/2001/XMLSchema', $typemap[0]['type_ns']);
$this->assertEquals('dateTime', $typemap[0]['type_name']);
$this->assertInstanceOf('Closure', $typemap[0]['from_xml']);
$this->assertInstanceOf('Closure', $typemap[0]['to_xml']);
$this->assertEquals('http://www.w3.org/2001/XMLSchema', $typemap[1]['type_ns']);
$this->assertEquals('date', $typemap[1]['type_name']);
$this->assertInstanceOf('Closure', $typemap[1]['from_xml']);
$this->assertInstanceOf('Closure', $typemap[1]['to_xml']);
}
public function testSet()
{
$converters = new TypeConverterCollection();
$dateTimeTypeConverter = new DateTimeTypeConverter();
$converters->add($dateTimeTypeConverter);
$converter = array(new DateTypeConverter);
$converters->set($converter);
$this->assertSame($converter, $converters->all());
}
public function testAddCollection()
{
$converters1 = new TypeConverterCollection();
$converters2 = new TypeConverterCollection();
$dateTimeTypeConverter = new DateTimeTypeConverter();
$converters2->add($dateTimeTypeConverter);
$converters1->addCollection($converters2);
$this->assertSame(array($dateTimeTypeConverter), $converters1->all());
$this->setExpectedException('InvalidArgumentException');
$converters1->addCollection($converters2);
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace BeSimple\Tests\SoapCommon\Fixtures;
use BeSimple\SoapCommon\Mime\PartHeader;
class MimePartHeader extends PartHeader
{
}

View File

@ -0,0 +1,9 @@
<?php
namespace BeSimple\Tests\SoapCommon\Fixtures;
use BeSimple\SoapCommon\AbstractSoapBuilder;
class SoapBuilder extends AbstractSoapBuilder
{
}

View File

@ -0,0 +1,29 @@
HTTP/1.1 401 Authorization Required
Date: Fri, 12 Feb 2010 15:46:00 GMT
Server: Server
WWW-Authenticate: Basic realm="Realm"
Content-Length: 0
Cneonction: close
Content-Type: text/plain
HTTP/1.1 200 OK
Date: Fri, 12 Feb 2010 15:46:00 GMT
Server: Server
MIME-Version: 1.0
Cneonction: close
Transfer-Encoding: chunked
Content-Type: multipart/related; boundary="xxx-MIME-Boundary-xxx-0xa36cb38-0a36cb38-xxx-END-xxx"; type="text/xml"
--xxx-MIME-Boundary-xxx-0xa36cb38-0a36cb38-xxx-END-xxx
Content-Type: text/xml; charset="UTF-8"
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SE="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:doc href="cid:0x9d6ad00-0xa19ef48-0x9de7500-0xa4fae78-0xa382698" xmlns:ns1="http://myservice/schema/"/></SOAP-ENV:Body></SOAP-ENV:Envelope>
--xxx-MIME-Boundary-xxx-0xa36cb38-0a36cb38-xxx-END-xxx
Content-ID: <0x9d6ad00-0xa19ef48-0x9de7500-0xa4fae78-0xa382698>
Content-Type: application/binary
<?xml version="1.0" encoding="UTF-8"?>
<XmlDocument><NoContent/></XmlDocument>
--xxx-MIME-Boundary-xxx-0xa36cb38-0a36cb38-xxx-END-xxx--

View File

@ -0,0 +1,13 @@
HTTP/1.1 200 OK
Date: Sat, 11 Sep 2010 12:52:57 GMT
Server: Simple-Server/1.1
Transfer-Encoding: chunked
Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_2DB7ABF3DC5BED7FA51284209577582; type="application/soap+xml"; start="<0.urn:uuid:2DB7ABF3DC5BED7FA51284209577583@apache.org>"; action="urn:getVersionResponse"
--MIMEBoundaryurn_uuid_2DB7ABF3DC5BED7FA51284209577582
Content-Type: application/soap+xml; charset=utf-8
Content-Transfer-Encoding: 8bit
Content-ID: <0.urn:uuid:2DB7ABF3DC5BED7FA51284209577583@apache.org>
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing"><wsa:Action>urn:getVersionResponse</wsa:Action><wsa:RelatesTo>uuid:665aab53-4cef-4435-8934-4c10ed24fd42</wsa:RelatesTo></soapenv:Header><soapenv:Body><ns:getVersionResponse xmlns:ns="http://axisversion.sample"><ns:return>Hi - the Axis2 version is 1.5.1</ns:return></ns:getVersionResponse></soapenv:Body></soapenv:Envelope>
--MIMEBoundaryurn_uuid_2DB7ABF3DC5BED7FA51284209577582--

View File

@ -0,0 +1,22 @@
POST http://131.107.72.15/Mtom/svc/service.svc/Soap12MtomUTF8 HTTP/1.1
Content-Type: multipart/related; type="application/xop+xml";start="<http://tempuri.org/0>";boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7";start-info="application/soap+xml"
Host: 131.107.72.15
Content-Length: 1941
Expect: 100-continue
HTTP/1.1 100 Continue
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://xmlsoap.org/echoBinaryAsString</a:Action><a:MessageID>urn:uuid:1bf061d6-d532-4b0c-930b-8b8202c38b8a</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">http://131.107.72.15/Mtom/svc/service.svc/Soap12MtomUTF8</a:To></s:Header><s:Body><EchoBinaryAsString xmlns="http://xmlsoap.org/Ping"><array><xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F1%2F632618206527087310" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></array></EchoBinaryAsString></s:Body></s:Envelope>
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7
Content-ID: <http://tempuri.org/1/632618206527087310>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d !
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7--

View File

@ -0,0 +1,16 @@
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"><s:Header><a:Action s:mustUnderstand="1">http://xmlsoap.org/echoBinaryAsString</a:Action><a:MessageID>urn:uuid:1bf061d6-d532-4b0c-930b-8b8202c38b8a</a:MessageID><a:ReplyTo><a:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:Address></a:ReplyTo><a:To s:mustUnderstand="1">http://131.107.72.15/Mtom/svc/service.svc/Soap12MtomUTF8</a:To></s:Header><s:Body><EchoBinaryAsString xmlns="http://xmlsoap.org/Ping"><array><xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F1%2F632618206527087310" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></array></EchoBinaryAsString></s:Body></s:Envelope>
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7
Content-ID: <http://tempuri.org/1/632618206527087310>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d ! H e l l o W o r l d !
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7--

View File

@ -0,0 +1,17 @@
HTTP/1.1 200 OK
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Length: 1166
Via: 1.1 RED-PRXY-03
Date: Fri, 09 Sep 2005 06:57:22 GMT
Content-Type: multipart/related; type="application/xop+xml";start="<http://tempuri.org/0>";boundary="uuid:b71dc628-ec8f-4422-8a4a-992f041cb94c+id=46";start-info="application/soap+xml"
--uuid:b71dc628-ec8f-4422-8a4a-992f041cb94c+id=46
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"><s:Header><a:Action s:mustUnderstand="1">*</a:Action><a:RelatesTo>urn:uuid:1bf061d6-d532-4b0c-930b-8b8202c38b8a</a:RelatesTo><a:To s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</a:To></s:Header><s:Body><EchoBinaryAsStringResponse xmlns="http://xmlsoap.org/Ping"><EchoBinaryAsStringResult>Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!</EchoBinaryAsStringResult></EchoBinaryAsStringResponse></s:Body></s:Envelope>
--uuid:b71dc628-ec8f-4422-8a4a-992f041cb94c+id=46--

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8" ?>
<wsdl:definitions xmlns:types="http://example.com/mimetypes"
xmlns:ref="http://ws-i.org/profiles/basic/1.1/xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapbind="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://example.com/mimewsdl"
xmlns:tns="http://example.com/mimewsdl">
<wsdl:types>
<xsd:schema targetNamespace="http://example.com/mimetypes"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="ClaimDetail" type="types:ClaimDetailType"/>
<xsd:complexType name="ClaimDetailType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<!-- lots of other claim detail stuff -->
</xsd:sequence>
</xsd:complexType>
<xsd:element name="ClaimRefNo" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="ClaimIn">
<wsdl:part name="body" element="types:ClaimDetail"/>
<wsdl:part name="ClaimPhoto" type="xsd:base64Binary"/>
</wsdl:message>
<wsdl:message name="ClaimOut">
<wsdl:part name="out" element="types:ClaimRefNo"/>
</wsdl:message>
<wsdl:portType name="ClaimPortType">
<wsdl:operation name="SendClaim">
<wsdl:input message="tns:ClaimIn"/>
<wsdl:output message="tns:ClaimOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ClaimBinding" type="tns:ClaimPortType">
<soapbind:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="SendClaim">
<soapbind:operation soapAction="http://example.com/soapaction"/>
<wsdl:input>
<mime:multipartRelated>
<mime:part>
<soapbind:body parts="body" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="ClaimPhoto" type="image/jpeg"/>
</mime:part>
</mime:multipartRelated>
</wsdl:input>
<wsdl:output>
<soapbind:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
</wsdl:definitions>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8" ?>
<wsdl:definitions xmlns:types="http://example.com/mimetypes"
xmlns:ref="http://ws-i.org/profiles/basic/1.1/xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapbind="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://example.com/mimewsdl"
xmlns:tns="http://example.com/mimewsdl">
<wsdl:types>
<xsd:schema targetNamespace="http://example.com/mimetypes"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="ClaimDetail" type="types:ClaimDetailType"/>
<xsd:complexType name="ClaimDetailType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<!-- lots of other claim detail stuff -->
</xsd:sequence>
</xsd:complexType>
<xsd:element name="ClaimRefNo" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="ClaimIn">
<wsdl:part name="body" element="types:ClaimDetail"/>
<wsdl:part name="ClaimPhoto" type="xsd:base64Binary"/>
</wsdl:message>
<wsdl:message name="ClaimOut">
<wsdl:part name="out" element="types:ClaimRefNo"/>
</wsdl:message>
<wsdl:portType name="ClaimPortType">
<wsdl:operation name="SendClaim">
<wsdl:input message="tns:ClaimIn"/>
<wsdl:output message="tns:ClaimOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ClaimBinding" type="tns:ClaimPortType">
<soapbind:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="SendClaim">
<soapbind:operation soapAction="http://example.com/soapaction"/>
<wsdl:input>
<mime:multipartRelated>
<mime:part>
<soapbind:body parts="body" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="ClaimPhoto" type="image/*"/>
</mime:part>
</mime:multipartRelated>
</wsdl:input>
<wsdl:output>
<soapbind:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
</wsdl:definitions>

View File

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8" ?>
<wsdl:definitions xmlns:types="http://example.com/mimetypes"
xmlns:ref="http://ws-i.org/profiles/basic/1.1/xsd"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soapbind="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://example.com/mimewsdl"
xmlns:tns="http://example.com/mimewsdl">
<wsdl:types>
<xsd:schema targetNamespace="http://example.com/mimetypes"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="ClaimDetail" type="types:ClaimDetailType"/>
<xsd:complexType name="ClaimDetailType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<!-- lots of other claim detail stuff -->
</xsd:sequence>
</xsd:complexType>
<xsd:element name="ClaimRefNo" type="xsd:string"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="ClaimIn">
<wsdl:part name="body" element="types:ClaimDetail"/>
<wsdl:part name="ClaimPhoto" type="xsd:base64Binary"/>
</wsdl:message>
<wsdl:message name="ClaimOut">
<wsdl:part name="out" element="types:ClaimRefNo"/>
</wsdl:message>
<wsdl:portType name="ClaimPortType">
<wsdl:operation name="SendClaim">
<wsdl:input message="tns:ClaimIn"/>
<wsdl:output message="tns:ClaimOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ClaimBinding" type="tns:ClaimPortType">
<soapbind:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="SendClaim">
<soapbind:operation soapAction="http://example.com/soapaction"/>
<wsdl:input>
<mime:multipartRelated>
<mime:part>
<soapbind:body parts="body" use="literal"/>
</mime:part>
<mime:part>
<mime:content part="ClaimPhoto" type="*/*"/>
</mime:part>
</mime:multipartRelated>
</wsdl:input>
<wsdl:output>
<soapbind:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
</wsdl:definitions>

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICoDCCAgkCBEnhw2IwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAk5aMRMw
EQYDVQQIEwpXZWxsaW5ndG9uMRowGAYDVQQHExFQYXJhcGFyYXVtdSBCZWFjaDEq
MCgGA1UEChMhU29zbm9za2kgU29mdHdhcmUgQXNzb2NpYXRlcyBMdGQuMRAwDgYD
VQQLEwdVbmtub3duMRgwFgYDVQQDEw9EZW5uaXMgU29zbm9za2kwHhcNMDkwNDEy
MTAzMzA2WhcNMzYwODI3MTAzMzA2WjCBljELMAkGA1UEBhMCTloxEzARBgNVBAgT
CldlbGxpbmd0b24xGjAYBgNVBAcTEVBhcmFwYXJhdW11IEJlYWNoMSowKAYDVQQK
EyFTb3Nub3NraSBTb2Z0d2FyZSBBc3NvY2lhdGVzIEx0ZC4xEDAOBgNVBAsTB1Vu
a25vd24xGDAWBgNVBAMTD0Rlbm5pcyBTb3Nub3NraTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAhOVyNK8xyxtb4DnKtU6mF9KoiFqCk7eKoLE26+9h410CtTkx
zWAfgnR+8i+LPbdsPY+yXAo6NYpCCKolXfDLe+AG2GwnMZGrIl6+BLF3hqTmIXBF
TLGUmC7A7uBTivaWgdH1w3hb33rASoVU67BVtQ3QQi99juZX4vU9o9pScocCAwEA
ATANBgkqhkiG9w0BAQUFAAOBgQBMNPo1KAGbz8Jl6HGbtAcetieSJ3bEAXmv1tcj
ysBS67AXzdu1Ac+onHh2EpzBM7kuGbw+trU+AhulooPpewIQRApXP1F0KHRDcbqW
jwvknS6HnomN9572giLGKn2601bHiRUj35hiA8aLmMUBppIRPFFAoQ0QUBCPx+m8
/0n33w==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAITlcjSvMcsbW+A5yrVOphfSqIha
gpO3iqCxNuvvYeNdArU5Mc1gH4J0fvIviz23bD2PslwKOjWKQgiqJV3wy3vgBthsJzGRqyJevgSx
d4ak5iFwRUyxlJguwO7gU4r2loHR9cN4W996wEqFVOuwVbUN0EIvfY7mV+L1PaPaUnKHAgMBAAEC
gYAZ6UqtLwN8YGc3fs0hMKZ9upsViuAuwPiMgED/G3twgzAF+ZLWQkmie+hMfCyf6eV200+pVm0n
Bz/8xH/oowxpX0Kk3szoB4vFghjU84GKUcrbhu/NRIm7l3drnfbzqhQkHDCx6n1CotI4Gs49cDWu
4uEAuxJkEIVY553unZjZgQJBAOJVIallNKmD0iQlvtWRmRzpmYDjt9vhNY6WBTIOx6SDn9SRaoSA
fkipQ2HXo04r78TQ674+zfZ1lRTkFG7px6ECQQCWUPHp3pSZOM1oGzJrNvNaw+MizZAZjq34npHm
9GRquFLG7BlCaI9QNGE7pN2ryYsYCRUMaM2e4GR0tUXxVGknAkAgrxqFU9AfCqI2Bh1gyf3KZxF7
w2axofwR8ygc6nV6FGfoUneHWubhp0/LuVAj4cRmL6Vbe8ZSaPh2Y9lviuMBAkEAicP8Q+1E4j1m
PPEYP51oYprANOiUFmhnWEL00+jPk+QFsd03tV6hYs/vAbwzkjuwqMHCMdJoCiH8z95IEUvc5wJA
MvLOuZdu4dmhOXg/YKsbMSPjFNEVskLQNSXqw6O2wIrpPg1NQvBBAOTbiuZj3vind4VPos1wc4vB
QocvdUC6dA==
-----END PRIVATE KEY-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICoDCCAgkCBEnhwzMwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNVBAYTAk5aMRMw
EQYDVQQIEwpXZWxsaW5ndG9uMRowGAYDVQQHExFQYXJhcGFyYXVtdSBCZWFjaDEq
MCgGA1UEChMhU29zbm9za2kgU29mdHdhcmUgQXNzb2NpYXRlcyBMdGQuMRAwDgYD
VQQLEwdVbmtub3duMRgwFgYDVQQDEw9EZW5uaXMgU29zbm9za2kwHhcNMDkwNDEy
MTAzMjE5WhcNMzYwODI3MTAzMjE5WjCBljELMAkGA1UEBhMCTloxEzARBgNVBAgT
CldlbGxpbmd0b24xGjAYBgNVBAcTEVBhcmFwYXJhdW11IEJlYWNoMSowKAYDVQQK
EyFTb3Nub3NraSBTb2Z0d2FyZSBBc3NvY2lhdGVzIEx0ZC4xEDAOBgNVBAsTB1Vu
a25vd24xGDAWBgNVBAMTD0Rlbm5pcyBTb3Nub3NraTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEA1H3mjQCF9uce2jmm/Yq9kE4ytfvkp4c8G90cDfJXJvOiGQds
p2vDZXKuCkHQ7vsBBXPNTt8J/d8ZbEwyuB9Ccz5pJqi6Ig6Y2/mEsPthDyh5SrJV
yQ/wxUGwmfSuwdrIMnplMTq+OR9BOfT3CvjSvuy9d6BQNo4wOMkDvmZTtI8CAwEA
ATANBgkqhkiG9w0BAQUFAAOBgQCqv4475QaqlKcN2QCZJbLVKZEX+76XLQurGkgf
2fCgesRHjfUfOHyTTlhWQdEKTcBB2XviUyyW6I//fmKfXUIiQqvgh4LHdXRPEXDf
Y9nr89MjyQpDlnl6AlrvSej30a9iwVRUeVk4d6gxWHMRonKBFgh+TGexxUXHtPkf
B1Pdtg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,144 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\Mime\MultiPart;
use BeSimple\SoapCommon\Mime\Part;
use BeSimple\SoapCommon\Mime\PartHeader;
class MultiPartTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$mp = new MultiPart();
$this->assertEquals('1.0', $mp->getHeader('MIME-Version'));
$this->assertEquals('multipart/related', $mp->getHeader('Content-Type'));
$this->assertEquals('text/xml', $mp->getHeader('Content-Type', 'type'));
$this->assertEquals('utf-8', $mp->getHeader('Content-Type', 'charset'));
$this->assertRegExp('~urn:uuid:.*~', $mp->getHeader('Content-Type', 'boundary'));
}
public function testGetMimeMessage()
{
$mp = new MultiPart();
/*
string(51) "
--urn:uuid:a81ca327-591e-4656-91a1-8f177ada95b0--"
*/
$this->assertEquals(51, strlen($mp->getMimeMessage()));
$p = new Part('test');
$mp->addPart($p, true);
/*
string(259) "
--urn:uuid:a81ca327-591e-4656-91a1-8f177ada95b0
Content-Type: application/octet-stream; charset=utf-8
Content-Transfer-Encoding: binary
Content-ID: <urn:uuid:a0ad4376-5b08-4471-9f6f-c29aee881e84>
test
--urn:uuid:a81ca327-591e-4656-91a1-8f177ada95b0--"
*/
$this->assertEquals(259, strlen($mp->getMimeMessage()));
}
public function testGetMimeMessageWithHeaders()
{
$mp = new MultiPart();
/*
string(189) "MIME-Version: 1.0
Content-Type: multipart/related; type="text/xml"; charset=utf-8; boundary="urn:uuid:231833e2-a23b-410a-862e-250524fc38f6"
--urn:uuid:231833e2-a23b-410a-862e-250524fc38f6--"
*/
$this->assertEquals(193, strlen($mp->getMimeMessage(true)));
$p = new Part('test');
$mp->addPart($p, true);
/*
string(452) "MIME-Version: 1.0
Content-Type: multipart/related; type="text/xml"; charset=utf-8; boundary="urn:uuid:231833e2-a23b-410a-862e-250524fc38f6"; start="<urn:uuid:9389c081-56f7-4f57-b66e-c81892c3d4db>"
--urn:uuid:231833e2-a23b-410a-862e-250524fc38f6
Content-Type: application/octet-stream; charset=utf-8
Content-Transfer-Encoding: binary
Content-ID: <urn:uuid:9389c081-56f7-4f57-b66e-c81892c3d4db>
test
--urn:uuid:231833e2-a23b-410a-862e-250524fc38f6--"
*/
$this->assertEquals(458, strlen($mp->getMimeMessage(true)));
}
public function testGetHeadersForHttp()
{
$mp = new MultiPart();
$result = array(
'Content-Type: multipart/related; type="text/xml"; charset=utf-8; boundary="' . $mp->getHeader('Content-Type', 'boundary') . '"',
);
$this->assertEquals($result, $mp->getHeadersForHttp());
$result = array(
'Content-Type: multipart/related; type="text/xml"; charset=utf-8; boundary="' . $mp->getHeader('Content-Type', 'boundary') . '"',
'Content-Description: test',
);
$mp->setHeader('Content-Description', 'test');
$this->assertEquals($result, $mp->getHeadersForHttp());
}
public function testAddGetPart()
{
$mp = new MultiPart();
$p = new Part('test');
$p->setHeader('Content-ID', 'mycontentid');
$mp->addPart($p);
$this->assertEquals($p, $mp->getPart('mycontentid'));
}
public function testAddGetPartWithMain()
{
$mp = new MultiPart();
$p = new Part('test');
$mp->addPart($p, true);
$this->assertEquals($p, $mp->getPart());
}
public function testGetParts()
{
$mp = new MultiPart();
$p1 = new Part('test');
$mp->addPart($p1, true);
$p2 = new Part('test');
$mp->addPart($p2);
$withoutMain = array(
trim($p2->getHeader('Content-ID'),'<>') => $p2,
);
$this->assertEquals($withoutMain, $mp->getParts());
$withMain = array(
trim($p1->getHeader('Content-ID'),'<>') => $p1,
trim($p2->getHeader('Content-ID'),'<>') => $p2,
);
$this->assertEquals($withMain, $mp->getParts(true));
}
}

View File

@ -0,0 +1,153 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\Mime\MultiPart;
use BeSimple\SoapCommon\Mime\Parser;
use BeSimple\SoapCommon\Mime\Part;
use BeSimple\SoapCommon\Mime\PartHeader;
class ParserTest extends \PHPUnit_Framework_TestCase
{
public function testParserRequestWsi()
{
$filename = dirname(__DIR__).DIRECTORY_SEPARATOR.'Fixtures/WS-I-MTOM-request.txt';
$mimeMessage = file_get_contents($filename);
$mp = Parser::parseMimeMessage($mimeMessage);
$this->assertsForWsiMtomRequest($mp);
}
public function testParserResponseAmazon()
{
$filename = dirname(__DIR__).DIRECTORY_SEPARATOR.'Fixtures/SwA-response-amazon.txt';
$mimeMessage = file_get_contents($filename);
$mp = Parser::parseMimeMessage($mimeMessage);
$this->assertEquals('Fri, 12 Feb 2010 15:46:00 GMT', $mp->getHeader('Date'));
$this->assertEquals('Server', $mp->getHeader('Server'));
$this->assertEquals('1.0', $mp->getHeader('MIME-Version'));
$this->assertEquals('close', $mp->getHeader('Cneonction'));
$this->assertEquals('chunked', $mp->getHeader('Transfer-Encoding'));
$this->assertEquals('multipart/related', $mp->getHeader('Content-Type'));
$this->assertEquals('text/xml', $mp->getHeader('Content-Type', 'type'));
$this->assertEquals('utf-8', $mp->getHeader('Content-Type', 'charset'));
$this->assertEquals('xxx-MIME-Boundary-xxx-0xa36cb38-0a36cb38-xxx-END-xxx', $mp->getHeader('Content-Type', 'boundary'));
$p1 = $mp->getPart();
$this->assertEquals('text/xml', $p1->getHeader('Content-Type'));
$this->assertEquals('UTF-8', $p1->getHeader('Content-Type', 'charset'));
$this->assertEquals(389, strlen($p1->getContent()));
$p2 = $mp->getPart('0x9d6ad00-0xa19ef48-0x9de7500-0xa4fae78-0xa382698');
$this->assertEquals('binary', $p2->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('application/binary', $p2->getHeader('Content-Type'));
$this->assertEquals(79, strlen($p2->getContent()));
}
public function testParserResponseAxis()
{
$filename = dirname(__DIR__).DIRECTORY_SEPARATOR.'Fixtures/SwA-response-axis.txt';
$mimeMessage = file_get_contents($filename);
$mp = Parser::parseMimeMessage($mimeMessage);
$this->assertEquals('Sat, 11 Sep 2010 12:52:57 GMT', $mp->getHeader('Date'));
$this->assertEquals('Simple-Server/1.1', $mp->getHeader('Server'));
$this->assertEquals('1.0', $mp->getHeader('MIME-Version'));
$this->assertEquals('chunked', $mp->getHeader('Transfer-Encoding'));
$this->assertEquals('multipart/related', $mp->getHeader('Content-Type'));
$this->assertEquals('application/soap+xml', $mp->getHeader('Content-Type', 'type'));
$this->assertEquals('utf-8', $mp->getHeader('Content-Type', 'charset'));
$this->assertEquals('<0.urn:uuid:2DB7ABF3DC5BED7FA51284209577583@apache.org>', $mp->getHeader('Content-Type', 'start'));
$this->assertEquals('urn:getVersionResponse', $mp->getHeader('Content-Type', 'action'));
$this->assertEquals('MIMEBoundaryurn_uuid_2DB7ABF3DC5BED7FA51284209577582', $mp->getHeader('Content-Type', 'boundary'));
$p1 = $mp->getPart('0.urn:uuid:2DB7ABF3DC5BED7FA51284209577583@apache.org');
$this->assertEquals('8bit', $p1->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('application/soap+xml', $p1->getHeader('Content-Type'));
$this->assertEquals('utf-8', $p1->getHeader('Content-Type', 'charset'));
$this->assertEquals(499, strlen($p1->getContent()));
}
public function testParserResponseWsi()
{
$filename = dirname(__DIR__).DIRECTORY_SEPARATOR.'Fixtures/WS-I-MTOM-response.txt';
$mimeMessage = file_get_contents($filename);
$mp = Parser::parseMimeMessage($mimeMessage);
$this->assertEquals('Keep-Alive', $mp->getHeader('Proxy-Connection'));
$this->assertEquals('Keep-Alive', $mp->getHeader('Connection'));
$this->assertEquals('1166', $mp->getHeader('Content-Length'));
$this->assertEquals('1.1 RED-PRXY-03', $mp->getHeader('Via'));
$this->assertEquals('Fri, 09 Sep 2005 06:57:22 GMT', $mp->getHeader('Date'));
$this->assertEquals('multipart/related', $mp->getHeader('Content-Type'));
$this->assertEquals('application/xop+xml', $mp->getHeader('Content-Type', 'type'));
$this->assertEquals('utf-8', $mp->getHeader('Content-Type', 'charset'));
$this->assertEquals('<http://tempuri.org/0>', $mp->getHeader('Content-Type', 'start'));
$this->assertEquals('application/soap+xml', $mp->getHeader('Content-Type', 'start-info'));
$this->assertEquals('uuid:b71dc628-ec8f-4422-8a4a-992f041cb94c+id=46', $mp->getHeader('Content-Type', 'boundary'));
$p1 = $mp->getPart('http://tempuri.org/0');
$this->assertEquals('8bit', $p1->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('application/xop+xml', $p1->getHeader('Content-Type'));
$this->assertEquals('utf-8', $p1->getHeader('Content-Type', 'charset'));
$this->assertEquals('application/soap+xml', $p1->getHeader('Content-Type', 'type'));
$this->assertEquals(910, strlen($p1->getContent()));
}
public function testParserWithHeaderArray()
{
$filename = dirname(__DIR__).DIRECTORY_SEPARATOR.'Fixtures/WS-I-MTOM-request_noheader.txt';
$mimeMessage = file_get_contents($filename);
$headers = array(
'Content-Type' => 'multipart/related; type="application/xop+xml";start="<http://tempuri.org/0>";boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7";start-info="application/soap+xml"',
'Content-Length' => 1941,
'Host' => '131.107.72.15',
'Expect' => '100-continue',
);
$mp = Parser::parseMimeMessage($mimeMessage, $headers);
$this->assertsForWsiMtomRequest($mp);
}
/*
* used in:
* - testParserWithHeaderArray
* - testParserRequestWsi
*/
private function assertsForWsiMtomRequest(MultiPart $mp)
{
$this->assertEquals('multipart/related', $mp->getHeader('Content-Type'));
$this->assertEquals('application/xop+xml', $mp->getHeader('Content-Type', 'type'));
$this->assertEquals('utf-8', $mp->getHeader('Content-Type', 'charset'));
$this->assertEquals('<http://tempuri.org/0>', $mp->getHeader('Content-Type', 'start'));
$this->assertEquals('application/soap+xml', $mp->getHeader('Content-Type', 'start-info'));
$this->assertEquals('uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=7', $mp->getHeader('Content-Type', 'boundary'));
$this->assertEquals('1941', $mp->getHeader('Content-Length'));
$this->assertEquals('131.107.72.15', $mp->getHeader('Host'));
$this->assertEquals('100-continue', $mp->getHeader('Expect'));
$p1 = $mp->getPart('http://tempuri.org/0');
$this->assertEquals('8bit', $p1->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('application/xop+xml', $p1->getHeader('Content-Type'));
$this->assertEquals('utf-8', $p1->getHeader('Content-Type', 'charset'));
$this->assertEquals('application/soap+xml', $p1->getHeader('Content-Type', 'type'));
$this->assertEquals(737, strlen($p1->getContent()));
$p2 = $mp->getPart('http://tempuri.org/1/632618206527087310');
$this->assertEquals('binary', $p2->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('application/octet-stream', $p2->getHeader('Content-Type'));
$this->assertEquals(769, strlen($p2->getContent()));
}
}

View File

@ -0,0 +1,57 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\Mime\PartHeader;
use BeSimple\Tests\SoapCommon\Fixtures\MimePartHeader;
class PartHeaderTest extends \PHPUnit_Framework_TestCase
{
public function testSetGetHeader()
{
$ph = new MimePartHeader();
$ph->setHeader('Content-Type', 'text/xml');
$this->assertEquals('text/xml', $ph->getHeader('Content-Type'));
}
public function testSetGetHeaderSubvalue()
{
$ph = new MimePartHeader();
$ph->setHeader('Content-Type', 'utf-8', 'charset');
$this->assertEquals(null, $ph->getHeader('Content-Type', 'charset'));
$ph->setHeader('Content-Type', 'text/xml');
$ph->setHeader('Content-Type', 'charset', 'utf-8');
$this->assertEquals('utf-8', $ph->getHeader('Content-Type', 'charset'));
}
public function testGenerateHeaders()
{
$ph = new MimePartHeader();
$class = new \ReflectionClass($ph);
$method = $class->getMethod('generateHeaders');
$method->setAccessible(true);
$this->assertEquals('', $method->invoke($ph));
$ph->setHeader('Content-Type', 'text/xml');
$this->assertEquals("Content-Type: text/xml\r\n", $method->invoke($ph));
$ph->setHeader('Content-Type', 'charset', 'utf-8');
$this->assertEquals("Content-Type: text/xml; charset=utf-8\r\n", $method->invoke($ph));
$ph->setHeader('Content-Type', 'type', 'text/xml');
$this->assertEquals("Content-Type: text/xml; charset=utf-8; type=\"text/xml\"\r\n", $method->invoke($ph));
}
}

View File

@ -0,0 +1,62 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\Mime\Part;
use BeSimple\SoapCommon\Mime\PartHeader;
class PartTest extends \PHPUnit_Framework_TestCase
{
public function testConstructor()
{
$p = new Part('<xml1/>', 'text/xml', 'utf-8', Part::ENCODING_BINARY, 'urn:myuniqueresource');
$this->assertEquals('<xml1/>', $p->getContent());
$this->assertEquals('text/xml', $p->getHeader('Content-Type'));
$this->assertEquals('utf-8', $p->getHeader('Content-Type', 'charset'));
$this->assertEquals(Part::ENCODING_BINARY, $p->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('<urn:myuniqueresource>', $p->getHeader('Content-ID'));
}
public function testDefaultConstructor()
{
$p = new Part();
$this->assertNull($p->getContent());
$this->assertEquals('application/octet-stream', $p->getHeader('Content-Type'));
$this->assertEquals('utf-8', $p->getHeader('Content-Type', 'charset'));
$this->assertEquals(Part::ENCODING_BINARY, $p->getHeader('Content-Transfer-Encoding'));
$this->assertRegExp('~<urn:uuid:.*>~', $p->getHeader('Content-ID'));
}
public function testSetContent()
{
$p = new Part();
$p->setContent('<xml1/>');
$this->assertEquals('<xml1/>', $p->getContent());
}
public function testGetMessagePart()
{
$p = new Part('<xml1/>', 'text/xml', 'utf-8', Part::ENCODING_BINARY, 'urn:myuniqueresource');
$messagePart = "Content-Type: text/xml; charset=utf-8\r\n" .
"Content-Transfer-Encoding: binary\r\n" .
"Content-ID: <urn:myuniqueresource>\r\n" .
"\r\n".
"<xml1/>";
$this->assertEquals($messagePart, $p->getMessagePart());
}
}

View File

@ -0,0 +1,119 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\WsSecurityKey;
use ass\XmlSecurity\Key as XmlSecurityKey;
class WsSecurityKeyTest extends \PHPUnit_Framework_TestCase
{
public function testHasKeys()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientkey.pem';
$wsk->addPrivateKey(\ass\XmlSecurity\Key::RSA_SHA1, $filename);
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientcert.pem';
$wsk->addPublicKey(\ass\XmlSecurity\Key::RSA_SHA1, $filename);
$this->assertTrue($wsk->hasKeys());
$this->assertTrue($wsk->hasPrivateKey());
$this->assertTrue($wsk->hasPublicKey());
}
public function testHasKeysNone()
{
$wsk = new WsSecurityKey();
$this->assertFalse($wsk->hasKeys());
$this->assertFalse($wsk->hasPrivateKey());
$this->assertFalse($wsk->hasPublicKey());
}
public function testHasPrivateKey()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientkey.pem';
$wsk->addPrivateKey(\ass\XmlSecurity\Key::RSA_SHA1, $filename);
$this->assertFalse($wsk->hasKeys());
$this->assertTrue($wsk->hasPrivateKey());
}
public function testHasPublicKey()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientcert.pem';
$wsk->addPublicKey(\ass\XmlSecurity\Key::RSA_SHA1, $filename);
$this->assertFalse($wsk->hasKeys());
$this->assertTrue($wsk->hasPublicKey());
}
public function testAddPrivateKey()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientkey.pem';
$wsk->addPrivateKey(\ass\XmlSecurity\Key::RSA_SHA1, $filename);
$this->assertTrue($wsk->hasPrivateKey());
$this->assertInstanceOf('ass\XmlSecurity\Key', $wsk->getPrivateKey());
}
public function testAddPrivateKeySessionKey()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientkey.pem';
$wsk->addPrivateKey(\ass\XmlSecurity\Key::TRIPLEDES_CBC);
$this->assertTrue($wsk->hasPrivateKey());
$this->assertInstanceOf('ass\XmlSecurity\Key', $wsk->getPrivateKey());
}
public function testAddPrivateKeyNoFile()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientkey.pem';
$wsk->addPrivateKey(\ass\XmlSecurity\Key::RSA_SHA1, file_get_contents($filename), false);
$this->assertTrue($wsk->hasPrivateKey());
$this->assertInstanceOf('ass\XmlSecurity\Key', $wsk->getPrivateKey());
}
public function testAddPublicKey()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientcert.pem';
$wsk->addPublicKey(\ass\XmlSecurity\Key::RSA_SHA1, $filename);
$this->assertTrue($wsk->hasPublicKey());
$this->assertInstanceOf('ass\XmlSecurity\Key', $wsk->getPublicKey());
}
public function testAddPublicKeyNoFile()
{
$wsk = new WsSecurityKey();
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/clientcert.pem';
$wsk->addPublicKey(\ass\XmlSecurity\Key::RSA_SHA1, file_get_contents($filename), false);
$this->assertTrue($wsk->hasPublicKey());
$this->assertInstanceOf('ass\XmlSecurity\Key', $wsk->getPublicKey());
}
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the BeSimpleSoapBundle.
*
* (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\Tests\SoapCommon\Soap;
use BeSimple\SoapCommon\WsdlHandler;
class WsdlHandlerTest extends \PHPUnit_Framework_TestCase
{
public function testIsValidMimeTypeType()
{
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/WsdlMimeContent.wsdl';
$wh = new WsdlHandler($filename, SOAP_1_1);
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'body', 'text/xml'));
$this->assertFalse($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'body', 'image/gif'));
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'image/jpeg'));
$this->assertFalse($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'image/gif'));
$this->assertFalse($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'text/xml'));
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/WsdlMimeContent2.wsdl';
$wh = new WsdlHandler($filename, SOAP_1_1);
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'body', 'text/xml'));
$this->assertFalse($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'body', 'image/gif'));
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'image/jpeg'));
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'image/gif'));
$this->assertFalse($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'text/xml'));
$filename = __DIR__.DIRECTORY_SEPARATOR.'Fixtures/WsdlMimeContent3.wsdl';
$wh = new WsdlHandler($filename, SOAP_1_1);
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'body', 'text/xml'));
$this->assertFalse($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'body', 'image/gif'));
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'image/jpeg'));
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'image/gif'));
$this->assertTrue($wh->isValidMimeTypeType('http://example.com/soapaction', WsdlHandler::BINDING_OPERATION_INPUT, 'ClaimPhoto', 'text/xml'));
}
}

View File

@ -0,0 +1,5 @@
<?php
$loader = require __DIR__.'/../vendor/autoload.php';
$loader->add('BeSimple\Tests\SoapCommon\\', __DIR__);

View File

@ -0,0 +1,42 @@
#!/usr/bin/env php
<?php
/*
* This file is part of the BeSimpleSoapCommon.
*
* (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.
*/
/*
CAUTION: This file installs the dependencies needed to run the BeSimpleSoapCommon test suite.
https://github.com/BeSimple/BeSimpleSoapCommon
*/
if (!is_dir($vendorDir = dirname(__FILE__).'/vendor')) {
mkdir($vendorDir, 0777, true);
}
$deps = array(
array('vfsStream', 'https://github.com/mikey179/vfsStream.git', 'RELEASE-0.10.1'),
array('XmlSecurity', 'https://github.com/aschamberger/XmlSecurity.git', 'origin/HEAD'),
);
foreach ($deps as $dep) {
list($name, $url, $rev) = $dep;
echo "> Installing/Updating $name\n";
$installDir = $vendorDir.'/'.$name;
if (!is_dir($installDir)) {
system(sprintf('git clone %s %s', escapeshellarg($url), escapeshellarg($installDir)));
}
system(sprintf('cd %s && git fetch origin && git reset --hard %s', escapeshellarg($installDir), escapeshellarg($rev)));
}