Merge pull request #5 from aschamberger/master

Interfaces for processing SoapRequest/SoapResponse in Client/Server #2
This commit is contained in:
Christian Kerl 2012-01-08 11:15:15 -08:00
commit f6a0dcf9a7
20 changed files with 979 additions and 11 deletions

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

@ -13,15 +13,41 @@
namespace BeSimple\SoapCommon\Converter; namespace BeSimple\SoapCommon\Converter;
/** /**
* Type converter interface.
*
* @author Christian Kerl <christian-kerl@web.de> * @author Christian Kerl <christian-kerl@web.de>
*/ */
interface TypeConverterInterface interface TypeConverterInterface
{ {
/**
* Get type namespace.
*
* @return string
*/
function getTypeNamespace(); function getTypeNamespace();
/**
* Get type name.
*
* @return string
*/
function getTypeName(); function getTypeName();
/**
* Convert given XML string to PHP type.
*
* @param string $data XML string
*
* @return mixed
*/
function convertXmlToPhp($data); function convertXmlToPhp($data);
/**
* Convert PHP type to XML string.
*
* @param mixed $data PHP type
*
* @return string
*/
function convertPhpToXml($data); 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

@ -191,6 +191,7 @@ class Helper
* Get SOAP namespace for the given $version. * Get SOAP namespace for the given $version.
* *
* @param int $version SOAP_1_1|SOAP_1_2 * @param int $version SOAP_1_1|SOAP_1_2
*
* @return string * @return string
*/ */
public static function getSoapNamespace($version) public static function getSoapNamespace($version)
@ -206,6 +207,7 @@ class Helper
* Get SOAP version from namespace URI. * Get SOAP version from namespace URI.
* *
* @param string $namespace NS_SOAP_1_1|NS_SOAP_1_2 * @param string $namespace NS_SOAP_1_1|NS_SOAP_1_2
*
* @return int SOAP_1_1|SOAP_1_2 * @return int SOAP_1_1|SOAP_1_2
*/ */
public static function getSoapVersionFromNamespace($namespace) public static function getSoapVersionFromNamespace($namespace)

View File

@ -46,6 +46,7 @@ class MultiPart extends PartHeader
* Construct new mime object. * Construct new mime object.
* *
* @param string $boundary Boundary string * @param string $boundary Boundary string
*
* @return void * @return void
*/ */
public function __construct($boundary = null) public function __construct($boundary = null)
@ -64,6 +65,7 @@ class MultiPart extends PartHeader
* Get mime message of this object (without headers). * Get mime message of this object (without headers).
* *
* @param boolean $withHeaders Returned mime message contains headers * @param boolean $withHeaders Returned mime message contains headers
*
* @return string * @return string
*/ */
public function getMimeMessage($withHeaders = false) public function getMimeMessage($withHeaders = false)
@ -106,6 +108,7 @@ class MultiPart extends PartHeader
* *
* @param \BeSimple\SoapCommon\Mime\Part $part Part that is added * @param \BeSimple\SoapCommon\Mime\Part $part Part that is added
* @param boolean $isMain Is the given part the main part of mime message * @param boolean $isMain Is the given part the main part of mime message
*
* @return void * @return void
*/ */
public function addPart(Part $part, $isMain = false) public function addPart(Part $part, $isMain = false)
@ -124,6 +127,7 @@ class MultiPart extends PartHeader
* parameter. * parameter.
* *
* @param string $contentId Content id of desired part * @param string $contentId Content id of desired part
*
* @return \BeSimple\SoapCommon\Mime\Part|null * @return \BeSimple\SoapCommon\Mime\Part|null
*/ */
public function getPart($contentId = null) public function getPart($contentId = null)
@ -141,6 +145,7 @@ class MultiPart extends PartHeader
* Get all parts. * Get all parts.
* *
* @param boolean $includeMainPart Should main part be in result set * @param boolean $includeMainPart Should main part be in result set
*
* @return array(\BeSimple\SoapCommon\Mime\Part) * @return array(\BeSimple\SoapCommon\Mime\Part)
*/ */
public function getParts($includeMainPart = false) public function getParts($includeMainPart = false)

View File

@ -24,6 +24,7 @@ class Parser
* *
* @param string $mimeMessage Mime message string * @param string $mimeMessage Mime message string
* @param array(string=>string) $headers Array of header elements (e.g. coming from http request) * @param array(string=>string) $headers Array of header elements (e.g. coming from http request)
*
* @return \BeSimple\SoapCommon\Mime\MultiPart * @return \BeSimple\SoapCommon\Mime\MultiPart
*/ */
public static function parseMimeMessage($mimeMessage, array $headers = array()) public static function parseMimeMessage($mimeMessage, array $headers = array())
@ -31,6 +32,8 @@ class Parser
$boundary = null; $boundary = null;
$start = null; $start = null;
$multipart = new MultiPart(); $multipart = new MultiPart();
$hitFirstBoundary = false;
$inHeader = true;
// add given headers, e.g. coming from HTTP headers // add given headers, e.g. coming from HTTP headers
if (count($headers) > 0) { if (count($headers) > 0) {
foreach ($headers as $name => $value) { foreach ($headers as $name => $value) {
@ -42,12 +45,11 @@ class Parser
$multipart->setHeader($name, $value); $multipart->setHeader($name, $value);
} }
} }
$inHeader = false;
} }
$hitFirstBoundary = false;
$inHeader = true;
$content = ''; $content = '';
$currentPart = $multipart; $currentPart = $multipart;
$lines = preg_split("/\r\n|\n/", $mimeMessage); $lines = preg_split("/(\r\n)/", $mimeMessage);
foreach ($lines as $line) { foreach ($lines as $line) {
// ignore http status code and POST * // ignore http status code and POST *
if (substr($line, 0, 5) == 'HTTP/' || substr($line, 0, 4) == 'POST') { if (substr($line, 0, 5) == 'HTTP/' || substr($line, 0, 4) == 'POST') {
@ -72,7 +74,7 @@ class Parser
unset($currentHeader); unset($currentHeader);
} }
if ($inHeader) { if ($inHeader) {
if ($line == '') { if (trim($line) == '') {
$inHeader = false; $inHeader = false;
continue; continue;
} }
@ -83,7 +85,7 @@ class Parser
if (strlen($line) > 0 && $line[0] == "-") { if (strlen($line) > 0 && $line[0] == "-") {
if (strcmp(trim($line), '--' . $boundary) === 0) { if (strcmp(trim($line), '--' . $boundary) === 0) {
if ($currentPart instanceof Part) { if ($currentPart instanceof Part) {
$content = iconv_substr($content, 0, -2, 'utf-8'); $content = substr($content, 0, -2);
self::decodeContent($currentPart, $content); self::decodeContent($currentPart, $content);
// check if there is a start parameter given, if not set first part // check if there is a start parameter given, if not set first part
$isMain = (is_null($start) || $start == $currentPart->getHeader('Content-ID')) ? true : false; $isMain = (is_null($start) || $start == $currentPart->getHeader('Content-ID')) ? true : false;
@ -97,7 +99,7 @@ class Parser
$inHeader = true; $inHeader = true;
$content = ''; $content = '';
} elseif (strcmp(trim($line), '--' . $boundary . '--') === 0) { } elseif (strcmp(trim($line), '--' . $boundary . '--') === 0) {
$content = iconv_substr($content, 0, -2, 'utf-8'); $content = substr($content, 0, -2);
self::decodeContent($currentPart, $content); self::decodeContent($currentPart, $content);
// check if there is a start parameter given, if not set first part // check if there is a start parameter given, if not set first part
$isMain = (is_null($start) || $start == $currentPart->getHeader('Content-ID')) ? true : false; $isMain = (is_null($start) || $start == $currentPart->getHeader('Content-ID')) ? true : false;
@ -109,7 +111,7 @@ class Parser
} }
} else { } else {
if ($hitFirstBoundary === false) { if ($hitFirstBoundary === false) {
if ($line != '') { if (trim($line) != '') {
$inHeader = true; $inHeader = true;
$currentHeader = $line; $currentHeader = $line;
continue; continue;
@ -118,7 +120,6 @@ class Parser
$content .= $line . "\r\n"; $content .= $line . "\r\n";
} }
} }
} }
return $multipart; return $multipart;
} }
@ -133,6 +134,7 @@ class Parser
* @param \BeSimple\SoapCommon\Mime\PartHeader $part Header part * @param \BeSimple\SoapCommon\Mime\PartHeader $part Header part
* @param string $headerName Header name * @param string $headerName Header name
* @param string $headerValue Header value * @param string $headerValue Header value
*
* @return null * @return null
*/ */
private static function parseContentTypeHeader(PartHeader $part, $headerName, $headerValue) private static function parseContentTypeHeader(PartHeader $part, $headerName, $headerValue)
@ -165,6 +167,7 @@ class Parser
* *
* @param \BeSimple\SoapCommon\Mime\Part $part Part to add content * @param \BeSimple\SoapCommon\Mime\Part $part Part to add content
* @param string $content Content to decode * @param string $content Content to decode
*
* @return null * @return null
*/ */
private static function decodeContent(Part $part, $content) private static function decodeContent(Part $part, $content)

View File

@ -68,6 +68,7 @@ class Part extends PartHeader
* @param string $charset Charset * @param string $charset Charset
* @param string $encoding Encoding * @param string $encoding Encoding
* @param string $contentId Content id * @param string $contentId Content id
*
* @return void * @return void
*/ */
public function __construct($content = null, $contentType = 'application/octet-stream', $charset = null, $encoding = self::ENCODING_BINARY, $contentId = null) public function __construct($content = null, $contentType = 'application/octet-stream', $charset = null, $encoding = self::ENCODING_BINARY, $contentId = null)
@ -76,7 +77,7 @@ class Part extends PartHeader
$this->setHeader('Content-Type', $contentType); $this->setHeader('Content-Type', $contentType);
if (!is_null($charset)) { if (!is_null($charset)) {
$this->setHeader('Content-Type', 'charset', $charset); $this->setHeader('Content-Type', 'charset', $charset);
} else { // if (substr($contentType, 0, 4) == 'text') { } else {
$this->setHeader('Content-Type', 'charset', 'utf-8'); $this->setHeader('Content-Type', 'charset', 'utf-8');
} }
$this->setHeader('Content-Transfer-Encoding', $encoding); $this->setHeader('Content-Transfer-Encoding', $encoding);
@ -110,6 +111,7 @@ class Part extends PartHeader
* Set mime content. * Set mime content.
* *
* @param mixed $content Content to set * @param mixed $content Content to set
*
* @return void * @return void
*/ */
public function setContent($content) public function setContent($content)
@ -147,6 +149,7 @@ class Part extends PartHeader
case self::ENCODING_QUOTED_PRINTABLE: case self::ENCODING_QUOTED_PRINTABLE:
return quoted_printable_encode($content); return quoted_printable_encode($content);
case self::ENCODING_BINARY: case self::ENCODING_BINARY:
return $content;
case self::ENCODING_SEVEN_BIT: case self::ENCODING_SEVEN_BIT:
case self::ENCODING_EIGHT_BIT: case self::ENCODING_EIGHT_BIT:
default: default:

View File

@ -32,6 +32,7 @@ abstract class PartHeader
* @param string $name Header name * @param string $name Header name
* @param string $value Header value * @param string $value Header value
* @param string $subValue Is sub value? * @param string $subValue Is sub value?
*
* @return void * @return void
*/ */
public function setHeader($name, $value, $subValue = null) public function setHeader($name, $value, $subValue = null)
@ -57,6 +58,7 @@ abstract class PartHeader
* *
* @param string $name Header name * @param string $name Header name
* @param string $subValue Sub value name * @param string $subValue Sub value name
*
* @return mixed|array(mixed) * @return mixed|array(mixed)
*/ */
public function getHeader($name, $subValue = null) public function getHeader($name, $subValue = null)
@ -104,6 +106,7 @@ abstract class PartHeader
* Generates a header field value from the given value paramater. * Generates a header field value from the given value paramater.
* *
* @param array(string=>string)|string $value Header value * @param array(string=>string)|string $value Header value
*
* @return string * @return string
*/ */
protected function generateHeaderFieldValue($value) protected function generateHeaderFieldValue($value)
@ -129,6 +132,7 @@ abstract class PartHeader
* "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "=" * "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "="
* *
* @param string $string String to quote * @param string $string String to quote
*
* @return string * @return string
*/ */
private function quoteValueString($string) private function quoteValueString($string)

View File

@ -0,0 +1,137 @@
<?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)
{
$request->setAttachments($this->attachments);
$this->attachments = array();
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);
}
$this->attachments = $response->getAttachments();
}
}

View File

@ -0,0 +1,256 @@
<?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();
}
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

@ -42,6 +42,7 @@ class WsSecurityKey
* @param string $key Private key * @param string $key Private key
* @param boolean $keyIsFile Given key parameter is path to key file * @param boolean $keyIsFile Given key parameter is path to key file
* @param string $passphrase Passphrase for key * @param string $passphrase Passphrase for key
*
* @return void * @return void
*/ */
public function addPrivateKey($encryptionType, $key = null, $keyIsFile = true, $passphrase = null) public function addPrivateKey($encryptionType, $key = null, $keyIsFile = true, $passphrase = null)
@ -55,6 +56,7 @@ class WsSecurityKey
* @param string $encryptionType Encryption type * @param string $encryptionType Encryption type
* @param string $key Public key * @param string $key Public key
* @param boolean $keyIsFile Given key parameter is path to key file * @param boolean $keyIsFile Given key parameter is path to key file
*
* @return void * @return void
*/ */
public function addPublicKey($encryptionType, $key = null, $keyIsFile = true) public function addPublicKey($encryptionType, $key = null, $keyIsFile = true)

View File

@ -87,6 +87,7 @@ class WsdlHandler
* Gets the mime type information from the WSDL file. * Gets the mime type information from the WSDL file.
* *
* @param string $soapAction Soap action to analyse * @param string $soapAction Soap action to analyse
*
* @return array(string=>array(string=>array(string))) * @return array(string=>array(string=>array(string)))
*/ */
private function getMimeTypesForSoapAction($soapAction) private function getMimeTypesForSoapAction($soapAction)
@ -152,6 +153,7 @@ class WsdlHandler
* @param string $operationType Operation type * @param string $operationType Operation type
* @param string $part Part name * @param string $part Part name
* @param string $currentMimeType Current mime type * @param string $currentMimeType Current mime type
*
* @return boolean * @return boolean
*/ */
public function isValidMimeTypeType($soapAction, $operationType, $part, $currentMimeType) public function isValidMimeTypeType($soapAction, $operationType, $part, $currentMimeType)

View File

@ -52,7 +52,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase
$p2 = $mp->getPart('0x9d6ad00-0xa19ef48-0x9de7500-0xa4fae78-0xa382698'); $p2 = $mp->getPart('0x9d6ad00-0xa19ef48-0x9de7500-0xa4fae78-0xa382698');
$this->assertEquals('binary', $p2->getHeader('Content-Transfer-Encoding')); $this->assertEquals('binary', $p2->getHeader('Content-Transfer-Encoding'));
$this->assertEquals('application/binary', $p2->getHeader('Content-Type')); $this->assertEquals('application/binary', $p2->getHeader('Content-Type'));
$this->assertEquals(81, strlen($p2->getContent())); $this->assertEquals(79, strlen($p2->getContent()));
} }
public function testParserResponseAxis() public function testParserResponseAxis()

View File

@ -19,7 +19,7 @@ spl_autoload_register(function($class) {
return true; return true;
} }
} elseif (0 === strpos($class, 'ass\XmlSecurity\\')) { } elseif (0 === strpos($class, 'ass\XmlSecurity\\')) {
$path = __DIR__.'/../vendor/XmlSecurity/src/'.strtr($class, '\\', '/').'.php'; $path = __DIR__.'/../vendor/XmlSecurity/src/'.strtr($class, '\\', '/').'.php';
if (file_exists($path) && is_readable($path)) { if (file_exists($path) && is_readable($path)) {
require_once $path; require_once $path;