diff --git a/src/BeSimple/SoapCommon/Converter/MtomTypeConverter.php b/src/BeSimple/SoapCommon/Converter/MtomTypeConverter.php new file mode 100644 index 0000000..52ea961 --- /dev/null +++ b/src/BeSimple/SoapCommon/Converter/MtomTypeConverter.php @@ -0,0 +1,108 @@ + + * (c) Francis Besset + * + * 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 + */ +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; + } +} diff --git a/src/BeSimple/SoapCommon/Converter/SoapKernelAwareInterface.php b/src/BeSimple/SoapCommon/Converter/SoapKernelAwareInterface.php new file mode 100644 index 0000000..655a258 --- /dev/null +++ b/src/BeSimple/SoapCommon/Converter/SoapKernelAwareInterface.php @@ -0,0 +1,32 @@ + + * (c) Francis Besset + * + * 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 + */ +interface SoapKernelAwareInterface +{ + /** + * Set SoapKernel instance. + * + * @param \BeSimple\SoapCommon\SoapKernel $soapKernel SoapKernel instance + * + * @return void + */ + function setKernel(SoapKernel $soapKernel); +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/Converter/SwaTypeConverter.php b/src/BeSimple/SoapCommon/Converter/SwaTypeConverter.php new file mode 100644 index 0000000..40d6372 --- /dev/null +++ b/src/BeSimple/SoapCommon/Converter/SwaTypeConverter.php @@ -0,0 +1,96 @@ + + * (c) Francis Besset + * + * 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 + */ +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; + } +} diff --git a/src/BeSimple/SoapCommon/Converter/TypeConverterInterface.php b/src/BeSimple/SoapCommon/Converter/TypeConverterInterface.php index 4de7d7f..e390963 100644 --- a/src/BeSimple/SoapCommon/Converter/TypeConverterInterface.php +++ b/src/BeSimple/SoapCommon/Converter/TypeConverterInterface.php @@ -13,15 +13,41 @@ namespace BeSimple\SoapCommon\Converter; /** + * Type converter interface. + * * @author Christian Kerl */ 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); } \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/FilterHelper.php b/src/BeSimple/SoapCommon/FilterHelper.php new file mode 100644 index 0000000..01a1717 --- /dev/null +++ b/src/BeSimple/SoapCommon/FilterHelper.php @@ -0,0 +1,178 @@ + + * (c) Francis Besset + * + * 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 + */ +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; + } + } +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/Helper.php b/src/BeSimple/SoapCommon/Helper.php index 19185ed..c33a9df 100644 --- a/src/BeSimple/SoapCommon/Helper.php +++ b/src/BeSimple/SoapCommon/Helper.php @@ -191,6 +191,7 @@ class Helper * Get SOAP namespace for the given $version. * * @param int $version SOAP_1_1|SOAP_1_2 + * * @return string */ public static function getSoapNamespace($version) @@ -206,6 +207,7 @@ class Helper * 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) diff --git a/src/BeSimple/SoapCommon/Mime/MultiPart.php b/src/BeSimple/SoapCommon/Mime/MultiPart.php index 1a3b7e1..1b8ffa3 100644 --- a/src/BeSimple/SoapCommon/Mime/MultiPart.php +++ b/src/BeSimple/SoapCommon/Mime/MultiPart.php @@ -46,6 +46,7 @@ class MultiPart extends PartHeader * Construct new mime object. * * @param string $boundary Boundary string + * * @return void */ public function __construct($boundary = null) @@ -64,6 +65,7 @@ class MultiPart extends PartHeader * Get mime message of this object (without headers). * * @param boolean $withHeaders Returned mime message contains headers + * * @return string */ public function getMimeMessage($withHeaders = false) @@ -106,6 +108,7 @@ class MultiPart extends PartHeader * * @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) @@ -124,6 +127,7 @@ class MultiPart extends PartHeader * parameter. * * @param string $contentId Content id of desired part + * * @return \BeSimple\SoapCommon\Mime\Part|null */ public function getPart($contentId = null) @@ -141,6 +145,7 @@ class MultiPart extends PartHeader * Get all parts. * * @param boolean $includeMainPart Should main part be in result set + * * @return array(\BeSimple\SoapCommon\Mime\Part) */ public function getParts($includeMainPart = false) diff --git a/src/BeSimple/SoapCommon/Mime/Parser.php b/src/BeSimple/SoapCommon/Mime/Parser.php index ab41b97..c4a8c27 100644 --- a/src/BeSimple/SoapCommon/Mime/Parser.php +++ b/src/BeSimple/SoapCommon/Mime/Parser.php @@ -24,6 +24,7 @@ class Parser * * @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()) @@ -31,6 +32,8 @@ class Parser $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) { @@ -42,12 +45,11 @@ class Parser $multipart->setHeader($name, $value); } } + $inHeader = false; } - $hitFirstBoundary = false; - $inHeader = true; $content = ''; $currentPart = $multipart; - $lines = preg_split("/\r\n|\n/", $mimeMessage); + $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') { @@ -72,7 +74,7 @@ class Parser unset($currentHeader); } if ($inHeader) { - if ($line == '') { + if (trim($line) == '') { $inHeader = false; continue; } @@ -83,7 +85,7 @@ class Parser if (strlen($line) > 0 && $line[0] == "-") { if (strcmp(trim($line), '--' . $boundary) === 0) { if ($currentPart instanceof Part) { - $content = iconv_substr($content, 0, -2, 'utf-8'); + $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; @@ -97,7 +99,7 @@ class Parser $inHeader = true; $content = ''; } elseif (strcmp(trim($line), '--' . $boundary . '--') === 0) { - $content = iconv_substr($content, 0, -2, 'utf-8'); + $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; @@ -109,7 +111,7 @@ class Parser } } else { if ($hitFirstBoundary === false) { - if ($line != '') { + if (trim($line) != '') { $inHeader = true; $currentHeader = $line; continue; @@ -118,7 +120,6 @@ class Parser $content .= $line . "\r\n"; } } - } return $multipart; } @@ -133,6 +134,7 @@ class Parser * @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) @@ -165,6 +167,7 @@ class Parser * * @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) diff --git a/src/BeSimple/SoapCommon/Mime/Part.php b/src/BeSimple/SoapCommon/Mime/Part.php index 88a2ca7..714f137 100644 --- a/src/BeSimple/SoapCommon/Mime/Part.php +++ b/src/BeSimple/SoapCommon/Mime/Part.php @@ -68,6 +68,7 @@ class Part extends PartHeader * @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) @@ -76,7 +77,7 @@ class Part extends PartHeader $this->setHeader('Content-Type', $contentType); if (!is_null($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-Transfer-Encoding', $encoding); @@ -110,6 +111,7 @@ class Part extends PartHeader * Set mime content. * * @param mixed $content Content to set + * * @return void */ public function setContent($content) @@ -147,6 +149,7 @@ class Part extends PartHeader 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: diff --git a/src/BeSimple/SoapCommon/Mime/PartHeader.php b/src/BeSimple/SoapCommon/Mime/PartHeader.php index 8e78bea..ff0dcfc 100644 --- a/src/BeSimple/SoapCommon/Mime/PartHeader.php +++ b/src/BeSimple/SoapCommon/Mime/PartHeader.php @@ -32,6 +32,7 @@ abstract class PartHeader * @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) @@ -57,6 +58,7 @@ abstract class PartHeader * * @param string $name Header name * @param string $subValue Sub value name + * * @return mixed|array(mixed) */ public function getHeader($name, $subValue = null) @@ -104,6 +106,7 @@ abstract class PartHeader * Generates a header field value from the given value paramater. * * @param array(string=>string)|string $value Header value + * * @return string */ protected function generateHeaderFieldValue($value) @@ -129,6 +132,7 @@ abstract class PartHeader * "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "=" * * @param string $string String to quote + * * @return string */ private function quoteValueString($string) diff --git a/src/BeSimple/SoapCommon/SoapKernel.php b/src/BeSimple/SoapCommon/SoapKernel.php new file mode 100644 index 0000000..da57db0 --- /dev/null +++ b/src/BeSimple/SoapCommon/SoapKernel.php @@ -0,0 +1,137 @@ + + * (c) Francis Besset + * (c) Andreas Schamberger + * + * 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 + */ +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(); + } +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/SoapMessage.php b/src/BeSimple/SoapCommon/SoapMessage.php new file mode 100644 index 0000000..97e0a04 --- /dev/null +++ b/src/BeSimple/SoapCommon/SoapMessage.php @@ -0,0 +1,256 @@ + + * (c) Francis Besset + * (c) Andreas Schamberger + * + * 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 + * @author Andreas Schamberger + */ +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; + } +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/SoapRequest.php b/src/BeSimple/SoapCommon/SoapRequest.php new file mode 100644 index 0000000..314d157 --- /dev/null +++ b/src/BeSimple/SoapCommon/SoapRequest.php @@ -0,0 +1,26 @@ + + * (c) Francis Besset + * (c) Andreas Schamberger + * + * 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 + */ +class SoapRequest extends SoapMessage +{ + +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/SoapRequestFilter.php b/src/BeSimple/SoapCommon/SoapRequestFilter.php new file mode 100644 index 0000000..dbc990c --- /dev/null +++ b/src/BeSimple/SoapCommon/SoapRequestFilter.php @@ -0,0 +1,31 @@ + + * (c) Francis Besset + * (c) Andreas Schamberger + * + * 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 + */ +interface SoapRequestFilter +{ + /** + * Modify SOAP response. + * + * @param SoapRequest $request SOAP request + */ + public function filterRequest(SoapRequest $request); +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/SoapResponse.php b/src/BeSimple/SoapCommon/SoapResponse.php new file mode 100644 index 0000000..b6815b2 --- /dev/null +++ b/src/BeSimple/SoapCommon/SoapResponse.php @@ -0,0 +1,26 @@ + + * (c) Francis Besset + * (c) Andreas Schamberger + * + * 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 + */ +class SoapResponse extends SoapMessage +{ + +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/SoapResponseFilter.php b/src/BeSimple/SoapCommon/SoapResponseFilter.php new file mode 100644 index 0000000..c7d6bb6 --- /dev/null +++ b/src/BeSimple/SoapCommon/SoapResponseFilter.php @@ -0,0 +1,31 @@ + + * (c) Francis Besset + * (c) Andreas Schamberger + * + * 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 + */ +interface SoapResponseFilter +{ + /** + * Modify SOAP response. + * + * @param SoapResponse $response SOAP response + */ + public function filterResponse(SoapResponse $response); +} \ No newline at end of file diff --git a/src/BeSimple/SoapCommon/WsSecurityKey.php b/src/BeSimple/SoapCommon/WsSecurityKey.php index 327b521..432e654 100644 --- a/src/BeSimple/SoapCommon/WsSecurityKey.php +++ b/src/BeSimple/SoapCommon/WsSecurityKey.php @@ -42,6 +42,7 @@ class WsSecurityKey * @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) @@ -55,6 +56,7 @@ class WsSecurityKey * @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) diff --git a/src/BeSimple/SoapCommon/WsdlHandler.php b/src/BeSimple/SoapCommon/WsdlHandler.php index f0f533e..6fd044b 100644 --- a/src/BeSimple/SoapCommon/WsdlHandler.php +++ b/src/BeSimple/SoapCommon/WsdlHandler.php @@ -87,6 +87,7 @@ class WsdlHandler * 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) @@ -152,6 +153,7 @@ class WsdlHandler * @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) diff --git a/tests/BeSimple/Tests/SoapCommon/Mime/ParserTest.php b/tests/BeSimple/Tests/SoapCommon/Mime/ParserTest.php index 8efa1f9..1128325 100644 --- a/tests/BeSimple/Tests/SoapCommon/Mime/ParserTest.php +++ b/tests/BeSimple/Tests/SoapCommon/Mime/ParserTest.php @@ -52,7 +52,7 @@ class ParserTest extends \PHPUnit_Framework_TestCase $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(81, strlen($p2->getContent())); + $this->assertEquals(79, strlen($p2->getContent())); } public function testParserResponseAxis() diff --git a/tests/bootstrap.php b/tests/bootstrap.php index f2d913c..67150ad 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -19,7 +19,7 @@ spl_autoload_register(function($class) { return true; } } 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)) { require_once $path;