-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathMTOMSoapClient.php
116 lines (98 loc) · 3.73 KB
/
MTOMSoapClient.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
/**
* This file is part of the KeepItSimple package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @package KeepItSimple\Http\Soap
* @author Alexandre Debusschere (debuss-a)
* @copyright Copyright (c) Alexandre Debusschere <[email protected]>
* @licence MIT
*/
namespace KeepItSimple\Http\Soap;
use DOMDocument;
use SoapClient;
use Exception;
/**
* Class MTOMSoapClient
*
* This class overrides SoapClient::__doRequest() method to implement MTOM for PHP.
* It decodes XML and integrate attachments in the XML response.
*
* @author Alexandre D. <debuss-a>
* @version 1.0.0
*/
class MTOMSoapClient extends SoapClient
{
/**
* It replaces the :
* <xop:Include href="cid:[email protected]" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
* By the binary code contained in attachment
* Content-ID: <[email protected]>
*
* Note that the binary is converted to base64 with base64_encode().
*
* @param string|null $response
* @return string|null The XML SOAP response with <xop> tag replaced by base64 corresponding attachment
* @throws Exception
*/
protected function process(?string $response): ?string
{
if (!$response) {
return null;
}
// Catch XML response
$xml_response = null;
preg_match('/<soap[\s\S]*nvelope>/i', $response, $xml_response);
if (!is_array($xml_response) || !count($xml_response)) {
throw new Exception('No XML has been found.');
}
$xml_response = reset($xml_response);
try {
$dom = new DOMDocument();
$dom->loadXML($xml_response);
$xop_elements = $dom->getElementsByTagNameNS('http://www.w3.org/2004/08/xop/include', 'Include');
$counts = $xop_elements->count() - 1;
// You can modify, and even delete, nodes from a DOMNodeList if you iterate backwards
// https://www.php.net/manual/en/class.domnodelist.php#83390
for ($i = $counts; $i >= 0; $i -= 1) {
$xop_element = $xop_elements->item($i);
$cid = $xop_element->getAttribute('href');
$cid = str_replace('cid:', '', $cid);
// Find binary
$content_id_tag = 'Content-ID: <'.$cid.'>';
$start = strpos($response, $content_id_tag) + strlen($content_id_tag);
$end = strpos($response, '--uuid:', $start);
$binary = substr($response, $start, $end - $start);
$binary = trim($binary);
$binary = base64_encode($binary);
$xop_element->parentNode->nodeValue = $binary;
}
// Save modified XML string
$xml_response = $dom->saveXML();
} catch (Exception $exception) {
throw new Exception(sprintf(
'An error occurred while processing the XML response: %s.',
$exception->getMessage()
));
}
return $xml_response;
}
/**
* Override SoapClient to add MTOM decoding on responses.
*
* @link http://php.net/manual/en/soapclient.dorequest.php
* @param string $request
* @param string $location
* @param string $action
* @param int $version
* @param int $one_way
* @return string|null
* @throws Exception
*/
public function __doRequest($request, $location, $action, $version, $one_way = 0): ?string
{
$response = parent::__doRequest($request, $location, $action, $version, $one_way);
return $this->process($response);
}
}