Soap server with attachments refactoring
This commit is contained in:
@ -16,6 +16,7 @@ use BeSimple\SoapCommon\Helper;
|
||||
use BeSimple\SoapCommon\Mime\MultiPart as MimeMultiPart;
|
||||
use BeSimple\SoapCommon\Mime\Parser as MimeParser;
|
||||
use BeSimple\SoapCommon\Mime\Part as MimePart;
|
||||
use BeSimple\SoapCommon\Mime\Part;
|
||||
use BeSimple\SoapCommon\SoapRequest;
|
||||
use BeSimple\SoapCommon\SoapRequestFilter;
|
||||
use BeSimple\SoapCommon\SoapResponse;
|
||||
@ -30,32 +31,17 @@ class MimeFilter implements SoapRequestFilter, SoapResponseFilter
|
||||
{
|
||||
public function filterRequest(SoapRequest $request, $attachmentType)
|
||||
{
|
||||
$attachmentsReceived = [];
|
||||
$multiPartMessage = MimeParser::parseMimeMessage(
|
||||
$request->getContent(),
|
||||
['Content-Type' => trim($request->getContentType())]
|
||||
);
|
||||
$soapPart = $multiPartMessage->getMainPart();
|
||||
$attachments = $multiPartMessage->getAttachments();
|
||||
|
||||
// check content type if it is a multipart mime message
|
||||
$requestContentType = $request->getContentType();
|
||||
if (stripos($requestContentType, 'multipart/related') !== false) {
|
||||
// parse mime message
|
||||
$headers = [
|
||||
'Content-Type' => trim($requestContentType),
|
||||
];
|
||||
$multipart = MimeParser::parseMimeMessage($request->getContent(), $headers);
|
||||
// get soap payload and update SoapResponse object
|
||||
$soapPart = $multipart->getPart();
|
||||
// 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
|
||||
$content = preg_replace('/href=(?!#)/', 'myhref=', $soapPart->getContent());
|
||||
$request->setContent($content);
|
||||
$request->setContentType($soapPart->getHeader('Content-Type'));
|
||||
// store attachments
|
||||
$attachments = $multipart->getParts(false);
|
||||
foreach ($attachments as $cid => $attachment) {
|
||||
$attachmentsReceived[$cid] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($attachmentsReceived) > 0) {
|
||||
$request->setAttachments($attachmentsReceived);
|
||||
$request->setContent($this->sanitizePhpExceptionOnHrefs($soapPart));
|
||||
$request->setContentType($soapPart->getHeader('Content-Type'));
|
||||
if (count($attachments) > 0) {
|
||||
$request->setAttachments($attachments);
|
||||
}
|
||||
|
||||
return $request;
|
||||
@ -65,28 +51,26 @@ class MimeFilter implements SoapRequestFilter, SoapResponseFilter
|
||||
{
|
||||
$attachmentsToSend = $response->getAttachments();
|
||||
if (count($attachmentsToSend) > 0) {
|
||||
$multipart = new MimeMultiPart();
|
||||
$multipart = new MimeMultiPart('Part_' . rand(10, 15) . '_' . uniqid() . '.' . uniqid());
|
||||
$soapPart = new MimePart($response->getContent(), 'text/xml', 'utf-8', MimePart::ENCODING_EIGHT_BIT);
|
||||
$soapVersion = $response->getVersion();
|
||||
// change content type headers for MTOM with SOAP 1.1
|
||||
if ($soapVersion == SOAP_1_1 && $attachmentType & Helper::ATTACHMENTS_TYPE_MTOM) {
|
||||
|
||||
if ($soapVersion === SOAP_1_1 && $attachmentType === Helper::ATTACHMENTS_TYPE_MTOM) {
|
||||
$multipart->setHeader('Content-Type', 'type', 'application/xop+xml');
|
||||
$multipart->setHeader('Content-Type', 'start-info', 'text/xml');
|
||||
$soapPart->setHeader('Content-Type', 'application/xop+xml');
|
||||
$soapPart->setHeader('Content-Type', 'type', 'text/xml');
|
||||
}
|
||||
// change content type headers for SOAP 1.2
|
||||
elseif ($soapVersion == SOAP_1_2) {
|
||||
} elseif ($soapVersion === SOAP_1_2) {
|
||||
$multipart->setHeader('Content-Type', 'type', 'application/soap+xml');
|
||||
$soapPart->setHeader('Content-Type', 'application/soap+xml');
|
||||
}
|
||||
|
||||
$multipart->addPart($soapPart, true);
|
||||
foreach ($attachmentsToSend as $cid => $attachment) {
|
||||
$multipart->addPart($attachment, false);
|
||||
}
|
||||
$response->setContent($multipart->getMimeMessage());
|
||||
|
||||
// TODO
|
||||
$headers = $multipart->getHeadersForHttp();
|
||||
list(, $contentType) = explode(': ', $headers[0]);
|
||||
|
||||
@ -95,4 +79,11 @@ class MimeFilter implements SoapRequestFilter, SoapResponseFilter
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function sanitizePhpExceptionOnHrefs(Part $soapPart)
|
||||
{
|
||||
// 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
|
||||
return preg_replace('/href=(?!#)/', 'myhref=', $soapPart->getContent());
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace BeSimple\SoapServer\SoapOptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SoapServerOptions
|
||||
{
|
||||
const SOAP_SERVER_PERSISTENCE_NONE = 0;
|
||||
@ -43,6 +45,22 @@ class SoapServerOptions
|
||||
$this->persistence = $persistence;
|
||||
}
|
||||
|
||||
public function getHandler()
|
||||
{
|
||||
if ($this->hasHandlerObject()) {
|
||||
|
||||
return $this->getHandlerObject();
|
||||
|
||||
} else if ($this->hasHandlerClass()) {
|
||||
|
||||
return $this->getHandlerClass();
|
||||
|
||||
} else {
|
||||
|
||||
throw new Exception('No HandlerClass or HandlerObject set');
|
||||
}
|
||||
}
|
||||
|
||||
public function hasHandlerClass()
|
||||
{
|
||||
return $this->handlerClass !== null;
|
||||
|
@ -8,9 +8,6 @@ class SoapResponse extends CommonSoapResponse
|
||||
{
|
||||
public function getResponseContent()
|
||||
{
|
||||
// set Content-Type header
|
||||
header('Content-Type: ' . $this->getContentType());
|
||||
|
||||
return $this->getContent();
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
namespace BeSimple\SoapServer;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapCommon\Mime\Part;
|
||||
use BeSimple\SoapCommon\SoapMessage;
|
||||
|
||||
class SoapResponseFactory
|
||||
@ -23,7 +25,7 @@ class SoapResponseFactory
|
||||
* @param string $location Location
|
||||
* @param string $action SOAP action
|
||||
* @param string $version SOAP version
|
||||
* @param array $attachments SOAP attachments
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
*
|
||||
* @return SoapResponse
|
||||
*/
|
||||
@ -37,6 +39,33 @@ class SoapResponseFactory
|
||||
$contentType = SoapMessage::getContentTypeForVersion($version);
|
||||
$response->setContentType($contentType);
|
||||
|
||||
if (count($attachments) > 0) {
|
||||
$response->setAttachments(
|
||||
self::createAttachmentParts($attachments)
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SoapAttachment[] $attachments SOAP attachments
|
||||
* @return Part[]
|
||||
*/
|
||||
private function createAttachmentParts(array $attachments = [])
|
||||
{
|
||||
$parts = [];
|
||||
foreach ($attachments as $attachment) {
|
||||
$part = new Part(
|
||||
$attachment->getContent(),
|
||||
'application/pdf',
|
||||
'utf-8',
|
||||
Part::ENCODING_BINARY,
|
||||
$attachment->getId()
|
||||
);
|
||||
$parts[] = $part;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,13 @@
|
||||
|
||||
namespace BeSimple\SoapServer;
|
||||
|
||||
use BeSimple\SoapBundle\Soap\SoapAttachment;
|
||||
use BeSimple\SoapCommon\AttachmentsHandler;
|
||||
use BeSimple\SoapCommon\SoapKernel;
|
||||
use BeSimple\SoapCommon\SoapOptions\SoapOptions;
|
||||
use BeSimple\SoapCommon\SoapRequest;
|
||||
use BeSimple\SoapCommon\SoapRequestFactory;
|
||||
use BeSimple\SoapCommon\Storage\RequestHandlerAttachmentsStorage;
|
||||
use BeSimple\SoapServer\SoapOptions\SoapServerOptions;
|
||||
use BeSimple\SoapCommon\Converter\MtomTypeConverter;
|
||||
use BeSimple\SoapCommon\Converter\SwaTypeConverter;
|
||||
@ -44,9 +47,6 @@ class SoapServer extends \SoapServer
|
||||
*/
|
||||
public function __construct(SoapServerOptions $soapServerOptions, SoapOptions $soapOptions)
|
||||
{
|
||||
if ($soapOptions->hasAttachments()) {
|
||||
$soapOptions = $this->configureTypeConverters($soapOptions);
|
||||
}
|
||||
$this->soapVersion = $soapOptions->getSoapVersion();
|
||||
$this->soapServerOptions = $soapServerOptions;
|
||||
$this->soapOptions = $soapOptions;
|
||||
@ -60,6 +60,7 @@ class SoapServer extends \SoapServer
|
||||
/**
|
||||
* Custom handle method to be able to modify the SOAP messages.
|
||||
*
|
||||
* @deprecated Please, use createRequest + handleRequest methods
|
||||
* @param string $requestUrl
|
||||
* @param string $soapAction
|
||||
* @param string $requestContent = null
|
||||
@ -67,15 +68,9 @@ class SoapServer extends \SoapServer
|
||||
*/
|
||||
public function handle($requestUrl, $soapAction, $requestContent = null)
|
||||
{
|
||||
try {
|
||||
|
||||
return $this->getSoapResponse($requestUrl, $soapAction, $requestContent)->getResponseContent();
|
||||
|
||||
} catch (\SoapFault $fault) {
|
||||
$this->fault($fault->faultcode, $fault->faultstring);
|
||||
|
||||
return self::SOAP_SERVER_REQUEST_FAILED;
|
||||
}
|
||||
return $this->handleRequest(
|
||||
$this->createRequest($requestUrl, $soapAction, $requestContent)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,20 +78,42 @@ class SoapServer extends \SoapServer
|
||||
*
|
||||
* @param string $requestUrl
|
||||
* @param string $soapAction
|
||||
* @param string $requestContentType
|
||||
* @param string $requestContent = null
|
||||
* @return SoapResponse
|
||||
* @return SoapRequest
|
||||
*/
|
||||
public function getSoapResponse($requestUrl, $soapAction, $requestContent = null)
|
||||
public function createRequest($requestUrl, $soapAction, $requestContentType, $requestContent = null)
|
||||
{
|
||||
$soapRequest = SoapRequestFactory::create(
|
||||
$requestUrl,
|
||||
$soapAction,
|
||||
$this->soapVersion,
|
||||
$requestContentType,
|
||||
$requestContent
|
||||
);
|
||||
$soapResponse = $this->handleSoapRequest($soapRequest);
|
||||
$soapKernel = new SoapKernel();
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapRequest = $soapKernel->filterRequest(
|
||||
$soapRequest,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
);
|
||||
}
|
||||
|
||||
return $soapResponse;
|
||||
return $soapRequest;
|
||||
}
|
||||
|
||||
public function handleRequest(SoapRequest $soapRequest)
|
||||
{
|
||||
try {
|
||||
|
||||
return $this->handleSoapRequest($soapRequest);
|
||||
|
||||
} catch (\SoapFault $fault) {
|
||||
$this->fault($fault->faultcode, $fault->faultstring);
|
||||
|
||||
return self::SOAP_SERVER_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,33 +127,87 @@ class SoapServer extends \SoapServer
|
||||
*/
|
||||
private function handleSoapRequest(SoapRequest $soapRequest)
|
||||
{
|
||||
$soapKernel = new SoapKernel();
|
||||
/** @var AttachmentsHandler $handler */
|
||||
$handler = $this->soapServerOptions->getHandler();
|
||||
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapRequest = $soapKernel->filterRequest($soapRequest, $this->getFilters(), $this->soapOptions->getAttachmentType());
|
||||
$this->injectAttachmentStorage($handler, $soapRequest, $this->soapOptions->getAttachmentType());
|
||||
}
|
||||
|
||||
ob_start();
|
||||
parent::handle($soapRequest->getContent());
|
||||
$response = ob_get_clean();
|
||||
$nativeSoapServerResponse = ob_get_clean();
|
||||
|
||||
$attachments = [];
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$attachments = $handler->getAttachmentsFromStorage();
|
||||
}
|
||||
|
||||
// Remove headers added by SoapServer::handle() method
|
||||
header_remove('Content-Length');
|
||||
header_remove('Content-Type');
|
||||
|
||||
$soapResponse = SoapResponseFactory::create(
|
||||
$response,
|
||||
return $this->createResponse(
|
||||
$soapRequest->getLocation(),
|
||||
$soapRequest->getAction(),
|
||||
$soapRequest->getVersion()
|
||||
$soapRequest->getVersion(),
|
||||
$nativeSoapServerResponse,
|
||||
$attachments
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $requestLocation
|
||||
* @param string $soapAction
|
||||
* @param string $soapVersion
|
||||
* @param string|null $responseContent
|
||||
* @param SoapAttachment[] $attachments
|
||||
* @return SoapResponse
|
||||
*/
|
||||
private function createResponse($requestLocation, $soapAction, $soapVersion, $responseContent = null, $attachments = [])
|
||||
{
|
||||
$soapResponse = SoapResponseFactory::create(
|
||||
$responseContent,
|
||||
$requestLocation,
|
||||
$soapAction,
|
||||
$soapVersion,
|
||||
$attachments
|
||||
);
|
||||
$soapKernel = new SoapKernel();
|
||||
if ($this->soapOptions->hasAttachments()) {
|
||||
$soapResponse = $soapKernel->filterResponse($soapResponse, $this->getFilters(), $this->soapOptions->getAttachmentType());
|
||||
$soapResponse = $soapKernel->filterResponse(
|
||||
$soapResponse,
|
||||
$this->getAttachmentFilters(),
|
||||
$this->soapOptions->getAttachmentType()
|
||||
);
|
||||
}
|
||||
|
||||
return $soapResponse;
|
||||
}
|
||||
|
||||
private function injectAttachmentStorage(AttachmentsHandler $handler, SoapRequest $soapRequest, $attachmentType)
|
||||
{
|
||||
$attachments = [];
|
||||
if ($soapRequest->hasAttachments()) {
|
||||
foreach ($soapRequest->getAttachments() as $attachment) {
|
||||
$attachments[] = new SoapAttachment(
|
||||
$attachment->getHeader('Content-Disposition', 'filename'),
|
||||
$attachmentType,
|
||||
$attachment->getContent()
|
||||
);
|
||||
}
|
||||
}
|
||||
$handler->addAttachmentStorage(new RequestHandlerAttachmentsStorage($attachments));
|
||||
}
|
||||
|
||||
/**
|
||||
* Legacy code: TypeConverters should be resolved in SoapServer::__construct()
|
||||
* To be removed if all tests pass
|
||||
*
|
||||
* @deprecated
|
||||
* @param SoapOptions $soapOptions
|
||||
* @return SoapOptions
|
||||
*/
|
||||
private function configureTypeConverters(SoapOptions $soapOptions)
|
||||
{
|
||||
if ($soapOptions->getAttachmentType() !== SoapOptions::SOAP_ATTACHMENTS_TYPE_BASE64) {
|
||||
@ -152,7 +223,7 @@ class SoapServer extends \SoapServer
|
||||
return $soapOptions;
|
||||
}
|
||||
|
||||
private function getFilters()
|
||||
private function getAttachmentFilters()
|
||||
{
|
||||
$filters = [];
|
||||
if ($this->soapOptions->getAttachmentType() !== SoapOptions::SOAP_ATTACHMENTS_TYPE_BASE64) {
|
||||
|
@ -31,7 +31,7 @@ class XmlMimeFilter implements SoapResponseFilter
|
||||
{
|
||||
}
|
||||
|
||||
public function filterResponse(SoapResponse $response)
|
||||
public function filterResponse(SoapResponse $response, $attachmentType)
|
||||
{
|
||||
$dom = $response->getContentDocument();
|
||||
|
||||
|
Reference in New Issue
Block a user