Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - extending SoapClient to handle SWA (SOAP with Attachment)

Tags:

php

soap

I'm attempting to handle SWA responses from a Java SOAP service. In that SWA response is a binary attachment(s) appended to the end of the XML along with some MIME headers. I cannot use WSO2 for dependency requirement limitations.

Any help would be much appreciated!

// Input

------=_Part_42_539586119.1332526191981
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <03B4708A9544C182C43E51D9ADA1E456>

<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body> ... TRUNCATED XML SOAP RESPONSE ... </soapenv:Body></soapenv:Envelope>

------=_Part_42_539586119.1332526191981
Content-Type: image/png
Content-Transfer-Encoding: binary
Content-Id: <D637B1257E3E5EEA06AF0E45494F8448>

BINARY DATA GOES HERE


// End of input

// Script to split the response + return StdObj's like the parent class SoapClient + do something with the files

namespace Project;
class SoapClient extends \SoapClient
{
    public function __call ($function_name, $arguments)
    {
        // have the parent do a soap call, catch the lastResponse() if an error
        // occurred (eg has an attachment) and parse it out.
        try {
            $r = parent::__call($function_name, $arguments);
            return $r;
        } catch (\Exception $e) {
            // Assumption: When this is sent, it means that a file is being sent
            // because SimpleXML can't process it.
            if ($e->getMessage() == "looks like we got no XML document") {
                $response = parent::__getLastResponse();
                $partString = "/(------=_[a-zA-Z0-9_\\.]+)/";
                $outputArr = preg_split($partString, $response);
                // $outputAtt[0] -- empty and is the first MIME Part Header
                // $outputArr[1] -- Mime Header + XML (The SOAP Response)
                // $outputArr[n+1] -- additional files w/ MIME headers
                if (array_key_exists(1, $outputArr)) {
                    // remove the first 5 lines (4 MIME Header lines) + 1 Blank
                    // line
                    $data = implode("\n",
                    array_slice(explode("\n", $outputArr[1]), 5));

                    /// Simple XML Object ... appears to be an empty SimpleXMLElement though ... >:-(
                    $xml = simplexml_load_string($data, null, null, "http://schemas.xmlsoap.org/soap/envelope/");




                } else {
                    // OK Maybe this doesn't actually contain the XML... throw
                    // the original exception.
                    throw new \SoapFault($e->getMessage(), $e->getCode(),
                    $e->getPrevious());
                }
            } else {
                throw new \SoapFault($e->getMessage(), $e->getCode(),
                $e->getPrevious());
            }
        }
    }
}
like image 301
JPeterson Avatar asked Oct 08 '22 07:10

JPeterson


1 Answers

Use a MIME parser for this. It's pretty simple from there:

require_once('MimeMailParser.class.php');

class SwADownloadSoapClient extends SoapClient
{
    const ATTACHMENT_DIR = '/path/to/saved/attachments/';

    public function __doRequest(
        $request, $location, $action, $version, $one_way=0
    ) {
        // Issue the SOAP request as SoapClient would normall
        $sResult = parent::__doRequest(
                               $request, $location, $action, $version, $one_way);

        // Handle and parse MIME-encoded messages
        // @note We're not doing much inspection
        //       of the XML payload against the attachments ATM
        //       so not sure how greatly this lives up to the spec
        $sResult = $this->_parseMimeMessage($sResult);

        $oParser = new MimeMailParser();
        $oParser->setText($sResult);

        // Save the attachments
        $aAttachments = $oParser->getAttachments();
        foreach($aAttachments as $oAttachment) {
            $sFile = $oAttachment->filename;
            if($rFp = fopen(self::ATTACHMENT_DIR . $sFile, 'w')) {
                while($sBytes = $attachment->read())
                    fwrite($rFp, $sBytes);
                fclose($rFp);
            }
        }
    }
}

If you want to more properly implement the spec, you'll need to match up the MIME attachments against the SOAP XML.

like image 96
quickshiftin Avatar answered Oct 12 '22 10:10

quickshiftin