├── .gitignore ├── CONTRIBUTORS.md ├── Curl.php ├── MimeFilter.php ├── README.md ├── SoapClient.php ├── SoapClientBuilder.php ├── SoapKernel.php ├── SoapRequest.php ├── SoapResponse.php ├── Tests ├── AbstractWebserverTest.php ├── AxisInterop │ ├── Fixtures │ │ ├── AttachmentRequest.php │ │ ├── AttachmentType.php │ │ ├── BookInformation.php │ │ ├── MTOM.wsdl │ │ ├── SwA.wsdl │ │ ├── WsSecuritySigEnc.wsdl │ │ ├── WsSecurityUserPass.wsdl │ │ ├── addBook.php │ │ ├── addBookResponse.php │ │ ├── base64Binary.php │ │ ├── clientcert.pem │ │ ├── clientkey.pem │ │ ├── downloadFile.php │ │ ├── downloadFileResponse.php │ │ ├── getBook.php │ │ ├── getBookResponse.php │ │ ├── getBooksByType.php │ │ ├── getBooksByTypeResponse.php │ │ ├── image.jpg │ │ ├── servercert.pem │ │ ├── uploadFile.php │ │ └── uploadFileResponse.php │ ├── MtomAxisInteropTest.php │ ├── SwA │ │ ├── build.xml │ │ ├── resources │ │ │ └── META-INF │ │ │ │ └── services.xml │ │ └── src │ │ │ └── besimple │ │ │ └── service │ │ │ └── BeSimpleSwaService.java │ ├── SwaAxisInteropTest.php │ ├── TestCase.php │ ├── WsAddressingAxisInteropTest.php │ ├── WsSecuritySigEncAxisInteropTest.php │ ├── WsSecurityUserPassAxisInteropTest.php │ └── axis_services │ │ ├── besimple-swa.aar │ │ ├── library-signencr.aar │ │ ├── library-username-digest.aar │ │ ├── sample-mtom.aar │ │ └── version2.aar ├── CurlTest.php ├── Fixtures │ ├── curl.txt │ ├── foobar.wsdl │ ├── type_include.xsd │ ├── wsdl_include.wsdl │ ├── wsdlinclude │ │ ├── wsdlinctest_absolute.xml │ │ └── wsdlinctest_relative.xml │ └── xsdinclude │ │ ├── xsdinctest_absolute.xml │ │ └── xsdinctest_relative.xml ├── ServerInterop │ ├── Fixtures │ │ ├── AttachmentRequest.php │ │ ├── AttachmentType.php │ │ ├── BookInformation.php │ │ ├── MTOM.wsdl │ │ ├── SwA.wsdl │ │ ├── WsSecuritySigEnc.wsdl │ │ ├── WsSecurityUserPass.wsdl │ │ ├── addBook.php │ │ ├── addBookResponse.php │ │ ├── base64Binary.php │ │ ├── clientcert.pem │ │ ├── clientkey.pem │ │ ├── downloadFile.php │ │ ├── downloadFileResponse.php │ │ ├── getBook.php │ │ ├── getBookResponse.php │ │ ├── getBooksByType.php │ │ ├── getBooksByTypeResponse.php │ │ ├── image.jpg │ │ ├── servercert.pem │ │ ├── serverkey.pem │ │ ├── uploadFile.php │ │ └── uploadFileResponse.php │ ├── MTOMClient.php │ ├── MTOMServer.php │ ├── MtomServerInteropTest.php │ ├── SwAServer.php │ ├── SwaClient.php │ ├── SwaServerInteropTest.php │ ├── TestCase.php │ ├── WsSecuritySigEncServer.php │ ├── WsSecuritySigEncServerClient.php │ ├── WsSecuritySigEncServerInteropTest.php │ ├── WsSecurityUserPassServer.php │ ├── WsSecurityUserPassServerClient.php │ └── WsSecurityUserPassServerInteropTest.php ├── SoapClientBuilderTest.php ├── WsdlDownloaderTest.php └── bin │ ├── axis.sh │ └── phpwebserver.sh ├── WsAddressingFilter.php ├── WsSecurityFilter.php ├── WsdlDownloader.php ├── XmlMimeFilter.php ├── composer.json └── phpunit.xml.dist /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | composer.lock 3 | phpunit.xml 4 | Tests/Fixtures/build_include/ 5 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | * [Francis Besset](https://github.com/francisbesset) 2 | * [aschamberger](https://github.com/aschamberger) 3 | * [Scheb](https://github.com/Scheb) 4 | -------------------------------------------------------------------------------- /Curl.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | /** 16 | * cURL wrapper class for doing HTTP requests that uses the soap class options. 17 | * 18 | * @author Andreas Schamberger 19 | */ 20 | class Curl 21 | { 22 | /** 23 | * HTTP User Agent. 24 | * 25 | * @var string 26 | */ 27 | const USER_AGENT = 'PHP-SOAP/\BeSimple\SoapClient'; 28 | 29 | /** 30 | * Curl resource. 31 | * 32 | * @var resource 33 | */ 34 | private $ch; 35 | 36 | /** 37 | * Maximum number of location headers to follow. 38 | * 39 | * @var int 40 | */ 41 | private $followLocationMaxRedirects; 42 | 43 | /** 44 | * Request response data. 45 | * 46 | * @var string 47 | */ 48 | private $response; 49 | 50 | /** 51 | * Constructor. 52 | * 53 | * @param array $options Options array from SoapClient constructor 54 | * @param int $followLocationMaxRedirects Redirection limit for Location header 55 | */ 56 | public function __construct(array $options = array(), $followLocationMaxRedirects = 10) 57 | { 58 | // set the default HTTP user agent 59 | if (!isset($options['user_agent'])) { 60 | $options['user_agent'] = self::USER_AGENT; 61 | } 62 | $this->followLocationMaxRedirects = $followLocationMaxRedirects; 63 | 64 | // make http request 65 | $this->ch = curl_init(); 66 | $curlOptions = array( 67 | CURLOPT_ENCODING => '', 68 | CURLOPT_SSL_VERIFYPEER => false, 69 | CURLOPT_FAILONERROR => false, 70 | CURLOPT_RETURNTRANSFER => true, 71 | CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, 72 | CURLOPT_HEADER => true, 73 | CURLOPT_USERAGENT => $options['user_agent'], 74 | CURLINFO_HEADER_OUT => true, 75 | ); 76 | curl_setopt_array($this->ch, $curlOptions); 77 | if (isset($options['compression']) && !($options['compression'] & SOAP_COMPRESSION_ACCEPT)) { 78 | curl_setopt($this->ch, CURLOPT_ENCODING, 'identity'); 79 | } 80 | if (isset($options['connection_timeout'])) { 81 | curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, $options['connection_timeout']); 82 | } 83 | 84 | if (isset($options['proxy_host'])) { 85 | if (false !== $options['proxy_host']) { 86 | $proxyHost = $options['proxy_host'].(isset($options['proxy_port']) ? $options['proxy_port'] : 8080); 87 | } else { 88 | $proxyHost = false; 89 | } 90 | 91 | curl_setopt($this->ch, CURLOPT_PROXY, $proxyHost); 92 | 93 | if (false !== $proxyHost && isset($options['proxy_login'])) { 94 | curl_setopt($this->ch, CURLOPT_PROXYUSERPWD, $options['proxy_login'].':'.$options['proxy_password']); 95 | 96 | if (isset($options['proxy_auth'])) { 97 | curl_setopt($this->ch, CURLOPT_PROXYAUTH, $options['proxy_auth']); 98 | } 99 | } 100 | } 101 | 102 | if (isset($options['login'])) { 103 | curl_setopt($this->ch, CURLOPT_HTTPAUTH, isset($options['extra_options']['http_auth']) ? $options['extra_options']['http_auth'] : CURLAUTH_ANY); 104 | curl_setopt($this->ch, CURLOPT_USERPWD, $options['login'].':'.$options['password']); 105 | } 106 | if (isset($options['local_cert'])) { 107 | curl_setopt($this->ch, CURLOPT_SSLCERT, $options['local_cert']); 108 | curl_setopt($this->ch, CURLOPT_SSLCERTPASSWD, $options['passphrase']); 109 | } 110 | if (isset($options['ca_info'])) { 111 | curl_setopt($this->ch, CURLOPT_CAINFO, $options['ca_info']); 112 | } 113 | if (isset($options['ca_path'])) { 114 | curl_setopt($this->ch, CURLOPT_CAPATH, $options['ca_path']); 115 | } 116 | } 117 | 118 | /** 119 | * Destructor. 120 | */ 121 | public function __destruct() 122 | { 123 | curl_close($this->ch); 124 | } 125 | 126 | /** 127 | * Execute HTTP request. 128 | * Returns true if request was successfull. 129 | * 130 | * @param string $location HTTP location 131 | * @param string $request Request body 132 | * @param array $requestHeaders Request header strings 133 | * @param array $requestOptions An array of request options 134 | * 135 | * @return bool 136 | */ 137 | public function exec($location, $request = null, $requestHeaders = array(), $requestOptions = array()) 138 | { 139 | curl_setopt($this->ch, CURLOPT_URL, $location); 140 | 141 | if (!is_null($request)) { 142 | curl_setopt($this->ch, CURLOPT_POST, true); 143 | curl_setopt($this->ch, CURLOPT_POSTFIELDS, $request); 144 | } 145 | 146 | if (count($requestHeaders) > 0) { 147 | curl_setopt($this->ch, CURLOPT_HTTPHEADER, $requestHeaders); 148 | } 149 | 150 | if (count($requestOptions) > 0) { 151 | curl_setopt_array($this->ch, $requestOptions); 152 | } 153 | 154 | $this->response = $this->execManualRedirect(); 155 | 156 | return ($this->response === false) ? false : true; 157 | } 158 | 159 | /** 160 | * Custom curl_exec wrapper that allows to follow redirects when specific 161 | * http response code is set. SOAP only allows 307. 162 | * 163 | * @param int $redirects Current redirection count 164 | * 165 | * @return mixed 166 | */ 167 | private function execManualRedirect($redirects = 0) 168 | { 169 | if ($redirects > $this->followLocationMaxRedirects) { 170 | 171 | // TODO Redirection limit reached, aborting 172 | return false; 173 | } 174 | curl_setopt($this->ch, CURLOPT_HEADER, true); 175 | curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); 176 | $response = curl_exec($this->ch); 177 | $httpResponseCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE); 178 | if ($httpResponseCode == 307) { 179 | $headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE); 180 | $header = substr($response, 0, $headerSize); 181 | $matches = array(); 182 | preg_match('/Location:(.*?)\n/', $header, $matches); 183 | $url = trim(array_pop($matches)); 184 | // @parse_url to suppress E_WARNING for invalid urls 185 | if (($url = @parse_url($url)) !== false) { 186 | $lastUrl = parse_url(curl_getinfo($this->ch, CURLINFO_EFFECTIVE_URL)); 187 | if (!isset($url['scheme'])) { 188 | $url['scheme'] = $lastUrl['scheme']; 189 | } 190 | if (!isset($url['host'])) { 191 | $url['host'] = $lastUrl['host']; 192 | } 193 | if (!isset($url['path'])) { 194 | $url['path'] = $lastUrl['path']; 195 | } 196 | $newUrl = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query'] ? '?' . $url['query'] : ''); 197 | curl_setopt($this->ch, CURLOPT_URL, $newUrl); 198 | 199 | return $this->execManualRedirect($redirects++); 200 | } 201 | } 202 | 203 | return $response; 204 | } 205 | 206 | /** 207 | * Error code mapping from cURL error codes to PHP ext/soap error messages 208 | * (where applicable) 209 | * 210 | * http://curl.haxx.se/libcurl/c/libcurl-errors.html 211 | * 212 | * @return array(int=>string) 213 | */ 214 | protected function getErrorCodeMapping() 215 | { 216 | return array( 217 | 1 => 'Unknown protocol. Only http and https are allowed.', //CURLE_UNSUPPORTED_PROTOCOL 218 | 3 => 'Unable to parse URL', //CURLE_URL_MALFORMAT 219 | 5 => 'Could not connect to host', //CURLE_COULDNT_RESOLVE_PROXY 220 | 6 => 'Could not connect to host', //CURLE_COULDNT_RESOLVE_HOST 221 | 7 => 'Could not connect to host', //CURLE_COULDNT_CONNECT 222 | 9 => 'Could not connect to host', //CURLE_REMOTE_ACCESS_DENIED 223 | 28 => 'Failed Sending HTTP SOAP request', //CURLE_OPERATION_TIMEDOUT 224 | 35 => 'Could not connect to host', //CURLE_SSL_CONNECT_ERROR 225 | 41 => 'Can\'t uncompress compressed response', //CURLE_FUNCTION_NOT_FOUND 226 | 51 => 'Could not connect to host', //CURLE_PEER_FAILED_VERIFICATION 227 | 52 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_GOT_NOTHING 228 | 53 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_NOTFOUND 229 | 54 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_SETFAILED 230 | 55 => 'Failed Sending HTTP SOAP request', //CURLE_SEND_ERROR 231 | 56 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_RECV_ERROR 232 | 58 => 'Could not connect to host', //CURLE_SSL_CERTPROBLEM 233 | 59 => 'Could not connect to host', //CURLE_SSL_CIPHER 234 | 60 => 'Could not connect to host', //CURLE_SSL_CACERT 235 | 61 => 'Unknown Content-Encoding', //CURLE_BAD_CONTENT_ENCODING 236 | 65 => 'Failed Sending HTTP SOAP request', //CURLE_SEND_FAIL_REWIND 237 | 66 => 'SSL support is not available in this build', //CURLE_SSL_ENGINE_INITFAILED 238 | 67 => 'Could not connect to host', //CURLE_LOGIN_DENIED 239 | 77 => 'Could not connect to host', //CURLE_SSL_CACERT_BADFILE 240 | 80 => 'Error Fetching http body, No Content-Length, connection closed or chunked data', //CURLE_SSL_SHUTDOWN_FAILED 241 | ); 242 | } 243 | 244 | /** 245 | * Gets the curl error message. 246 | * 247 | * @return string 248 | */ 249 | public function getErrorMessage() 250 | { 251 | $errorCodeMapping = $this->getErrorCodeMapping(); 252 | $errorNumber = curl_errno($this->ch); 253 | if (isset($errorCodeMapping[$errorNumber])) { 254 | 255 | return $errorCodeMapping[$errorNumber]; 256 | } 257 | 258 | return curl_error($this->ch); 259 | } 260 | 261 | /** 262 | * Gets the request headers as a string. 263 | * 264 | * @return string 265 | */ 266 | public function getRequestHeaders() 267 | { 268 | return curl_getinfo($this->ch, CURLINFO_HEADER_OUT); 269 | } 270 | 271 | /** 272 | * Gets the whole response (including headers) as a string. 273 | * 274 | * @return string 275 | */ 276 | public function getResponse() 277 | { 278 | return $this->response; 279 | } 280 | 281 | /** 282 | * Gets the response body as a string. 283 | * 284 | * @return string 285 | */ 286 | public function getResponseBody() 287 | { 288 | $headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE); 289 | 290 | return substr($this->response, $headerSize); 291 | } 292 | 293 | /** 294 | * Gets the response content type. 295 | * 296 | * @return string 297 | */ 298 | public function getResponseContentType() 299 | { 300 | return curl_getinfo($this->ch, CURLINFO_CONTENT_TYPE); 301 | } 302 | 303 | /** 304 | * Gets the response headers as a string. 305 | * 306 | * @return string 307 | */ 308 | public function getResponseHeaders() 309 | { 310 | $headerSize = curl_getinfo($this->ch, CURLINFO_HEADER_SIZE); 311 | 312 | return substr($this->response, 0, $headerSize); 313 | } 314 | 315 | /** 316 | * Gets the response http status code. 317 | * 318 | * @return string 319 | */ 320 | public function getResponseStatusCode() 321 | { 322 | return curl_getinfo($this->ch, CURLINFO_HTTP_CODE); 323 | } 324 | 325 | /** 326 | * Gets the response http status message. 327 | * 328 | * @return string 329 | */ 330 | public function getResponseStatusMessage() 331 | { 332 | preg_match('/HTTP\/(1\.[0-1]+) ([0-9]{3}) (.*)/', $this->response, $matches); 333 | 334 | return trim(array_pop($matches)); 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /MimeFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\Helper; 16 | use BeSimple\SoapCommon\Mime\MultiPart as MimeMultiPart; 17 | use BeSimple\SoapCommon\Mime\Parser as MimeParser; 18 | use BeSimple\SoapCommon\Mime\Part as MimePart; 19 | use BeSimple\SoapCommon\SoapRequest; 20 | use BeSimple\SoapCommon\SoapRequestFilter; 21 | use BeSimple\SoapCommon\SoapResponse; 22 | use BeSimple\SoapCommon\SoapResponseFilter; 23 | 24 | /** 25 | * MIME filter. 26 | * 27 | * @author Andreas Schamberger 28 | */ 29 | class MimeFilter implements SoapRequestFilter, SoapResponseFilter 30 | { 31 | /** 32 | * Attachment type. 33 | * 34 | * @var int Helper::ATTACHMENTS_TYPE_SWA | Helper::ATTACHMENTS_TYPE_MTOM 35 | */ 36 | protected $attachmentType = Helper::ATTACHMENTS_TYPE_SWA; 37 | 38 | /** 39 | * Constructor. 40 | * 41 | * @param int $attachmentType Helper::ATTACHMENTS_TYPE_SWA | Helper::ATTACHMENTS_TYPE_MTOM 42 | */ 43 | public function __construct($attachmentType) 44 | { 45 | $this->attachmentType = $attachmentType; 46 | } 47 | 48 | /** 49 | * Reset all properties to default values. 50 | */ 51 | public function resetFilter() 52 | { 53 | $this->attachmentType = Helper::ATTACHMENTS_TYPE_SWA; 54 | } 55 | 56 | /** 57 | * Modify the given request XML. 58 | * 59 | * @param \BeSimple\SoapCommon\SoapRequest $request SOAP request 60 | * 61 | * @return void 62 | */ 63 | public function filterRequest(SoapRequest $request) 64 | { 65 | // get attachments from request object 66 | $attachmentsToSend = $request->getAttachments(); 67 | 68 | // build mime message if we have attachments 69 | if (count($attachmentsToSend) > 0) { 70 | $multipart = new MimeMultiPart(); 71 | $soapPart = new MimePart($request->getContent(), 'text/xml', 'utf-8', MimePart::ENCODING_EIGHT_BIT); 72 | $soapVersion = $request->getVersion(); 73 | // change content type headers for MTOM with SOAP 1.1 74 | if ($soapVersion == SOAP_1_1 && $this->attachmentType & Helper::ATTACHMENTS_TYPE_MTOM) { 75 | $multipart->setHeader('Content-Type', 'type', 'application/xop+xml'); 76 | $multipart->setHeader('Content-Type', 'start-info', 'text/xml'); 77 | $soapPart->setHeader('Content-Type', 'application/xop+xml'); 78 | $soapPart->setHeader('Content-Type', 'type', 'text/xml'); 79 | } 80 | // change content type headers for SOAP 1.2 81 | elseif ($soapVersion == SOAP_1_2) { 82 | $multipart->setHeader('Content-Type', 'type', 'application/soap+xml'); 83 | $soapPart->setHeader('Content-Type', 'application/soap+xml'); 84 | } 85 | $multipart->addPart($soapPart, true); 86 | foreach ($attachmentsToSend as $cid => $attachment) { 87 | $multipart->addPart($attachment, false); 88 | } 89 | $request->setContent($multipart->getMimeMessage()); 90 | 91 | // TODO 92 | $headers = $multipart->getHeadersForHttp(); 93 | list(, $contentType) = explode(': ', $headers[0]); 94 | 95 | $request->setContentType($contentType); 96 | } 97 | } 98 | 99 | /** 100 | * Modify the given response XML. 101 | * 102 | * @param \BeSimple\SoapCommon\SoapResponse $response SOAP response 103 | * 104 | * @return void 105 | */ 106 | public function filterResponse(SoapResponse $response) 107 | { 108 | // array to store attachments 109 | $attachmentsRecieved = array(); 110 | 111 | // check content type if it is a multipart mime message 112 | $responseContentType = $response->getContentType(); 113 | if (false !== stripos($responseContentType, 'multipart/related')) { 114 | // parse mime message 115 | $headers = array( 116 | 'Content-Type' => trim($responseContentType), 117 | ); 118 | $multipart = MimeParser::parseMimeMessage($response->getContent(), $headers); 119 | // get soap payload and update SoapResponse object 120 | $soapPart = $multipart->getPart(); 121 | // convert href -> myhref for external references as PHP throws exception in this case 122 | // http://svn.php.net/viewvc/php/php-src/branches/PHP_5_4/ext/soap/php_encoding.c?view=markup#l3436 123 | $content = preg_replace('/href=(?!#)/', 'myhref=', $soapPart->getContent()); 124 | $response->setContent($content); 125 | $response->setContentType($soapPart->getHeader('Content-Type')); 126 | // store attachments 127 | $attachments = $multipart->getParts(false); 128 | foreach ($attachments as $cid => $attachment) { 129 | $attachmentsRecieved[$cid] = $attachment; 130 | } 131 | } 132 | 133 | // add attachments to response object 134 | if (count($attachmentsRecieved) > 0) { 135 | $response->setAttachments($attachmentsRecieved); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BeSimpleSoapClient 2 | 3 | The BeSimpleSoapClient is a component that extends the native PHP SoapClient with further features like SwA, MTOM and WS-Security. 4 | 5 | # Features (only subsets of the linked specs implemented) 6 | 7 | * SwA: SOAP Messages with Attachments [Spec](http://www.w3.org/TR/SOAP-attachments) 8 | * MTOM: SOAP Message Transmission Optimization Mechanism [Spec](http://www.w3.org/TR/soap12-mtom/) 9 | * WS-Security [Spec1](http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0.pdf), [Spec2](http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf) 10 | * WS-Adressing [Spec](http://www.w3.org/2002/ws/addr/) 11 | 12 | # Installation 13 | 14 | If you do not yet have composer, install it like this: 15 | 16 | ```sh 17 | curl -s http://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin 18 | ``` 19 | 20 | Create a `composer.json` file: 21 | 22 | ```json 23 | { 24 | "require": { 25 | "besimple/soap-client": "0.2.*@dev" 26 | } 27 | } 28 | ``` 29 | 30 | Now you are ready to install the library: 31 | 32 | ```sh 33 | php /usr/local/bin/composer.phar install 34 | ``` 35 | -------------------------------------------------------------------------------- /SoapClientBuilder.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\AbstractSoapBuilder; 16 | use BeSimple\SoapCommon\Helper; 17 | 18 | /** 19 | * Fluent interface builder for SoapClient instance. 20 | * 21 | * @author Francis Besset 22 | * @author Christian Kerl 23 | */ 24 | class SoapClientBuilder extends AbstractSoapBuilder 25 | { 26 | /** 27 | * Authentication options. 28 | * 29 | * @var array(string=>mixed) 30 | */ 31 | protected $soapOptionAuthentication = array(); 32 | 33 | /** 34 | * Create new instance with default options. 35 | * 36 | * @return \BeSimple\SoapClient\SoapClientBuilder 37 | */ 38 | public static function createWithDefaults() 39 | { 40 | return parent::createWithDefaults() 41 | ->withUserAgent('BeSimpleSoap'); 42 | } 43 | 44 | /** 45 | * Finally returns a SoapClient instance. 46 | * 47 | * @return \BeSimple\SoapClient\SoapClient 48 | */ 49 | public function build() 50 | { 51 | $this->validateOptions(); 52 | 53 | return new SoapClient($this->wsdl, $this->getSoapOptions()); 54 | } 55 | 56 | /** 57 | * Get final array of SOAP options. 58 | * 59 | * @return array(string=>mixed) 60 | */ 61 | public function getSoapOptions() 62 | { 63 | return parent::getSoapOptions() + $this->soapOptionAuthentication; 64 | } 65 | 66 | /** 67 | * Configure option 'trace'. 68 | * 69 | * @param boolean $trace Enable/Disable 70 | * 71 | * @return \BeSimple\SoapClient\SoapClientBuilder 72 | */ 73 | public function withTrace($trace = true) 74 | { 75 | $this->soapOptions['trace'] = $trace; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * Configure option 'exceptions'. 82 | * 83 | * @param boolean $exceptions Enable/Disable 84 | * 85 | * @return \BeSimple\SoapClient\SoapClientBuilder 86 | */ 87 | public function withExceptions($exceptions = true) 88 | { 89 | $this->soapOptions['exceptions'] = $exceptions; 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * Configure option 'user_agent'. 96 | * 97 | * @param string $userAgent User agent string 98 | * 99 | * @return \BeSimple\SoapClient\SoapClientBuilder 100 | */ 101 | public function withUserAgent($userAgent) 102 | { 103 | $this->soapOptions['user_agent'] = $userAgent; 104 | 105 | return $this; 106 | } 107 | 108 | /** 109 | * Enable gzip compression. 110 | * 111 | * @return \BeSimple\SoapClient\SoapClientBuilder 112 | */ 113 | public function withCompressionGzip() 114 | { 115 | $this->soapOptions['compression'] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP; 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * Enable deflate compression. 122 | * 123 | * @return \BeSimple\SoapClient\SoapClientBuilder 124 | */ 125 | public function withCompressionDeflate() 126 | { 127 | $this->soapOptions['compression'] = SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE; 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * Configure basic authentication 134 | * 135 | * @param string $username Username 136 | * @param string $password Password 137 | * 138 | * @return \BeSimple\SoapClient\SoapClientBuilder 139 | */ 140 | public function withBasicAuthentication($username, $password) 141 | { 142 | $this->soapOptionAuthentication = array( 143 | 'authentication' => SOAP_AUTHENTICATION_BASIC, 144 | 'login' => $username, 145 | 'password' => $password, 146 | ); 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * Configure digest authentication. 153 | * 154 | * @param string $certificate Certificate 155 | * @param string $passphrase Passphrase 156 | * 157 | * @return \BeSimple\SoapClient\SoapClientBuilder 158 | */ 159 | public function withDigestAuthentication($certificate, $passphrase = null) 160 | { 161 | $this->soapOptionAuthentication = array( 162 | 'authentication' => SOAP_AUTHENTICATION_DIGEST, 163 | 'local_cert' => $certificate, 164 | ); 165 | 166 | if ($passphrase) { 167 | $this->soapOptionAuthentication['passphrase'] = $passphrase; 168 | } 169 | 170 | return $this; 171 | } 172 | 173 | /** 174 | * Configure proxy. 175 | * 176 | * @param string $host Host 177 | * @param int $port Port 178 | * @param string $login Login 179 | * @param string $password Password 180 | * @param int $auth Authentication method 181 | * 182 | * @return \BeSimple\SoapClient\SoapClientBuilder 183 | */ 184 | public function withProxy($host, $port, $login = null, $password = null, $auth = null) 185 | { 186 | $this->soapOptions['proxy_host'] = $host; 187 | $this->soapOptions['proxy_port'] = $port; 188 | 189 | if ($login) { 190 | $this->soapOptions['proxy_login'] = $login; 191 | $this->soapOptions['proxy_password'] = $password; 192 | 193 | if ($auth) { 194 | if (!in_array($auth, array(\CURLAUTH_BASIC, \CURLAUTH_NTLM), true)) { 195 | throw new \InvalidArgumentException('Invalid authentication method: CURLAUTH_BASIC or CURLAUTH_NTLM constants are availables.'); 196 | } 197 | 198 | $this->soapOptions['proxy_auth'] = $auth; 199 | } 200 | } 201 | 202 | return $this; 203 | } 204 | 205 | /** 206 | * SOAP attachment type Base64. 207 | * 208 | * @return \BeSimple\SoapServer\SoapServerBuilder 209 | */ 210 | public function withBase64Attachments() 211 | { 212 | $this->options['attachment_type'] = Helper::ATTACHMENTS_TYPE_BASE64; 213 | 214 | return $this; 215 | } 216 | 217 | /** 218 | * SOAP attachment type SwA. 219 | * 220 | * @return \BeSimple\SoapServer\SoapServerBuilder 221 | */ 222 | public function withSwaAttachments() 223 | { 224 | $this->options['attachment_type'] = Helper::ATTACHMENTS_TYPE_SWA; 225 | 226 | return $this; 227 | } 228 | 229 | /** 230 | * SOAP attachment type MTOM. 231 | * 232 | * @return \BeSimple\SoapServer\SoapServerBuilder 233 | */ 234 | public function withMtomAttachments() 235 | { 236 | $this->options['attachment_type'] = Helper::ATTACHMENTS_TYPE_MTOM; 237 | 238 | return $this; 239 | } 240 | 241 | /** 242 | * Validate options. 243 | */ 244 | protected function validateOptions() 245 | { 246 | $this->validateWsdl(); 247 | } 248 | } 249 | -------------------------------------------------------------------------------- /SoapKernel.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * (c) Andreas Schamberger 9 | * 10 | * This source file is subject to the MIT license that is bundled 11 | * with this source code in the file LICENSE. 12 | */ 13 | 14 | namespace BeSimple\SoapClient; 15 | 16 | use BeSimple\SoapCommon\SoapKernel as CommonSoapKernel; 17 | use BeSimple\SoapCommon\SoapRequest as CommonSoapRequest; 18 | use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse; 19 | 20 | /** 21 | * SoapKernel for Client. 22 | * 23 | * @author Andreas Schamberger 24 | */ 25 | class SoapKernel extends CommonSoapKernel 26 | { 27 | /** 28 | * {@inheritDoc} 29 | */ 30 | public function filterRequest(CommonSoapRequest $request) 31 | { 32 | $request->setAttachments($this->attachments); 33 | $this->attachments = array(); 34 | 35 | parent::filterRequest($request); 36 | } 37 | 38 | /** 39 | * {@inheritDoc} 40 | */ 41 | public function filterResponse(CommonSoapResponse $response) 42 | { 43 | parent::filterResponse($response); 44 | 45 | $this->attachments = $response->getAttachments(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SoapRequest.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\SoapRequest as CommonSoapRequest; 16 | use BeSimple\SoapCommon\SoapMessage; 17 | 18 | /** 19 | * SoapRequest class for SoapClient. Provides factory function for request object. 20 | * 21 | * @author Andreas Schamberger 22 | */ 23 | class SoapRequest extends CommonSoapRequest 24 | { 25 | /** 26 | * Factory function for SoapRequest. 27 | * 28 | * @param string $content Content 29 | * @param string $location Location 30 | * @param string $action SOAP action 31 | * @param string $version SOAP version 32 | * 33 | * @return BeSimple\SoapClient\SoapRequest 34 | */ 35 | public static function create($content, $location, $action, $version) 36 | { 37 | $request = new SoapRequest(); 38 | // $content is if unmodified from SoapClient not a php string type! 39 | $request->setContent((string) $content); 40 | $request->setLocation($location); 41 | $request->setAction($action); 42 | $request->setVersion($version); 43 | $contentType = SoapMessage::getContentTypeForVersion($version); 44 | $request->setContentType($contentType); 45 | 46 | return $request; 47 | } 48 | } -------------------------------------------------------------------------------- /SoapResponse.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse; 16 | 17 | /** 18 | * SoapResponse class for SoapClient. Provides factory function for response object. 19 | * 20 | * @author Andreas Schamberger 21 | */ 22 | class SoapResponse extends CommonSoapResponse 23 | { 24 | /** 25 | * Factory function for SoapResponse. 26 | * 27 | * @param string $content Content 28 | * @param string $location Location 29 | * @param string $action SOAP action 30 | * @param string $version SOAP version 31 | * @param string $contentType Content type header 32 | * 33 | * @return BeSimple\SoapClient\SoapResponse 34 | */ 35 | public static function create($content, $location, $action, $version, $contentType) 36 | { 37 | $response = new SoapResponse(); 38 | $response->setContent($content); 39 | $response->setLocation($location); 40 | $response->setAction($action); 41 | $response->setVersion($version); 42 | $response->setContentType($contentType); 43 | 44 | return $response; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Tests/AbstractWebserverTest.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient\Tests; 14 | 15 | use Symfony\Component\Process\PhpExecutableFinder; 16 | use Symfony\Component\Process\ProcessBuilder; 17 | 18 | /** 19 | * @author francis.besset@gmail.com 20 | */ 21 | abstract class AbstractWebServerTest extends \PHPUnit_Framework_TestCase 22 | { 23 | /** 24 | * @var ProcessBuilder 25 | */ 26 | static protected $webserver; 27 | static protected $websererPortLength; 28 | 29 | public static function setUpBeforeClass() 30 | { 31 | if (version_compare(PHP_VERSION, '5.4.0', '<')) { 32 | self::markTestSkipped('PHP Webserver is available from PHP 5.4'); 33 | } 34 | 35 | $phpFinder = new PhpExecutableFinder(); 36 | self::$webserver = ProcessBuilder::create(array( 37 | 'exec', // used exec binary (https://github.com/symfony/symfony/issues/5759) 38 | $phpFinder->find(), 39 | '-S', 40 | sprintf('localhost:%d', WEBSERVER_PORT), 41 | '-t', 42 | __DIR__.DIRECTORY_SEPARATOR.'Fixtures', 43 | ))->getProcess(); 44 | 45 | self::$webserver->start(); 46 | usleep(100000); 47 | 48 | self::$websererPortLength = strlen(WEBSERVER_PORT); 49 | } 50 | 51 | public static function tearDownAfterClass() 52 | { 53 | self::$webserver->stop(0); 54 | usleep(100000); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/AxisInterop/Fixtures/AttachmentRequest.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 | -------------------------------------------------------------------------------- /Tests/AxisInterop/Fixtures/SwA.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | BeSimpleSwaService 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 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /Tests/AxisInterop/Fixtures/WsSecuritySigEnc.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 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 | 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 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /Tests/AxisInterop/Fixtures/WsSecurityUserPass.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 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 | 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 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /Tests/AxisInterop/Fixtures/addBook.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 24 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 25 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_MTOM, 26 | 'cache_wsdl' => WSDL_CACHE_NONE, 27 | 'classmap' => array( 28 | 'base64Binary' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\base64Binary', 29 | 'AttachmentRequest' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\AttachmentRequest', 30 | ), 31 | 'proxy_host' => false, 32 | ); 33 | 34 | public function testAttachment() 35 | { 36 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/MTOM.wsdl', $this->options); 37 | 38 | $b64 = new base64Binary(); 39 | $b64->_ = 'This is a test. :)'; 40 | $b64->contentType = 'text/plain'; 41 | 42 | $attachment = new AttachmentRequest(); 43 | $attachment->fileName = 'test123.txt'; 44 | $attachment->binaryData = $b64; 45 | 46 | $this->assertEquals('File saved succesfully.', $sc->attachment($attachment)); 47 | 48 | // $fileCreatedByServer = __DIR__.'/'.$attachment->fileName; 49 | // $this->assertEquals($b64->_, file_get_contents($fileCreatedByServer)); 50 | // unlink($fileCreatedByServer); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Tests/AxisInterop/SwA/build.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /Tests/AxisInterop/SwA/resources/META-INF/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | BeSimple test service for SwA. 4 | true 5 | besimple.service.BeSimpleSwaService 6 | 7 | urn:uploadFile 8 | 9 | 10 | 11 | urn:downloadFile 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Tests/AxisInterop/SwA/src/besimple/service/BeSimpleSwaService.java: -------------------------------------------------------------------------------- 1 | package besimple.service; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | 6 | import javax.xml.namespace.QName; 7 | 8 | import javax.activation.DataHandler; 9 | import javax.activation.FileDataSource; 10 | 11 | import org.apache.axiom.attachments.Attachments; 12 | import org.apache.axiom.om.OMAbstractFactory; 13 | import org.apache.axiom.om.OMAttribute; 14 | import org.apache.axiom.om.OMElement; 15 | import org.apache.axiom.om.OMFactory; 16 | import org.apache.axiom.om.OMNamespace; 17 | 18 | import org.apache.axis2.context.MessageContext; 19 | import org.apache.axis2.context.OperationContext; 20 | import org.apache.axis2.wsdl.WSDLConstants; 21 | 22 | public class BeSimpleSwaService { 23 | 24 | String namespace = "http://service.besimple"; 25 | 26 | public OMElement uploadFile(OMElement element) throws Exception { 27 | OMElement dataElement = (OMElement)element.getFirstChildWithName(new QName(namespace, "data")); 28 | OMAttribute hrefAttribute = dataElement.getAttribute(new QName("href")); 29 | 30 | String contentID = hrefAttribute.getAttributeValue(); 31 | contentID = contentID.trim(); 32 | if (contentID.substring(0, 3).equalsIgnoreCase("cid")) { 33 | contentID = contentID.substring(4); 34 | } 35 | OMElement nameElement = (OMElement)element.getFirstChildWithName(new QName(namespace, "name")); 36 | String name = nameElement.getText(); 37 | 38 | MessageContext msgCtx = MessageContext.getCurrentMessageContext(); 39 | Attachments attachment = msgCtx.getAttachmentMap(); 40 | DataHandler dataHandler = attachment.getDataHandler(contentID); 41 | 42 | File file = new File(name); 43 | FileOutputStream fileOutputStream = new FileOutputStream(file); 44 | dataHandler.writeTo(fileOutputStream); 45 | fileOutputStream.flush(); 46 | fileOutputStream.close(); 47 | 48 | OMFactory factory = OMAbstractFactory.getOMFactory(); 49 | OMNamespace omNs = factory.createOMNamespace(namespace, "swa"); 50 | OMElement wrapperElement = factory.createOMElement("uploadFileResponse", omNs); 51 | OMElement returnElement = factory.createOMElement("return", omNs, wrapperElement); 52 | returnElement.setText("File saved succesfully."); 53 | 54 | return wrapperElement; 55 | } 56 | 57 | public OMElement downloadFile(OMElement element) throws Exception { 58 | OMElement nameElement = (OMElement)element.getFirstChildWithName(new QName(namespace, "name")); 59 | String name = nameElement.getText(); 60 | 61 | MessageContext msgCtxIn = MessageContext.getCurrentMessageContext(); 62 | OperationContext operationContext = msgCtxIn.getOperationContext(); 63 | MessageContext msgCtxOut = operationContext.getMessageContext(WSDLConstants.MESSAGE_LABEL_OUT_VALUE); 64 | 65 | FileDataSource fileDataSource = new FileDataSource(name); 66 | DataHandler dataHandler = new DataHandler(fileDataSource); 67 | 68 | String contentID = "cid:" + msgCtxOut.addAttachment(dataHandler); 69 | 70 | OMFactory factory = OMAbstractFactory.getOMFactory(); 71 | OMNamespace omNs = factory.createOMNamespace(namespace, "swa"); 72 | OMElement wrapperElement = factory.createOMElement("downloadFileResponse", omNs); 73 | OMElement dataElement = factory.createOMElement("data", omNs, wrapperElement); 74 | dataElement.addAttribute("href", contentID, null); 75 | 76 | return wrapperElement; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tests/AxisInterop/SwaAxisInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 31 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 32 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_SWA, 33 | 'cache_wsdl' => WSDL_CACHE_NONE, 34 | 'classmap' => array( 35 | 'downloadFile' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\downloadFile', 36 | 'downloadFileResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\downloadFileResponse', 37 | 'uploadFile' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\uploadFile', 38 | 'uploadFileResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\uploadFileResponse', 39 | ), 40 | 'proxy_host' => false, 41 | ); 42 | 43 | public function testUploadDownloadText() 44 | { 45 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $this->options); 46 | 47 | $upload = new uploadFile(); 48 | $upload->name = 'upload.txt'; 49 | $upload->data = 'This is a test. :)'; 50 | $result = $sc->uploadFile($upload); 51 | 52 | $this->assertEquals('File saved succesfully.', $result->return); 53 | 54 | $download = new downloadFile(); 55 | $download->name = 'upload.txt'; 56 | $result = $sc->downloadFile($download); 57 | 58 | $this->assertEquals($upload->data, $result->data); 59 | } 60 | 61 | public function testUploadDownloadImage() 62 | { 63 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $this->options); 64 | 65 | $upload = new uploadFile(); 66 | $upload->name = 'image.jpg'; 67 | $upload->data = file_get_contents(__DIR__.'/Fixtures/image.jpg'); // source: http://www.freeimageslive.com/galleries/light/pics/swirl3768.jpg; 68 | $result = $sc->uploadFile($upload); 69 | 70 | $this->assertEquals('File saved succesfully.', $result->return); 71 | 72 | $download = new downloadFile(); 73 | $download->name = 'image.jpg'; 74 | $result = $sc->downloadFile($download); 75 | 76 | $this->assertEquals($upload->data, $result->data); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Tests/AxisInterop/TestCase.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 17 | 'The Axis server is not started on port 8080.' 18 | ); 19 | } 20 | 21 | curl_close($ch); 22 | } 23 | } -------------------------------------------------------------------------------- /Tests/AxisInterop/WsAddressingAxisInteropTest.php: -------------------------------------------------------------------------------- 1 | 15 | * ... 16 | * 17 | * 18 | * build.xml: 19 | * replace version.aar with version2.aar 20 | * 21 | * 2) Run ant build.xml in "$AXIS_HOME/samples/version" 22 | * 23 | */ 24 | 25 | use BeSimple\SoapClient\SoapClient as BeSimpleSoapClient; 26 | use BeSimple\SoapClient\WsAddressingFilter as BeSimpleWsAddressingFilter; 27 | 28 | use BeSimple\SoapClient\Tests\AxisInterop\TestCase; 29 | 30 | class WsAddressingAxisInteropTest extends TestCase 31 | { 32 | private $options = array( 33 | 'soap_version' => SOAP_1_2, 34 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 35 | 'proxy_host' => false, 36 | ); 37 | 38 | public function testSession() 39 | { 40 | $sc = new BeSimpleSoapClient('http://localhost:8080/axis2/services/Version2?wsdl', $this->options); 41 | $soapKernel = $sc->getSoapKernel(); 42 | $wsaFilter = new BeSimpleWsAddressingFilter(); 43 | $soapKernel->registerFilter($wsaFilter); 44 | 45 | $wsaFilter->setReplyTo(BeSimpleWsAddressingFilter::ENDPOINT_REFERENCE_ANONYMOUS); 46 | $wsaFilter->setMessageId(); 47 | 48 | $version = $sc->getVersion(); 49 | 50 | $soapSessionId1 = $wsaFilter->getReferenceParameter('http://ws.apache.org/namespaces/axis2', 'ServiceGroupId'); 51 | 52 | $wsaFilter->addReferenceParameter('http://ws.apache.org/namespaces/axis2', 'axis2', 'ServiceGroupId', $soapSessionId1); 53 | 54 | $version = $sc->getVersion(); 55 | 56 | $soapSessionId2 = $wsaFilter->getReferenceParameter('http://ws.apache.org/namespaces/axis2', 'ServiceGroupId'); 57 | 58 | $this->assertEquals($soapSessionId1, $soapSessionId2); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Tests/AxisInterop/WsSecuritySigEncAxisInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_2, 57 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 58 | 'classmap' => array( 59 | 'getBook' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBook', 60 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBookResponse', 61 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBooksByType', 62 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBooksByTypeResponse', 63 | 'addBook' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\addBook', 64 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\addBookResponse', 65 | 'BookInformation' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\BookInformation', 66 | ), 67 | 'proxy_host' => false, 68 | ); 69 | 70 | public function testSigEnc() 71 | { 72 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecuritySigEnc.wsdl', $this->options); 73 | 74 | $wssFilter = new BeSimpleWsSecurityFilter(); 75 | // user key for signature and encryption 76 | $securityKeyUser = new BeSimpleWsSecurityKey(); 77 | $securityKeyUser->addPrivateKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/clientkey.pem', true); 78 | $securityKeyUser->addPublicKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/clientcert.pem', true); 79 | $wssFilter->setUserSecurityKeyObject($securityKeyUser); 80 | // service key for encryption 81 | $securityKeyService = new BeSimpleWsSecurityKey(); 82 | $securityKeyService->addPrivateKey(XmlSecurityKey::TRIPLEDES_CBC); 83 | $securityKeyService->addPublicKey(XmlSecurityKey::RSA_1_5, __DIR__.'/Fixtures/servercert.pem', true); 84 | $wssFilter->setServiceSecurityKeyObject($securityKeyService); 85 | // TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | TOKEN_REFERENCE_SECURITY_TOKEN | TOKEN_REFERENCE_THUMBPRINT_SHA1 86 | $wssFilter->setSecurityOptionsSignature(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_SECURITY_TOKEN); 87 | $wssFilter->setSecurityOptionsEncryption(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_THUMBPRINT_SHA1); 88 | 89 | $soapKernel = $sc->getSoapKernel(); 90 | $soapKernel->registerFilter($wssFilter); 91 | 92 | $gb = new getBook(); 93 | $gb->isbn = '0061020052'; 94 | $result = $sc->getBook($gb); 95 | $this->assertInstanceOf('BeSimple\SoapClient\Tests\AxisInterop\Fixtures\BookInformation', $result->getBookReturn); 96 | 97 | $ab = new addBook(); 98 | $ab->isbn = '0445203498'; 99 | $ab->title = 'The Dragon Never Sleeps'; 100 | $ab->author = 'Cook, Glen'; 101 | $ab->type = 'scifi'; 102 | 103 | $this->assertTrue((bool) $sc->addBook($ab)); 104 | 105 | // getBooksByType("scifi"); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Tests/AxisInterop/WsSecurityUserPassAxisInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_2, 33 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 34 | 'classmap' => array( 35 | 'getBook' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBook', 36 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBookResponse', 37 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBooksByType', 38 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\getBooksByTypeResponse', 39 | 'addBook' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\addBook', 40 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\addBookResponse', 41 | 'BookInformation' => 'BeSimple\SoapClient\Tests\AxisInterop\Fixtures\BookInformation', 42 | ), 43 | 'proxy_host' => false, 44 | ); 45 | 46 | public function testUserPassText() 47 | { 48 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options); 49 | 50 | $wssFilter = new BeSimpleWsSecurityFilter(true, 600); 51 | $wssFilter->addUserData('libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_TEXT); 52 | 53 | $soapKernel = $sc->getSoapKernel(); 54 | $soapKernel->registerFilter($wssFilter); 55 | 56 | $gb = new getBook(); 57 | $gb->isbn = '0061020052'; 58 | $result = $sc->getBook($gb); 59 | $this->assertInstanceOf('BeSimple\SoapClient\Tests\AxisInterop\Fixtures\BookInformation', $result->getBookReturn); 60 | 61 | $ab = new addBook(); 62 | $ab->isbn = '0445203498'; 63 | $ab->title = 'The Dragon Never Sleeps'; 64 | $ab->author = 'Cook, Glen'; 65 | $ab->type = 'scifi'; 66 | 67 | $this->assertTrue((bool) $sc->addBook($ab)); 68 | 69 | // getBooksByType("scifi"); 70 | } 71 | 72 | public function testUserPassDigest() 73 | { 74 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options); 75 | 76 | $wssFilter = new BeSimpleWsSecurityFilter(true, 600); 77 | $wssFilter->addUserData( 'libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST ); 78 | 79 | $soapKernel = $sc->getSoapKernel(); 80 | $soapKernel->registerFilter($wssFilter); 81 | 82 | $gb = new getBook(); 83 | $gb->isbn = '0061020052'; 84 | $result = $sc->getBook($gb); 85 | $this->assertInstanceOf('BeSimple\SoapClient\Tests\AxisInterop\Fixtures\BookInformation', $result->getBookReturn); 86 | 87 | $ab = new addBook(); 88 | $ab->isbn = '0445203498'; 89 | $ab->title = 'The Dragon Never Sleeps'; 90 | $ab->author = 'Cook, Glen'; 91 | $ab->type = 'scifi'; 92 | 93 | $this->assertTrue((bool) $sc->addBook($ab)); 94 | 95 | // getBooksByType("scifi"); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Tests/AxisInterop/axis_services/besimple-swa.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeSimple/BeSimpleSoapClient/91e91c4addb6e5d981e53eadf5d4c71f9ca8085b/Tests/AxisInterop/axis_services/besimple-swa.aar -------------------------------------------------------------------------------- /Tests/AxisInterop/axis_services/library-signencr.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeSimple/BeSimpleSoapClient/91e91c4addb6e5d981e53eadf5d4c71f9ca8085b/Tests/AxisInterop/axis_services/library-signencr.aar -------------------------------------------------------------------------------- /Tests/AxisInterop/axis_services/library-username-digest.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeSimple/BeSimpleSoapClient/91e91c4addb6e5d981e53eadf5d4c71f9ca8085b/Tests/AxisInterop/axis_services/library-username-digest.aar -------------------------------------------------------------------------------- /Tests/AxisInterop/axis_services/sample-mtom.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeSimple/BeSimpleSoapClient/91e91c4addb6e5d981e53eadf5d4c71f9ca8085b/Tests/AxisInterop/axis_services/sample-mtom.aar -------------------------------------------------------------------------------- /Tests/AxisInterop/axis_services/version2.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BeSimple/BeSimpleSoapClient/91e91c4addb6e5d981e53eadf5d4c71f9ca8085b/Tests/AxisInterop/axis_services/version2.aar -------------------------------------------------------------------------------- /Tests/CurlTest.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient\Tests; 14 | 15 | use BeSimple\SoapClient\Curl; 16 | 17 | /** 18 | * @author Andreas Schamberger 19 | */ 20 | class CurlTest extends AbstractWebserverTest 21 | { 22 | public function testExec() 23 | { 24 | $curl = new Curl(array( 25 | 'proxy_host' => false, 26 | )); 27 | 28 | $this->assertTrue($curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT))); 29 | $this->assertTrue($curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT))); 30 | } 31 | 32 | public function testGetErrorMessage() 33 | { 34 | $curl = new Curl(array( 35 | 'proxy_host' => false, 36 | )); 37 | 38 | $curl->exec('http://unknown/curl.txt'); 39 | $this->assertEquals('Could not connect to host', $curl->getErrorMessage()); 40 | 41 | $curl->exec(sprintf('xyz://localhost:%d/@404.txt', WEBSERVER_PORT)); 42 | $this->assertEquals('Unknown protocol. Only http and https are allowed.', $curl->getErrorMessage()); 43 | 44 | $curl->exec(''); 45 | $this->assertEquals('Unable to parse URL', $curl->getErrorMessage()); 46 | } 47 | 48 | public function testGetRequestHeaders() 49 | { 50 | $curl = new Curl(array( 51 | 'proxy_host' => false, 52 | )); 53 | 54 | $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); 55 | $this->assertEquals(132 + self::$websererPortLength, strlen($curl->getRequestHeaders())); 56 | 57 | $curl->exec(sprintf('http://localhost:%s/404.txt', WEBSERVER_PORT)); 58 | $this->assertEquals(131 + self::$websererPortLength, strlen($curl->getRequestHeaders())); 59 | } 60 | 61 | public function testGetResponse() 62 | { 63 | $curl = new Curl(array( 64 | 'proxy_host' => false, 65 | )); 66 | 67 | $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); 68 | $this->assertSame('OK', $curl->getResponseStatusMessage()); 69 | $this->assertEquals(145 + self::$websererPortLength, strlen($curl->getResponse())); 70 | 71 | $curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)); 72 | $this->assertSame('Not Found', $curl->getResponseStatusMessage()); 73 | } 74 | 75 | public function testGetResponseBody() 76 | { 77 | $curl = new Curl(array( 78 | 'proxy_host' => false, 79 | )); 80 | 81 | $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); 82 | $this->assertEquals('This is a testfile for cURL.', $curl->getResponseBody()); 83 | } 84 | 85 | public function testGetResponseContentType() 86 | { 87 | $curl = new Curl(array( 88 | 'proxy_host' => false, 89 | )); 90 | 91 | $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); 92 | $this->assertEquals('text/plain; charset=UTF-8', $curl->getResponseContentType()); 93 | 94 | $curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)); 95 | $this->assertEquals('text/html; charset=UTF-8', $curl->getResponseContentType()); 96 | } 97 | 98 | public function testGetResponseHeaders() 99 | { 100 | $curl = new Curl(array( 101 | 'proxy_host' => false, 102 | )); 103 | 104 | $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); 105 | $this->assertEquals(117 + self::$websererPortLength, strlen($curl->getResponseHeaders())); 106 | 107 | $curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)); 108 | $this->assertEquals(124 + self::$websererPortLength, strlen($curl->getResponseHeaders())); 109 | } 110 | 111 | public function testGetResponseStatusCode() 112 | { 113 | $curl = new Curl(array( 114 | 'proxy_host' => false, 115 | )); 116 | 117 | $curl->exec(sprintf('http://localhost:%d/curl.txt', WEBSERVER_PORT)); 118 | $this->assertEquals(200, $curl->getResponseStatusCode()); 119 | 120 | $curl->exec(sprintf('http://localhost:%d/404.txt', WEBSERVER_PORT)); 121 | $this->assertEquals(404, $curl->getResponseStatusCode()); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Tests/Fixtures/curl.txt: -------------------------------------------------------------------------------- 1 | This is a testfile for cURL. -------------------------------------------------------------------------------- /Tests/Fixtures/foobar.wsdl: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /Tests/Fixtures/type_include.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tests/Fixtures/wsdl_include.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Tests/Fixtures/wsdlinclude/wsdlinctest_absolute.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | wsdlincludetest 4 | 5 | 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/wsdlinclude/wsdlinctest_relative.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | wsdlincludetest 4 | 5 | 6 | -------------------------------------------------------------------------------- /Tests/Fixtures/xsdinclude/xsdinctest_absolute.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | xsdinctest 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Tests/Fixtures/xsdinclude/xsdinctest_relative.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | xsdinctest 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Tests/ServerInterop/Fixtures/AttachmentRequest.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 | -------------------------------------------------------------------------------- /Tests/ServerInterop/Fixtures/SwA.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 3 | BeSimpleSwaService 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 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /Tests/ServerInterop/Fixtures/WsSecuritySigEnc.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 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 | 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 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /Tests/ServerInterop/Fixtures/WsSecurityUserPass.wsdl: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 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 | 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 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /Tests/ServerInterop/Fixtures/addBook.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 13 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 14 | 'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders 15 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_MTOM, 16 | 'cache_wsdl' => WSDL_CACHE_NONE, 17 | 'classmap' => array( 18 | 'base64Binary' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\base64Binary', 19 | 'AttachmentRequest' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\AttachmentRequest', 20 | ), 21 | 'connection_timeout' => 1, 22 | ); 23 | 24 | $sc = new BeSimpleSoapClient('Fixtures/MTOM.wsdl', $options); 25 | 26 | //var_dump($sc->__getFunctions()); 27 | //var_dump($sc->__getTypes()); 28 | 29 | try { 30 | $b64 = new base64Binary(); 31 | $b64->_ = 'This is a test. :)'; 32 | $b64->contentType = 'text/plain'; 33 | 34 | $attachment = new AttachmentRequest(); 35 | $attachment->fileName = 'test123.txt'; 36 | $attachment->binaryData = $b64; 37 | 38 | var_dump($sc->attachment($attachment)); 39 | 40 | } catch (Exception $e) { 41 | var_dump($e); 42 | } 43 | 44 | // var_dump( 45 | // $sc->__getLastRequestHeaders(), 46 | // $sc->__getLastRequest(), 47 | // $sc->__getLastResponseHeaders(), 48 | // $sc->__getLastResponse() 49 | // ); -------------------------------------------------------------------------------- /Tests/ServerInterop/MTOMServer.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 12 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 13 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_MTOM, 14 | 'cache_wsdl' => WSDL_CACHE_NONE, 15 | 'classmap' => array( 16 | 'base64Binary' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\base64Binary', 17 | 'AttachmentType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\AttachmentRequest', 18 | ), 19 | ); 20 | 21 | class Mtom 22 | { 23 | public function attachment(Fixtures\AttachmentRequest $attachment) 24 | { 25 | $b64 = $attachment->binaryData; 26 | 27 | file_put_contents(__DIR__.'/'.$attachment->fileName, $b64->_); 28 | 29 | return 'File saved succesfully.'; 30 | } 31 | } 32 | 33 | $ss = new BeSimpleSoapServer(__DIR__.'/Fixtures/MTOM.wsdl', $options); 34 | $ss->setClass('Mtom'); 35 | $ss->handle(); 36 | -------------------------------------------------------------------------------- /Tests/ServerInterop/MtomServerInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 16 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 17 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_MTOM, 18 | 'cache_wsdl' => WSDL_CACHE_NONE, 19 | 'classmap' => array( 20 | 'base64Binary' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\base64Binary', 21 | 'AttachmentRequest' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\AttachmentRequest', 22 | ), 23 | 'proxy_host' => false, 24 | ); 25 | 26 | public function testAttachment() 27 | { 28 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/MTOM.wsdl', $this->options); 29 | 30 | $b64 = new base64Binary(); 31 | $b64->_ = 'This is a test. :)'; 32 | $b64->contentType = 'text/plain'; 33 | 34 | $attachment = new AttachmentRequest(); 35 | $attachment->fileName = 'test123.txt'; 36 | $attachment->binaryData = $b64; 37 | 38 | $this->assertEquals('File saved succesfully.', $sc->attachment($attachment)); 39 | 40 | $fileCreatedByServer = __DIR__.'/'.$attachment->fileName; 41 | $this->assertEquals($b64->_, file_get_contents($fileCreatedByServer)); 42 | unlink($fileCreatedByServer); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/ServerInterop/SwAServer.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 15 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 16 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_SWA, 17 | 'cache_wsdl' => WSDL_CACHE_NONE, 18 | 'classmap' => array( 19 | 'downloadFile' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\downloadFile', 20 | 'downloadFileResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\downloadFileResponse', 21 | 'uploadFile' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\uploadFile', 22 | 'uploadFileResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\uploadFileResponse', 23 | ), 24 | ); 25 | 26 | class SwA 27 | { 28 | public function uploadFile(uploadFile $uploadFile) 29 | { 30 | file_put_contents(__DIR__.'/'.$uploadFile->name, $uploadFile->data); 31 | 32 | $ufr = new uploadFileResponse(); 33 | $ufr->return = 'File saved succesfully.'; 34 | 35 | return $ufr; 36 | } 37 | 38 | public function downloadFile(downloadFile $downloadFile) 39 | { 40 | $dfr = new downloadFileResponse(); 41 | $dfr->data = file_get_contents(__DIR__.'/'.$downloadFile->name); 42 | 43 | return $dfr; 44 | } 45 | } 46 | 47 | $ss = new BeSimpleSoapServer(__DIR__.'/Fixtures/SwA.wsdl', $options); 48 | $ss->setClass('SwA'); 49 | $ss->handle(); 50 | -------------------------------------------------------------------------------- /Tests/ServerInterop/SwaClient.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 17 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 18 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_SWA, 19 | 'cache_wsdl' => WSDL_CACHE_NONE, 20 | 'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders 21 | 'classmap' => array( 22 | 'downloadFile' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\downloadFile', 23 | 'downloadFileResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\downloadFileResponse', 24 | 'uploadFile' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\uploadFile', 25 | 'uploadFileResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\uploadFileResponse', 26 | ), 27 | ); 28 | 29 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $options); 30 | 31 | try { 32 | 33 | $upload = new uploadFile(); 34 | $upload->name = 'upload.txt'; 35 | $upload->data = 'This is a test. :)'; 36 | $result = $sc->uploadFile($upload); 37 | 38 | var_dump($result); 39 | 40 | $download = new downloadFile(); 41 | $download->name = 'upload.txt'; 42 | var_dump($sc->downloadFile($download)); 43 | } catch (Exception $e) { 44 | var_dump($e); 45 | } 46 | 47 | // var_dump( 48 | // $sc->__getLastRequestHeaders(), 49 | // $sc->__getLastRequest(), 50 | // $sc->__getLastResponseHeaders(), 51 | // $sc->__getLastResponse() 52 | // ); -------------------------------------------------------------------------------- /Tests/ServerInterop/SwaServerInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 17 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 18 | 'attachment_type' => BeSimpleSoapHelper::ATTACHMENTS_TYPE_SWA, 19 | 'cache_wsdl' => WSDL_CACHE_NONE, 20 | 'classmap' => array( 21 | 'downloadFile' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\downloadFile', 22 | 'downloadFileResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\downloadFileResponse', 23 | 'uploadFile' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\uploadFile', 24 | 'uploadFileResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\uploadFileResponse', 25 | ), 26 | 'proxy_host' => false, 27 | ); 28 | 29 | public function testUploadDownloadText() 30 | { 31 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $this->options); 32 | 33 | $upload = new uploadFile(); 34 | $upload->name = 'upload.txt'; 35 | $upload->data = 'This is a test. :)'; 36 | $result = $sc->uploadFile($upload); 37 | 38 | $this->assertEquals('File saved succesfully.', $result->return); 39 | 40 | $download = new downloadFile(); 41 | $download->name = 'upload.txt'; 42 | $result = $sc->downloadFile($download); 43 | 44 | $this->assertEquals($upload->data, $result->data); 45 | 46 | unlink(__DIR__.'/../ServerInterop/'.$download->name); 47 | } 48 | 49 | public function testUploadDownloadImage() 50 | { 51 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/SwA.wsdl', $this->options); 52 | 53 | $upload = new uploadFile(); 54 | $upload->name = 'image.jpg'; 55 | $upload->data = file_get_contents(__DIR__.'/Fixtures/image.jpg'); // source: http://www.freeimageslive.com/galleries/light/pics/swirl3768.jpg; 56 | $result = $sc->uploadFile($upload); 57 | 58 | $this->assertEquals('File saved succesfully.', $result->return); 59 | 60 | $download = new downloadFile(); 61 | $download->name = 'image.jpg'; 62 | $result = $sc->downloadFile($download); 63 | 64 | $this->assertEquals($upload->data, $result->data); 65 | 66 | unlink(__DIR__.'/../ServerInterop/'.$download->name); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Tests/ServerInterop/TestCase.php: -------------------------------------------------------------------------------- 1 | markTestSkipped( 11 | 'The PHP cli webserver is not available with PHP 5.3.' 12 | ); 13 | } 14 | 15 | $ch = curl_init('http://localhost:8081/'); 16 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); 17 | curl_setopt($ch, CURLOPT_HEADER, true); 18 | curl_setopt($ch, CURLOPT_NOBODY, true); 19 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 20 | 21 | if (curl_exec($ch) === false) { 22 | $this->markTestSkipped( 23 | 'The PHP webserver is not started on port 8081.' 24 | ); 25 | } 26 | 27 | curl_close($ch); 28 | } 29 | } -------------------------------------------------------------------------------- /Tests/ServerInterop/WsSecuritySigEncServer.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 22 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 23 | 'cache_wsdl' => WSDL_CACHE_NONE, 24 | 'classmap' => array( 25 | 'getBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBook', 26 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBookResponse', 27 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByType', 28 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByTypeResponse', 29 | 'addBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBook', 30 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBookResponse', 31 | 'BookInformation' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', 32 | ), 33 | ); 34 | 35 | class WsSecuritySigEncServer 36 | { 37 | public function getBook(getBook $gb) 38 | { 39 | $bi = new BookInformation(); 40 | $bi->isbn = $gb->isbn; 41 | $bi->title = 'title'; 42 | $bi->author = 'author'; 43 | $bi->type = 'scifi'; 44 | 45 | $br = new getBookResponse(); 46 | $br->getBookReturn = $bi; 47 | 48 | return $br; 49 | } 50 | 51 | public function addBook(addBook $ab) 52 | { 53 | $abr = new addBookResponse(); 54 | $abr->addBookReturn = true; 55 | 56 | return $abr; 57 | } 58 | } 59 | 60 | $ss = new BeSimpleSoapServer(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $options); 61 | 62 | $wssFilter = new BeSimpleWsSecurityFilter(); 63 | 64 | // user key for signature and encryption 65 | $securityKeyUser = new BeSimpleWsSecurityKey(); 66 | $securityKeyUser->addPrivateKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/serverkey.pem', true); 67 | $securityKeyUser->addPublicKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/servercert.pem', true); 68 | $wssFilter->setUserSecurityKeyObject($securityKeyUser); 69 | // service key for encryption 70 | $securityKeyService = new BeSimpleWsSecurityKey(); 71 | $securityKeyService->addPrivateKey(XmlSecurityKey::TRIPLEDES_CBC); 72 | $securityKeyService->addPublicKey(XmlSecurityKey::RSA_1_5, __DIR__.'/Fixtures/clientcert.pem', true); 73 | $wssFilter->setServiceSecurityKeyObject($securityKeyService); 74 | // TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | TOKEN_REFERENCE_SECURITY_TOKEN | TOKEN_REFERENCE_THUMBPRINT_SHA1 75 | $wssFilter->setSecurityOptionsSignature(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_SECURITY_TOKEN); 76 | $wssFilter->setSecurityOptionsEncryption(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_THUMBPRINT_SHA1); 77 | 78 | $soapKernel = $ss->getSoapKernel(); 79 | $soapKernel->registerFilter($wssFilter); 80 | 81 | $ss->setClass('WsSecuritySigEncServer'); 82 | $ss->handle(); 83 | -------------------------------------------------------------------------------- /Tests/ServerInterop/WsSecuritySigEncServerClient.php: -------------------------------------------------------------------------------- 1 | SOAP_1_2, 23 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 24 | 'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders 25 | 'classmap' => array( 26 | 'getBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBook', 27 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBookResponse', 28 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByType', 29 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByTypeResponse', 30 | 'addBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBook', 31 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBookResponse', 32 | 'BookInformation' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', 33 | ), 34 | ); 35 | 36 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecuritySigEnc.wsdl', $options); 37 | 38 | //var_dump($sc->__getFunctions()); 39 | //var_dump($sc->__getTypes()); 40 | 41 | try { 42 | $wssFilter = new BeSimpleWsSecurityFilter(); 43 | // user key for signature and encryption 44 | $securityKeyUser = new BeSimpleWsSecurityKey(); 45 | $securityKeyUser->addPrivateKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/clientkey.pem', true); 46 | $securityKeyUser->addPublicKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/clientcert.pem', true); 47 | $wssFilter->setUserSecurityKeyObject($securityKeyUser); 48 | // service key for encryption 49 | $securityKeyService = new BeSimpleWsSecurityKey(); 50 | $securityKeyService->addPrivateKey(XmlSecurityKey::TRIPLEDES_CBC); 51 | $securityKeyService->addPublicKey(XmlSecurityKey::RSA_1_5, __DIR__.'/Fixtures/servercert.pem', true); 52 | $wssFilter->setServiceSecurityKeyObject($securityKeyService); 53 | // TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | TOKEN_REFERENCE_SECURITY_TOKEN | TOKEN_REFERENCE_THUMBPRINT_SHA1 54 | $wssFilter->setSecurityOptionsSignature(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_SECURITY_TOKEN); 55 | $wssFilter->setSecurityOptionsEncryption(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_THUMBPRINT_SHA1); 56 | 57 | $soapKernel = $sc->getSoapKernel(); 58 | $soapKernel->registerFilter($wssFilter); 59 | 60 | $gb = new getBook(); 61 | $gb->isbn = '0061020052'; 62 | $result = $sc->getBook($gb); 63 | var_dump($result->getBookReturn); 64 | 65 | $ab = new addBook(); 66 | $ab->isbn = '0445203498'; 67 | $ab->title = 'The Dragon Never Sleeps'; 68 | $ab->author = 'Cook, Glen'; 69 | $ab->type = 'scifi'; 70 | 71 | var_dump($sc->addBook($ab)); 72 | 73 | } catch (Exception $e) { 74 | var_dump($e); 75 | } 76 | 77 | // var_dump( 78 | // $sc->__getLastRequestHeaders(), 79 | // $sc->__getLastRequest(), 80 | // $sc->__getLastResponseHeaders(), 81 | // $sc->__getLastResponse() 82 | // ); 83 | -------------------------------------------------------------------------------- /Tests/ServerInterop/WsSecuritySigEncServerInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_2, 23 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 24 | 'classmap' => array( 25 | 'getBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBook', 26 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBookResponse', 27 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByType', 28 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByTypeResponse', 29 | 'addBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBook', 30 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBookResponse', 31 | 'BookInformation' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', 32 | ), 33 | 'proxy_host' => false, 34 | ); 35 | 36 | public function testSigEnc() 37 | { 38 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecuritySigEnc.wsdl', $this->options); 39 | 40 | $wssFilter = new BeSimpleWsSecurityFilter(); 41 | // user key for signature and encryption 42 | $securityKeyUser = new BeSimpleWsSecurityKey(); 43 | $securityKeyUser->addPrivateKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/clientkey.pem', true); 44 | $securityKeyUser->addPublicKey(XmlSecurityKey::RSA_SHA1, __DIR__.'/Fixtures/clientcert.pem', true); 45 | $wssFilter->setUserSecurityKeyObject($securityKeyUser); 46 | // service key for encryption 47 | $securityKeyService = new BeSimpleWsSecurityKey(); 48 | $securityKeyService->addPrivateKey(XmlSecurityKey::TRIPLEDES_CBC); 49 | $securityKeyService->addPublicKey(XmlSecurityKey::RSA_1_5, __DIR__.'/Fixtures/servercert.pem', true); 50 | $wssFilter->setServiceSecurityKeyObject($securityKeyService); 51 | // TOKEN_REFERENCE_SUBJECT_KEY_IDENTIFIER | TOKEN_REFERENCE_SECURITY_TOKEN | TOKEN_REFERENCE_THUMBPRINT_SHA1 52 | $wssFilter->setSecurityOptionsSignature(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_SECURITY_TOKEN); 53 | $wssFilter->setSecurityOptionsEncryption(BeSimpleWsSecurityFilter::TOKEN_REFERENCE_THUMBPRINT_SHA1); 54 | 55 | $soapKernel = $sc->getSoapKernel(); 56 | $soapKernel->registerFilter($wssFilter); 57 | 58 | $gb = new getBook(); 59 | $gb->isbn = '0061020052'; 60 | $result = $sc->getBook($gb); 61 | $this->assertInstanceOf('BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', $result->getBookReturn); 62 | 63 | $ab = new addBook(); 64 | $ab->isbn = '0445203498'; 65 | $ab->title = 'The Dragon Never Sleeps'; 66 | $ab->author = 'Cook, Glen'; 67 | $ab->type = 'scifi'; 68 | 69 | $this->assertTrue((bool) $sc->addBook($ab)); 70 | 71 | // getBooksByType("scifi"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Tests/ServerInterop/WsSecurityUserPassServer.php: -------------------------------------------------------------------------------- 1 | SOAP_1_1, 19 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 20 | 'cache_wsdl' => WSDL_CACHE_NONE, 21 | 'classmap' => array( 22 | 'getBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBook', 23 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBookResponse', 24 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByType', 25 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByTypeResponse', 26 | 'addBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBook', 27 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBookResponse', 28 | 'BookInformation' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', 29 | ), 30 | ); 31 | 32 | class Auth 33 | { 34 | public static function usernamePasswordCallback($user) 35 | { 36 | if ($user == 'libuser') { 37 | return 'books'; 38 | } 39 | 40 | return null; 41 | } 42 | } 43 | 44 | class WsSecurityUserPassServer 45 | { 46 | public function getBook(getBook $gb) 47 | { 48 | $bi = new BookInformation(); 49 | $bi->isbn = $gb->isbn; 50 | $bi->title = 'title'; 51 | $bi->author = 'author'; 52 | $bi->type = 'scifi'; 53 | 54 | $br = new getBookResponse(); 55 | $br->getBookReturn = $bi; 56 | 57 | return $br; 58 | } 59 | 60 | public function addBook(addBook $ab) 61 | { 62 | $abr = new addBookResponse(); 63 | $abr->addBookReturn = true; 64 | 65 | return $abr; 66 | } 67 | } 68 | 69 | $ss = new BeSimpleSoapServer(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $options); 70 | 71 | $wssFilter = new BeSimpleWsSecurityFilter(); 72 | $wssFilter->setUsernamePasswordCallback(array('Auth', 'usernamePasswordCallback')); 73 | 74 | $soapKernel = $ss->getSoapKernel(); 75 | $soapKernel->registerFilter($wssFilter); 76 | 77 | $ss->setClass('WsSecurityUserPassServer'); 78 | $ss->handle(); 79 | -------------------------------------------------------------------------------- /Tests/ServerInterop/WsSecurityUserPassServerClient.php: -------------------------------------------------------------------------------- 1 | SOAP_1_2, 20 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 21 | 'trace' => true, // enables use of the methods SoapClient->__getLastRequest, SoapClient->__getLastRequestHeaders, SoapClient->__getLastResponse and SoapClient->__getLastResponseHeaders 22 | 'classmap' => array( 23 | 'getBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBook', 24 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBookResponse', 25 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByType', 26 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByTypeResponse', 27 | 'addBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBook', 28 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBookResponse', 29 | 'BookInformation' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', 30 | ), 31 | ); 32 | 33 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $options); 34 | 35 | //var_dump($sc->__getFunctions()); 36 | //var_dump($sc->__getTypes()); 37 | 38 | try { 39 | $wssFilter = new BeSimpleWsSecurityFilter(true, 600); 40 | $wssFilter->addUserData('libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST); 41 | 42 | $soapKernel = $sc->getSoapKernel(); 43 | $soapKernel->registerFilter($wssFilter); 44 | 45 | $gb = new getBook(); 46 | $gb->isbn = '0061020052'; 47 | $result = $sc->getBook($gb); 48 | var_dump($result->getBookReturn); 49 | 50 | $ab = new addBook(); 51 | $ab->isbn = '0445203498'; 52 | $ab->title = 'The Dragon Never Sleeps'; 53 | $ab->author = 'Cook, Glen'; 54 | $ab->type = 'scifi'; 55 | 56 | var_dump($sc->addBook($ab)); 57 | 58 | } catch (Exception $e) { 59 | var_dump($e); 60 | } 61 | 62 | // var_dump( 63 | // $sc->__getLastRequestHeaders(), 64 | // $sc->__getLastRequest(), 65 | // $sc->__getLastResponseHeaders(), 66 | // $sc->__getLastResponse() 67 | // ); 68 | -------------------------------------------------------------------------------- /Tests/ServerInterop/WsSecurityUserPassServerInteropTest.php: -------------------------------------------------------------------------------- 1 | SOAP_1_2, 22 | 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, // make sure that result is array for size=1 23 | 'classmap' => array( 24 | 'getBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBook', 25 | 'getBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBookResponse', 26 | 'getBooksByType' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByType', 27 | 'getBooksByTypeResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\getBooksByTypeResponse', 28 | 'addBook' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBook', 29 | 'addBookResponse' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\addBookResponse', 30 | 'BookInformation' => 'BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', 31 | ), 32 | 'proxy_host' => false, 33 | ); 34 | 35 | public function testUserPassText() 36 | { 37 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options); 38 | 39 | $wssFilter = new BeSimpleWsSecurityFilter(true, 600); 40 | $wssFilter->addUserData('libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_TEXT); 41 | 42 | $soapKernel = $sc->getSoapKernel(); 43 | $soapKernel->registerFilter($wssFilter); 44 | 45 | $gb = new getBook(); 46 | $gb->isbn = '0061020052'; 47 | $result = $sc->getBook($gb); 48 | $this->assertInstanceOf('BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', $result->getBookReturn); 49 | 50 | $ab = new addBook(); 51 | $ab->isbn = '0445203498'; 52 | $ab->title = 'The Dragon Never Sleeps'; 53 | $ab->author = 'Cook, Glen'; 54 | $ab->type = 'scifi'; 55 | 56 | $this->assertTrue((bool) $sc->addBook($ab)); 57 | 58 | // getBooksByType("scifi"); 59 | } 60 | 61 | public function testUserPassDigest() 62 | { 63 | $sc = new BeSimpleSoapClient(__DIR__.'/Fixtures/WsSecurityUserPass.wsdl', $this->options); 64 | 65 | $wssFilter = new BeSimpleWsSecurityFilter(true, 600); 66 | $wssFilter->addUserData( 'libuser', 'books', BeSimpleWsSecurityFilter::PASSWORD_TYPE_DIGEST ); 67 | 68 | $soapKernel = $sc->getSoapKernel(); 69 | $soapKernel->registerFilter($wssFilter); 70 | 71 | $gb = new getBook(); 72 | $gb->isbn = '0061020052'; 73 | $result = $sc->getBook($gb); 74 | $this->assertInstanceOf('BeSimple\SoapClient\Tests\ServerInterop\Fixtures\BookInformation', $result->getBookReturn); 75 | 76 | $ab = new addBook(); 77 | $ab->isbn = '0445203498'; 78 | $ab->title = 'The Dragon Never Sleeps'; 79 | $ab->author = 'Cook, Glen'; 80 | $ab->type = 'scifi'; 81 | 82 | $this->assertTrue((bool) $sc->addBook($ab)); 83 | 84 | // getBooksByType("scifi"); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Tests/SoapClientBuilderTest.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient\Tests; 14 | 15 | use BeSimple\SoapClient\SoapClientBuilder; 16 | 17 | class SoapClientBuilderTest extends \PHPUnit_Framework_TestCase 18 | { 19 | private $defaultOptions = array( 20 | 'features' => 0, 21 | 'classmap' => array(), 22 | 'typemap' => array(), 23 | ); 24 | 25 | public function testContruct() 26 | { 27 | $options = $this 28 | ->getSoapBuilder() 29 | ->getSoapOptions() 30 | ; 31 | 32 | $this->assertEquals($this->mergeOptions(array()), $options); 33 | } 34 | 35 | public function testWithTrace() 36 | { 37 | $builder = $this->getSoapBuilder(); 38 | 39 | $builder->withTrace(); 40 | $this->assertEquals($this->mergeOptions(array('trace' => true)), $builder->getSoapOptions()); 41 | 42 | $builder->withTrace(false); 43 | $this->assertEquals($this->mergeOptions(array('trace' => false)), $builder->getSoapOptions()); 44 | } 45 | 46 | public function testWithExceptions() 47 | { 48 | $builder = $this->getSoapBuilder(); 49 | 50 | $builder->withExceptions(); 51 | $this->assertEquals($this->mergeOptions(array('exceptions' => true)), $builder->getSoapOptions()); 52 | 53 | $builder->withExceptions(false); 54 | $this->assertEquals($this->mergeOptions(array('exceptions' => false)), $builder->getSoapOptions()); 55 | } 56 | 57 | public function testWithUserAgent() 58 | { 59 | $builder = $this->getSoapBuilder(); 60 | 61 | $builder->withUserAgent('BeSimpleSoap Test'); 62 | $this->assertEquals($this->mergeOptions(array('user_agent' => 'BeSimpleSoap Test')), $builder->getSoapOptions()); 63 | } 64 | 65 | public function testWithCompression() 66 | { 67 | $builder = $this->getSoapBuilder(); 68 | 69 | $builder->withCompressionGzip(); 70 | $this->assertEquals($this->mergeOptions(array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP)), $builder->getSoapOptions()); 71 | 72 | $builder->withCompressionDeflate(); 73 | $this->assertEquals($this->mergeOptions(array('compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_DEFLATE)), $builder->getSoapOptions()); 74 | } 75 | 76 | public function testWithAuthentication() 77 | { 78 | $builder = $this->getSoapBuilder(); 79 | 80 | $builder->withDigestAuthentication(__DIR__.'/Fixtures/cert.pem', 'foobar'); 81 | $this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_DIGEST, 'local_cert' => __DIR__.'/Fixtures/cert.pem', 'passphrase' => 'foobar')), $builder->getSoapOptions()); 82 | 83 | $builder->withDigestAuthentication(__DIR__.'/Fixtures/cert.pem'); 84 | $this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_DIGEST, 'local_cert' => __DIR__.'/Fixtures/cert.pem')), $builder->getSoapOptions()); 85 | 86 | $builder->withBasicAuthentication('foo', 'bar'); 87 | $this->assertEquals($this->mergeOptions(array('authentication' => SOAP_AUTHENTICATION_BASIC, 'login' => 'foo', 'password' => 'bar')), $builder->getSoapOptions()); 88 | } 89 | 90 | public function testWithProxy() 91 | { 92 | $builder = $this->getSoapBuilder(); 93 | 94 | $builder->withProxy('localhost', 8080); 95 | $this->assertEquals($this->mergeOptions(array('proxy_host' => 'localhost', 'proxy_port' => 8080)), $builder->getSoapOptions()); 96 | 97 | $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar'); 98 | $this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar')), $builder->getSoapOptions()); 99 | 100 | $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', \CURLAUTH_BASIC); 101 | $this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar', 'proxy_auth' => \CURLAUTH_BASIC)), $builder->getSoapOptions()); 102 | 103 | $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', \CURLAUTH_NTLM); 104 | $this->assertEquals($this->mergeOptions(array('proxy_host' => '127.0.0.1', 'proxy_port' => 8585, 'proxy_login' => 'foo', 'proxy_password' => 'bar', 'proxy_auth' => \CURLAUTH_NTLM)), $builder->getSoapOptions()); 105 | 106 | try { 107 | $builder->withProxy('127.0.0.1', 8585, 'foo', 'bar', -100); 108 | 109 | $this->fail('An expected exception has not been raised.'); 110 | } catch (\Exception $e) { 111 | $this->assertInstanceOf('InvalidArgumentException', $e); 112 | } 113 | } 114 | 115 | public function testCreateWithDefaults() 116 | { 117 | $builder = SoapClientBuilder::createWithDefaults(); 118 | 119 | $this->assertInstanceOf('BeSimple\SoapClient\SoapClientBuilder', $builder); 120 | 121 | $this->assertEquals($this->mergeOptions(array('soap_version' => SOAP_1_2, 'encoding' => 'UTF-8', 'features' => SOAP_SINGLE_ELEMENT_ARRAYS, 'user_agent' => 'BeSimpleSoap')), $builder->getSoapOptions()); 122 | } 123 | 124 | private function getSoapBuilder() 125 | { 126 | return new SoapClientBuilder(); 127 | } 128 | 129 | private function mergeOptions(array $options) 130 | { 131 | return array_merge($this->defaultOptions, $options); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Tests/bin/axis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 4 | cd $DIR 5 | 6 | VERSION_AXIS=1.5.1 7 | ZIP_AXIS=axis2-$VERSION_AXIS-bin.zip 8 | if [[ "$VERSION_AXIS" > "1.5.1" ]]; then 9 | PATH_AXIS=http://archive.apache.org/dist/axis/axis2/java/core/$VERSION_AXIS/$ZIP_AXIS 10 | else 11 | PATH_AXIS=http://archive.apache.org/dist/ws/axis2/${VERSION_AXIS//./_}/$ZIP_AXIS 12 | fi 13 | 14 | if [ ! -f "$DIR/$ZIP_AXIS" ]; then 15 | curl -O -s $PATH_AXIS 16 | fi 17 | 18 | VERSION_RAMPART=1.5 19 | ZIP_RAMPART=rampart-dist-$VERSION_RAMPART-bin.zip 20 | PATH_RAMPART=http://archive.apache.org/dist/axis/axis2/java/rampart/$VERSION_RAMPART/$ZIP_RAMPART 21 | 22 | if [ ! -f "$DIR/$ZIP_RAMPART" ]; then 23 | curl -O -s $PATH_RAMPART 24 | fi 25 | 26 | unzip -o -qq "$DIR/$ZIP_AXIS" 27 | 28 | AXIS_DIR=$DIR/axis2-$VERSION_AXIS 29 | 30 | unzip -o -qq -j "$DIR/$ZIP_RAMPART" '*/lib/*.jar' -d $AXIS_DIR/lib 31 | unzip -o -qq -j "$DIR/$ZIP_RAMPART" '*/modules/*.mar' -d $AXIS_DIR/repository/modules 32 | 33 | cp -r $DIR/../AxisInterop/axis_services/* $AXIS_DIR/repository/services 34 | 35 | $AXIS_DIR/bin/axis2server.sh& 36 | 37 | echo "Waiting until Axis is ready on port 8080" 38 | while [[ -z `curl -s 'http://localhost:8080/axis2/services/' ` ]] 39 | do 40 | echo -n "." 41 | sleep 2s 42 | done 43 | 44 | echo "Axis is up" -------------------------------------------------------------------------------- /Tests/bin/phpwebserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PHPWEBSERVEROK="$( php -r "if (version_compare(phpversion(), '5.4', '<')) { echo 'nok'; } else { echo 'ok'; }" )" 4 | 5 | if [ "$PHPWEBSERVEROK" != "ok" ]; then 6 | echo "No PHP webserver available before version 5.4..." 7 | exit 8 | fi 9 | 10 | DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 11 | cd $DIR 12 | 13 | php -S localhost:8081 -t "$DIR/.."& 14 | 15 | echo "Waiting until PHP webserver is ready on port 8081" 16 | while [[ -z `curl -s 'http://localhost:8081' ` ]] 17 | do 18 | echo -n "." 19 | sleep 2s 20 | done 21 | 22 | echo "PHP webserver is up" -------------------------------------------------------------------------------- /WsAddressingFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\FilterHelper; 16 | use BeSimple\SoapCommon\Helper; 17 | use BeSimple\SoapCommon\SoapRequest as CommonSoapRequest; 18 | use BeSimple\SoapCommon\SoapRequestFilter; 19 | use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse; 20 | use BeSimple\SoapCommon\SoapResponseFilter; 21 | 22 | /** 23 | * This plugin implements a subset of the following standards: 24 | * * Web Services Addressing 1.0 - Core 25 | * http://www.w3.org/TR/2006/REC-ws-addr-core 26 | * * Web Services Addressing 1.0 - SOAP Binding 27 | * http://www.w3.org/TR/ws-addr-soap 28 | * 29 | * Per default this plugin uses the SoapClient's $action and $location values 30 | * for wsa:Action and wsa:To. Therefore the only REQUIRED property 'wsa:Action' 31 | * is always set automatically. 32 | * 33 | * Limitation: wsa:From, wsa:FaultTo and wsa:ReplyTo only support the 34 | * wsa:Address element of the endpoint reference at the moment. 35 | * 36 | * @author Andreas Schamberger 37 | */ 38 | class WsAddressingFilter implements SoapRequestFilter, SoapResponseFilter 39 | { 40 | /** 41 | * (2.1) Endpoint reference (EPR) anonymous default address. 42 | * 43 | * Some endpoints cannot be located with a meaningful IRI; this URI is used 44 | * to allow such endpoints to send and receive messages. The precise meaning 45 | * of this URI is defined by the binding of Addressing to a specific 46 | * protocol and/or the context in which the EPR is used. 47 | * 48 | * @see http://www.w3.org/TR/2006/REC-ws-addr-core-20060509/#predefaddr 49 | */ 50 | const ENDPOINT_REFERENCE_ANONYMOUS = 'http://www.w3.org/2005/08/addressing/anonymous'; 51 | 52 | /** 53 | * (2.1) Endpoint reference (EPR) address for discarting messages. 54 | * 55 | * Messages sent to EPRs whose [address] is this value MUST be discarded 56 | * (i.e. not sent). This URI is typically used in EPRs that designate a 57 | * reply or fault endpoint (see section 3.1 Abstract Property Definitions) 58 | * to indicate that no reply or fault message should be sent. 59 | * 60 | * @see http://www.w3.org/TR/2006/REC-ws-addr-core-20060509/#predefaddr 61 | */ 62 | const ENDPOINT_REFERENCE_NONE = 'http://www.w3.org/2005/08/addressing/none'; 63 | 64 | /** 65 | * (3.1) Predefined value for reply. 66 | * 67 | * Indicates that this is a reply to the message identified by the [message id] IRI. 68 | * 69 | * see http://www.w3.org/TR/2006/REC-ws-addr-core-20060509/#predefrels 70 | */ 71 | const RELATIONSHIP_TYPE_REPLY = 'http://www.w3.org/2005/08/addressing/reply'; 72 | 73 | /** 74 | * FaultTo. 75 | * 76 | * @var string 77 | */ 78 | protected $faultTo; 79 | 80 | /** 81 | * From. 82 | * 83 | * @var string 84 | */ 85 | protected $from; 86 | 87 | /** 88 | * MessageId. 89 | * 90 | * @var string 91 | */ 92 | protected $messageId; 93 | 94 | /** 95 | * List of reference parameters associated with this soap message. 96 | * 97 | * @var unknown_type 98 | */ 99 | protected $referenceParametersSet = array(); 100 | 101 | /** 102 | * List of reference parameters recieved with this soap message. 103 | * 104 | * @var unknown_type 105 | */ 106 | protected $referenceParametersRecieved = array(); 107 | 108 | /** 109 | * RelatesTo. 110 | * 111 | * @var string 112 | */ 113 | protected $relatesTo; 114 | 115 | /** 116 | * RelatesTo@RelationshipType. 117 | * 118 | * @var string 119 | */ 120 | protected $relatesToRelationshipType; 121 | 122 | /** 123 | * ReplyTo. 124 | * 125 | * @var string 126 | */ 127 | protected $replyTo; 128 | 129 | /** 130 | * Add additional reference parameters 131 | * 132 | * @param string $ns Namespace URI 133 | * @param string $pfx Namespace prefix 134 | * @param string $parameter Parameter name 135 | * @param string $value Parameter value 136 | * 137 | * @return void 138 | */ 139 | public function addReferenceParameter($ns, $pfx, $parameter, $value) 140 | { 141 | $this->referenceParametersSet[] = array( 142 | 'ns' => $ns, 143 | 'pfx' => $pfx, 144 | 'parameter' => $parameter, 145 | 'value' => $value, 146 | ); 147 | } 148 | 149 | /** 150 | * Get additional reference parameters. 151 | * 152 | * @param string $ns Namespace URI 153 | * @param string $parameter Parameter name 154 | * 155 | * @return string|null 156 | */ 157 | public function getReferenceParameter($ns, $parameter) 158 | { 159 | if (isset($this->referenceParametersRecieved[$ns][$parameter])) { 160 | 161 | return $this->referenceParametersRecieved[$ns][$parameter]; 162 | } 163 | 164 | return null; 165 | } 166 | 167 | /** 168 | * Reset all properties to default values. 169 | */ 170 | public function resetFilter() 171 | { 172 | $this->faultTo = null; 173 | $this->from = null; 174 | $this->messageId = null; 175 | $this->referenceParametersRecieved = array(); 176 | $this->referenceParametersSet = array(); 177 | $this->relatesTo = null; 178 | $this->relatesToRelationshipType = null; 179 | $this->replyTo = null; 180 | } 181 | 182 | /** 183 | * Set FaultTo address of type xs:anyURI. 184 | * 185 | * @param string $faultTo xs:anyURI 186 | * 187 | * @return void 188 | */ 189 | public function setFaultTo($faultTo) 190 | { 191 | $this->faultTo = $faultTo; 192 | } 193 | 194 | /** 195 | * Set From address of type xs:anyURI. 196 | * 197 | * @param string $from xs:anyURI 198 | * 199 | * @return void 200 | */ 201 | public function setFrom($from) 202 | { 203 | $this->from = $from; 204 | } 205 | 206 | /** 207 | * Set MessageId of type xs:anyURI. 208 | * Default: UUID v4 e.g. 'uuid:550e8400-e29b-11d4-a716-446655440000' 209 | * 210 | * @param string $messageId xs:anyURI 211 | * 212 | * @return void 213 | */ 214 | public function setMessageId($messageId = null) 215 | { 216 | if (null === $messageId) { 217 | $messageId = 'uuid:' . Helper::generateUUID(); 218 | } 219 | $this->messageId = $messageId; 220 | } 221 | 222 | /** 223 | * Set RelatesTo of type xs:anyURI with the optional relationType 224 | * (of type xs:anyURI). 225 | * 226 | * @param string $relatesTo xs:anyURI 227 | * @param string $relationType xs:anyURI 228 | * 229 | * @return void 230 | */ 231 | public function setRelatesTo($relatesTo, $relationType = null) 232 | { 233 | $this->relatesTo = $relatesTo; 234 | if (null !== $relationType && $relationType != self::RELATIONSHIP_TYPE_REPLY) { 235 | $this->relatesToRelationshipType = $relationType; 236 | } 237 | } 238 | 239 | /** 240 | * Set ReplyTo address of type xs:anyURI 241 | * Default: self::ENDPOINT_REFERENCE_ANONYMOUS 242 | * 243 | * @param string $replyTo xs:anyURI 244 | * 245 | * @return void 246 | */ 247 | public function setReplyTo($replyTo = null) 248 | { 249 | if (null === $replyTo) { 250 | $replyTo = self::ENDPOINT_REFERENCE_ANONYMOUS; 251 | } 252 | $this->replyTo = $replyTo; 253 | } 254 | 255 | /** 256 | * Modify the given request XML. 257 | * 258 | * @param \BeSimple\SoapCommon\SoapRequest $request SOAP request 259 | * 260 | * @return void 261 | */ 262 | public function filterRequest(CommonSoapRequest $request) 263 | { 264 | // get \DOMDocument from SOAP request 265 | $dom = $request->getContentDocument(); 266 | 267 | // create FilterHelper 268 | $filterHelper = new FilterHelper($dom); 269 | 270 | // add the neccessary namespaces 271 | $filterHelper->addNamespace(Helper::PFX_WSA, Helper::NS_WSA); 272 | 273 | $action = $filterHelper->createElement(Helper::NS_WSA, 'Action', $request->getAction()); 274 | $filterHelper->addHeaderElement($action); 275 | 276 | $to = $filterHelper->createElement(Helper::NS_WSA, 'To', $request->getLocation()); 277 | $filterHelper->addHeaderElement($to); 278 | 279 | if (null !== $this->faultTo) { 280 | $faultTo = $filterHelper->createElement(Helper::NS_WSA, 'FaultTo'); 281 | $filterHelper->addHeaderElement($faultTo); 282 | 283 | $address = $filterHelper->createElement(Helper::NS_WSA, 'Address', $this->faultTo); 284 | $faultTo->appendChild($address); 285 | } 286 | 287 | if (null !== $this->from) { 288 | $from = $filterHelper->createElement(Helper::NS_WSA, 'From'); 289 | $filterHelper->addHeaderElement($from); 290 | 291 | $address = $filterHelper->createElement(Helper::NS_WSA, 'Address', $this->from); 292 | $from->appendChild($address); 293 | } 294 | 295 | if (null !== $this->messageId) { 296 | $messageId = $filterHelper->createElement(Helper::NS_WSA, 'MessageID', $this->messageId); 297 | $filterHelper->addHeaderElement($messageId); 298 | } 299 | 300 | if (null !== $this->relatesTo) { 301 | $relatesTo = $filterHelper->createElement(Helper::NS_WSA, 'RelatesTo', $this->relatesTo); 302 | if (null !== $this->relatesToRelationshipType) { 303 | $filterHelper->setAttribute($relatesTo, Helper::NS_WSA, 'RelationshipType', $this->relatesToRelationshipType); 304 | } 305 | $filterHelper->addHeaderElement($relatesTo); 306 | } 307 | 308 | if (null !== $this->replyTo) { 309 | $replyTo = $filterHelper->createElement(Helper::NS_WSA, 'ReplyTo'); 310 | $filterHelper->addHeaderElement($replyTo); 311 | 312 | $address = $filterHelper->createElement(Helper::NS_WSA, 'Address', $this->replyTo); 313 | $replyTo->appendChild($address); 314 | } 315 | 316 | foreach ($this->referenceParametersSet as $rp) { 317 | $filterHelper->addNamespace($rp['pfx'], $rp['ns']); 318 | $parameter = $filterHelper->createElement($rp['ns'], $rp['parameter'], $rp['value']); 319 | $filterHelper->setAttribute($parameter, Helper::NS_WSA, 'IsReferenceParameter', 'true'); 320 | $filterHelper->addHeaderElement($parameter); 321 | } 322 | } 323 | 324 | /** 325 | * Modify the given response XML. 326 | * 327 | * @param \BeSimple\SoapCommon\SoapResponse $response SOAP response 328 | * 329 | * @return void 330 | */ 331 | public function filterResponse(CommonSoapResponse $response) 332 | { 333 | // get \DOMDocument from SOAP response 334 | $dom = $response->getContentDocument(); 335 | 336 | $this->referenceParametersRecieved = array(); 337 | $referenceParameters = $dom->getElementsByTagNameNS(Helper::NS_WSA, 'ReferenceParameters')->item(0); 338 | if (null !== $referenceParameters) { 339 | foreach ($referenceParameters->childNodes as $childNode) { 340 | if (!isset($this->referenceParametersRecieved[$childNode->namespaceURI])) { 341 | $this->referenceParametersRecieved[$childNode->namespaceURI] = array(); 342 | } 343 | $this->referenceParametersRecieved[$childNode->namespaceURI][$childNode->localName] = $childNode->nodeValue; 344 | } 345 | } 346 | } 347 | } -------------------------------------------------------------------------------- /WsSecurityFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use ass\XmlSecurity\DSig as XmlSecurityDSig; 16 | use ass\XmlSecurity\Enc as XmlSecurityEnc; 17 | use BeSimple\SoapCommon\FilterHelper; 18 | use BeSimple\SoapCommon\Helper; 19 | use BeSimple\SoapCommon\SoapRequest as CommonSoapRequest; 20 | use BeSimple\SoapCommon\SoapRequestFilter; 21 | use BeSimple\SoapCommon\SoapResponse as CommonSoapResponse; 22 | use BeSimple\SoapCommon\SoapResponseFilter; 23 | use BeSimple\SoapCommon\WsSecurityFilterClientServer; 24 | 25 | /** 26 | * This plugin implements a subset of the following standards: 27 | * * Web Services Security: SOAP Message Security 1.0 (WS-Security 2004) 28 | * http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0.pdf 29 | * * Web Services Security UsernameToken Profile 1.0 30 | * http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf 31 | * * Web Services Security X.509 Certificate Token Profile 32 | * http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0.pdf 33 | * 34 | * @author Andreas Schamberger 35 | */ 36 | class WsSecurityFilter extends WsSecurityFilterClientServer implements SoapRequestFilter, SoapResponseFilter 37 | { 38 | /** 39 | * (UT 3.1) Password type: plain text. 40 | */ 41 | const PASSWORD_TYPE_TEXT = 0; 42 | 43 | /** 44 | * (UT 3.1) Password type: digest. 45 | */ 46 | const PASSWORD_TYPE_DIGEST = 1; 47 | 48 | /** 49 | * (UT 3.1) Password. 50 | * 51 | * @var string 52 | */ 53 | protected $password; 54 | 55 | /** 56 | * (UT 3.1) Password type: text or digest. 57 | * 58 | * @var int 59 | */ 60 | protected $passwordType; 61 | 62 | /** 63 | * (UT 3.1) Username. 64 | * 65 | * @var string 66 | */ 67 | protected $username; 68 | 69 | /** 70 | * User WsSecurityKey. 71 | * 72 | * @var \BeSimple\SoapCommon\WsSecurityKey 73 | */ 74 | protected $userSecurityKey; 75 | 76 | /** 77 | * Add user data. 78 | * 79 | * @param string $username Username 80 | * @param string $password Password 81 | * @param int $passwordType self::PASSWORD_TYPE_DIGEST | self::PASSWORD_TYPE_TEXT 82 | * 83 | * @return void 84 | */ 85 | public function addUserData($username, $password = null, $passwordType = self::PASSWORD_TYPE_DIGEST) 86 | { 87 | $this->username = $username; 88 | $this->password = $password; 89 | $this->passwordType = $passwordType; 90 | } 91 | 92 | /** 93 | * Reset all properties to default values. 94 | */ 95 | public function resetFilter() 96 | { 97 | parent::resetFilter(); 98 | $this->password = null; 99 | $this->passwordType = null; 100 | $this->username = null; 101 | } 102 | 103 | /** 104 | * Modify the given request XML. 105 | * 106 | * @param \BeSimple\SoapCommon\SoapRequest $request SOAP request 107 | * 108 | * @return void 109 | */ 110 | public function filterRequest(CommonSoapRequest $request) 111 | { 112 | // get \DOMDocument from SOAP request 113 | $dom = $request->getContentDocument(); 114 | 115 | // create FilterHelper 116 | $filterHelper = new FilterHelper($dom); 117 | 118 | // add the neccessary namespaces 119 | $filterHelper->addNamespace(Helper::PFX_WSS, Helper::NS_WSS); 120 | $filterHelper->addNamespace(Helper::PFX_WSU, Helper::NS_WSU); 121 | $filterHelper->registerNamespace(XmlSecurityDSig::PFX_XMLDSIG, XmlSecurityDSig::NS_XMLDSIG); 122 | 123 | // init timestamp 124 | $dt = new \DateTime('now', new \DateTimeZone('UTC')); 125 | $createdTimestamp = $dt->format(self::DATETIME_FORMAT); 126 | 127 | // create security header 128 | $security = $filterHelper->createElement(Helper::NS_WSS, 'Security'); 129 | $filterHelper->addHeaderElement($security, true, $this->actor, $request->getVersion()); 130 | 131 | if (true === $this->addTimestamp || null !== $this->expires) { 132 | $timestamp = $filterHelper->createElement(Helper::NS_WSU, 'Timestamp'); 133 | $created = $filterHelper->createElement(Helper::NS_WSU, 'Created', $createdTimestamp); 134 | $timestamp->appendChild($created); 135 | if (null !== $this->expires) { 136 | $dt->modify('+' . $this->expires . ' seconds'); 137 | $expiresTimestamp = $dt->format(self::DATETIME_FORMAT); 138 | $expires = $filterHelper->createElement(Helper::NS_WSU, 'Expires', $expiresTimestamp); 139 | $timestamp->appendChild($expires); 140 | } 141 | $security->appendChild($timestamp); 142 | } 143 | 144 | if (null !== $this->username) { 145 | $usernameToken = $filterHelper->createElement(Helper::NS_WSS, 'UsernameToken'); 146 | $security->appendChild($usernameToken); 147 | 148 | $username = $filterHelper->createElement(Helper::NS_WSS, 'Username', $this->username); 149 | $usernameToken->appendChild($username); 150 | 151 | if (null !== $this->password 152 | && (null === $this->userSecurityKey 153 | || (null !== $this->userSecurityKey && !$this->userSecurityKey->hasPrivateKey()))) { 154 | 155 | if (self::PASSWORD_TYPE_DIGEST === $this->passwordType) { 156 | $nonce = mt_rand(); 157 | $password = base64_encode(sha1($nonce . $createdTimestamp . $this->password, true)); 158 | $passwordType = Helper::NAME_WSS_UTP . '#PasswordDigest'; 159 | } else { 160 | $password = $this->password; 161 | $passwordType = Helper::NAME_WSS_UTP . '#PasswordText'; 162 | } 163 | $password = $filterHelper->createElement(Helper::NS_WSS, 'Password', $password); 164 | $filterHelper->setAttribute($password, null, 'Type', $passwordType); 165 | $usernameToken->appendChild($password); 166 | if (self::PASSWORD_TYPE_DIGEST === $this->passwordType) { 167 | $nonce = $filterHelper->createElement(Helper::NS_WSS, 'Nonce', base64_encode($nonce)); 168 | $usernameToken->appendChild($nonce); 169 | 170 | $created = $filterHelper->createElement(Helper::NS_WSU, 'Created', $createdTimestamp); 171 | $usernameToken->appendChild($created); 172 | } 173 | } 174 | } 175 | 176 | if (null !== $this->userSecurityKey && $this->userSecurityKey->hasKeys()) { 177 | $guid = 'CertId-' . Helper::generateUUID(); 178 | // add token references 179 | $keyInfo = null; 180 | if (null !== $this->tokenReferenceSignature) { 181 | $keyInfo = $this->createKeyInfo($filterHelper, $this->tokenReferenceSignature, $guid, $this->userSecurityKey->getPublicKey()); 182 | } 183 | $nodes = $this->createNodeListForSigning($dom, $security); 184 | $signature = XmlSecurityDSig::createSignature($this->userSecurityKey->getPrivateKey(), XmlSecurityDSig::EXC_C14N, $security, null, $keyInfo); 185 | $options = array( 186 | 'id_ns_prefix' => Helper::PFX_WSU, 187 | 'id_prefix_ns' => Helper::NS_WSU, 188 | ); 189 | foreach ($nodes as $node) { 190 | XmlSecurityDSig::addNodeToSignature($signature, $node, XmlSecurityDSig::SHA1, XmlSecurityDSig::EXC_C14N, $options); 191 | } 192 | XmlSecurityDSig::signDocument($signature, $this->userSecurityKey->getPrivateKey(), XmlSecurityDSig::EXC_C14N); 193 | 194 | $publicCertificate = $this->userSecurityKey->getPublicKey()->getX509Certificate(true); 195 | $binarySecurityToken = $filterHelper->createElement(Helper::NS_WSS, 'BinarySecurityToken', $publicCertificate); 196 | $filterHelper->setAttribute($binarySecurityToken, null, 'EncodingType', Helper::NAME_WSS_SMS . '#Base64Binary'); 197 | $filterHelper->setAttribute($binarySecurityToken, null, 'ValueType', Helper::NAME_WSS_X509 . '#X509v3'); 198 | $filterHelper->setAttribute($binarySecurityToken, Helper::NS_WSU, 'Id', $guid); 199 | $security->insertBefore($binarySecurityToken, $signature); 200 | 201 | // encrypt soap document 202 | if (null !== $this->serviceSecurityKey && $this->serviceSecurityKey->hasKeys()) { 203 | $guid = 'EncKey-' . Helper::generateUUID(); 204 | // add token references 205 | $keyInfo = null; 206 | if (null !== $this->tokenReferenceEncryption) { 207 | $keyInfo = $this->createKeyInfo($filterHelper, $this->tokenReferenceEncryption, $guid, $this->serviceSecurityKey->getPublicKey()); 208 | } 209 | $encryptedKey = XmlSecurityEnc::createEncryptedKey($guid, $this->serviceSecurityKey->getPrivateKey(), $this->serviceSecurityKey->getPublicKey(), $security, $signature, $keyInfo); 210 | $referenceList = XmlSecurityEnc::createReferenceList($encryptedKey); 211 | // token reference to encrypted key 212 | $keyInfo = $this->createKeyInfo($filterHelper, self::TOKEN_REFERENCE_SECURITY_TOKEN, $guid); 213 | $nodes = $this->createNodeListForEncryption($dom); 214 | foreach ($nodes as $node) { 215 | $type = XmlSecurityEnc::ELEMENT; 216 | if ($node->localName == 'Body') { 217 | $type = XmlSecurityEnc::CONTENT; 218 | } 219 | XmlSecurityEnc::encryptNode($node, $type, $this->serviceSecurityKey->getPrivateKey(), $referenceList, $keyInfo); 220 | } 221 | } 222 | } 223 | } 224 | 225 | /** 226 | * Modify the given request XML. 227 | * 228 | * @param \BeSimple\SoapCommon\SoapResponse $response SOAP response 229 | * 230 | * @return void 231 | */ 232 | public function filterResponse(CommonSoapResponse $response) 233 | { 234 | // get \DOMDocument from SOAP response 235 | $dom = $response->getContentDocument(); 236 | 237 | // locate security header 238 | $security = $dom->getElementsByTagNameNS(Helper::NS_WSS, 'Security')->item(0); 239 | if (null !== $security) { 240 | // add SecurityTokenReference resolver for KeyInfo 241 | $keyResolver = array($this, 'keyInfoSecurityTokenReferenceResolver'); 242 | XmlSecurityDSig::addKeyInfoResolver(Helper::NS_WSS, 'SecurityTokenReference', $keyResolver); 243 | // do we have a reference list in header 244 | $referenceList = XmlSecurityEnc::locateReferenceList($security); 245 | // get a list of encrypted nodes 246 | $encryptedNodes = XmlSecurityEnc::locateEncryptedData($dom, $referenceList); 247 | // decrypt them 248 | if (null !== $encryptedNodes) { 249 | foreach ($encryptedNodes as $encryptedNode) { 250 | XmlSecurityEnc::decryptNode($encryptedNode); 251 | } 252 | } 253 | // locate signature node 254 | $signature = XmlSecurityDSig::locateSignature($security); 255 | if (null !== $signature) { 256 | // verify references 257 | $options = array( 258 | 'id_ns_prefix' => Helper::PFX_WSU, 259 | 'id_prefix_ns' => Helper::NS_WSU, 260 | ); 261 | if (XmlSecurityDSig::verifyReferences($signature, $options) !== true) { 262 | throw new \SoapFault('wsse:FailedCheck', 'The signature or decryption was invalid'); 263 | } 264 | // verify signature 265 | if (XmlSecurityDSig::verifyDocumentSignature($signature) !== true) { 266 | throw new \SoapFault('wsse:FailedCheck', 'The signature or decryption was invalid'); 267 | } 268 | } 269 | 270 | $security->parentNode->removeChild($security); 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /WsdlDownloader.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\Cache; 16 | use BeSimple\SoapCommon\Helper; 17 | 18 | /** 19 | * Downloads WSDL files with cURL. Uses the WSDL_CACHE_* constants and the 20 | * 'soap.wsdl_*' ini settings. Does only file caching as SoapClient only 21 | * supports a file name parameter. The class also resolves remote XML schema 22 | * includes. 23 | * 24 | * @author Andreas Schamberger 25 | */ 26 | class WsdlDownloader 27 | { 28 | /** 29 | * Cache enabled. 30 | * 31 | * @var bool 32 | */ 33 | protected $cacheEnabled; 34 | 35 | /** 36 | * Cache dir. 37 | * 38 | * @var string 39 | */ 40 | protected $cacheDir; 41 | 42 | /** 43 | * Cache TTL. 44 | * 45 | * @var int 46 | */ 47 | protected $cacheTtl; 48 | 49 | /** 50 | * cURL instance for downloads. 51 | * 52 | * @var unknown_type 53 | */ 54 | protected $curl; 55 | 56 | /** 57 | * Resolve WSDl/XSD includes. 58 | * 59 | * @var boolean 60 | */ 61 | protected $resolveRemoteIncludes = true; 62 | 63 | /** 64 | * Constructor. 65 | * 66 | * @param \BeSimple\SoapClient\Curl $curl Curl instance 67 | * @param boolean $resolveRemoteIncludes WSDL/XSD include enabled? 68 | * @param boolean $cacheWsdl Cache constant 69 | */ 70 | public function __construct(Curl $curl, $resolveRemoteIncludes = true, $cacheWsdl = Cache::TYPE_DISK) 71 | { 72 | $this->curl = $curl; 73 | $this->resolveRemoteIncludes = (Boolean) $resolveRemoteIncludes; 74 | 75 | // get current WSDL caching config 76 | $this->cacheEnabled = $cacheWsdl === Cache::TYPE_NONE ? Cache::DISABLED : Cache::ENABLED == Cache::isEnabled(); 77 | $this->cacheDir = Cache::getDirectory(); 78 | $this->cacheTtl = Cache::getLifetime(); 79 | } 80 | 81 | /** 82 | * Download given WSDL file and return name of cache file. 83 | * 84 | * @param string $wsdl WSDL file URL/path 85 | * 86 | * @return string 87 | */ 88 | public function download($wsdl) 89 | { 90 | // download and cache remote WSDL files or local ones where we want to 91 | // resolve remote XSD includes 92 | $isRemoteFile = $this->isRemoteFile($wsdl); 93 | if ($isRemoteFile || $this->resolveRemoteIncludes) { 94 | $cacheFilePath = $this->cacheDir.DIRECTORY_SEPARATOR.'wsdl_'.md5($wsdl).'.cache'; 95 | 96 | if (!$this->cacheEnabled || !file_exists($cacheFilePath) || (filemtime($cacheFilePath) + $this->cacheTtl) < time()) { 97 | if ($isRemoteFile) { 98 | // execute request 99 | $responseSuccessfull = $this->curl->exec($wsdl); 100 | // get content 101 | if ($responseSuccessfull) { 102 | $response = $this->curl->getResponseBody(); 103 | 104 | if ($this->resolveRemoteIncludes) { 105 | $this->resolveRemoteIncludes($response, $cacheFilePath, $wsdl); 106 | } else { 107 | file_put_contents($cacheFilePath, $response); 108 | } 109 | } else { 110 | throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'"); 111 | } 112 | } elseif (file_exists($wsdl)) { 113 | $response = file_get_contents($wsdl); 114 | $this->resolveRemoteIncludes($response, $cacheFilePath); 115 | } else { 116 | throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'"); 117 | } 118 | } 119 | 120 | return $cacheFilePath; 121 | } elseif (file_exists($wsdl)) { 122 | return realpath($wsdl); 123 | } 124 | 125 | throw new \ErrorException("SOAP-ERROR: Parsing WSDL: Couldn't load from '" . $wsdl ."'"); 126 | } 127 | 128 | /** 129 | * Do we have a remote file? 130 | * 131 | * @param string $file File URL/path 132 | * 133 | * @return boolean 134 | */ 135 | private function isRemoteFile($file) 136 | { 137 | // @parse_url to suppress E_WARNING for invalid urls 138 | if (false !== $url = @parse_url($file)) { 139 | if (isset($url['scheme']) && 'http' === substr($url['scheme'], 0, 4)) { 140 | return true; 141 | } 142 | } 143 | 144 | return false; 145 | } 146 | 147 | /** 148 | * Resolves remote WSDL/XSD includes within the WSDL files. 149 | * 150 | * @param string $xml XML file 151 | * @param string $cacheFilePath Cache file name 152 | * @param boolean $parentFilePath Parent file name 153 | * 154 | * @return void 155 | */ 156 | private function resolveRemoteIncludes($xml, $cacheFilePath, $parentFilePath = null) 157 | { 158 | $doc = new \DOMDocument(); 159 | $doc->loadXML($xml); 160 | 161 | $xpath = new \DOMXPath($doc); 162 | $xpath->registerNamespace(Helper::PFX_XML_SCHEMA, Helper::NS_XML_SCHEMA); 163 | $xpath->registerNamespace(Helper::PFX_WSDL, Helper::NS_WSDL); 164 | 165 | // WSDL include/import 166 | $query = './/'.Helper::PFX_WSDL.':include | .//'.Helper::PFX_WSDL.':import'; 167 | $nodes = $xpath->query($query); 168 | if ($nodes->length > 0) { 169 | foreach ($nodes as $node) { 170 | $location = $node->getAttribute('location'); 171 | if ($this->isRemoteFile($location)) { 172 | $location = $this->download($location); 173 | $node->setAttribute('location', $location); 174 | } elseif (null !== $parentFilePath) { 175 | $location = $this->resolveRelativePathInUrl($parentFilePath, $location); 176 | $location = $this->download($location); 177 | $node->setAttribute('location', $location); 178 | } 179 | } 180 | } 181 | 182 | // XML schema include/import 183 | $query = './/'.Helper::PFX_XML_SCHEMA.':include | .//'.Helper::PFX_XML_SCHEMA.':import'; 184 | $nodes = $xpath->query($query); 185 | if ($nodes->length > 0) { 186 | foreach ($nodes as $node) { 187 | if ($node->hasAttribute('schemaLocation')) { 188 | $schemaLocation = $node->getAttribute('schemaLocation'); 189 | if ($this->isRemoteFile($schemaLocation)) { 190 | $schemaLocation = $this->download($schemaLocation); 191 | $node->setAttribute('schemaLocation', $schemaLocation); 192 | } elseif (null !== $parentFilePath) { 193 | $schemaLocation = $this->resolveRelativePathInUrl($parentFilePath, $schemaLocation); 194 | $schemaLocation = $this->download($schemaLocation); 195 | $node->setAttribute('schemaLocation', $schemaLocation); 196 | } 197 | } 198 | } 199 | } 200 | 201 | $doc->save($cacheFilePath); 202 | } 203 | 204 | /** 205 | * Resolves the relative path to base into an absolute. 206 | * 207 | * @param string $base Base path 208 | * @param string $relative Relative path 209 | * 210 | * @return string 211 | */ 212 | private function resolveRelativePathInUrl($base, $relative) 213 | { 214 | $urlParts = parse_url($base); 215 | 216 | // combine base path with relative path 217 | if (isset($urlParts['path']) && '/' === $relative{0}) { 218 | // $relative is absolute path from domain (starts with /) 219 | $path = $relative; 220 | } elseif (isset($urlParts['path']) && strrpos($urlParts['path'], '/') === (strlen($urlParts['path']) )) { 221 | // base path is directory 222 | $path = $urlParts['path'].$relative; 223 | } elseif (isset($urlParts['path'])) { 224 | // strip filename from base path 225 | $path = substr($urlParts['path'], 0, strrpos($urlParts['path'], '/')).'/'.$relative; 226 | } else { 227 | // no base path 228 | $path = '/'.$relative; 229 | } 230 | 231 | // foo/./bar ==> foo/bar 232 | // remove double slashes 233 | $path = preg_replace(array('#/\./#', '#/+#'), '/', $path); 234 | 235 | // split path by '/' 236 | $parts = explode('/', $path); 237 | 238 | // resolve /../ 239 | foreach ($parts as $key => $part) { 240 | if ('..' === $part) { 241 | $keyToDelete = $key - 1; 242 | 243 | while ($keyToDelete > 0) { 244 | if (isset($parts[$keyToDelete])) { 245 | unset($parts[$keyToDelete]); 246 | 247 | break; 248 | } 249 | 250 | $keyToDelete--; 251 | } 252 | 253 | unset($parts[$key]); 254 | } 255 | } 256 | 257 | $hostname = $urlParts['scheme'].'://'.$urlParts['host']; 258 | if (isset($urlParts['port'])) { 259 | $hostname .= ':'.$urlParts['port']; 260 | } 261 | 262 | return $hostname.implode('/', $parts); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /XmlMimeFilter.php: -------------------------------------------------------------------------------- 1 | 7 | * (c) Francis Besset 8 | * 9 | * This source file is subject to the MIT license that is bundled 10 | * with this source code in the file LICENSE. 11 | */ 12 | 13 | namespace BeSimple\SoapClient; 14 | 15 | use BeSimple\SoapCommon\FilterHelper; 16 | use BeSimple\SoapCommon\Helper; 17 | use BeSimple\SoapCommon\SoapRequest; 18 | use BeSimple\SoapCommon\SoapRequestFilter; 19 | 20 | /** 21 | * XML MIME filter that fixes the namespace of xmime:contentType attribute. 22 | * 23 | * @author Andreas Schamberger 24 | */ 25 | class XmlMimeFilter implements SoapRequestFilter 26 | { 27 | /** 28 | * Reset all properties to default values. 29 | */ 30 | public function resetFilter() 31 | { 32 | } 33 | 34 | /** 35 | * Modify the given request XML. 36 | * 37 | * @param \BeSimple\SoapCommon\SoapRequest $request SOAP request 38 | * 39 | * @return void 40 | */ 41 | public function filterRequest(SoapRequest $request) 42 | { 43 | // get \DOMDocument from SOAP request 44 | $dom = $request->getContentDocument(); 45 | 46 | // create FilterHelper 47 | $filterHelper = new FilterHelper($dom); 48 | 49 | // add the neccessary namespaces 50 | $filterHelper->addNamespace(Helper::PFX_XMLMIME, Helper::NS_XMLMIME); 51 | 52 | // get xsd:base64binary elements 53 | $xpath = new \DOMXPath($dom); 54 | $xpath->registerNamespace('XOP', Helper::NS_XOP); 55 | $query = '//XOP:Include/..'; 56 | $nodes = $xpath->query($query); 57 | 58 | // exchange attributes 59 | if ($nodes->length > 0) { 60 | foreach ($nodes as $node) { 61 | if ($node->hasAttribute('contentType')) { 62 | $contentType = $node->getAttribute('contentType'); 63 | $node->removeAttribute('contentType'); 64 | $filterHelper->setAttribute($node, Helper::NS_XMLMIME, 'contentType', $contentType); 65 | } 66 | } 67 | } 68 | 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "besimple/soap-client", 3 | "type": "library", 4 | "description": "Build and consume SOAP Client based web services", 5 | "keywords": [ "soap", "soap-client" ], 6 | "homepage": "https://github.com/BeSimple/BeSimpleSoapClient", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Francis Besset", 11 | "email": "francis.besset@gmail.com" 12 | }, 13 | { 14 | "name": "Christian Kerl", 15 | "email": "christian-kerl@web.de" 16 | }, 17 | { 18 | "name": "Andreas Schamberger", 19 | "email": "mail@andreass.net" 20 | } 21 | ], 22 | "require": { 23 | "php": ">=5.3.0", 24 | "ext-soap": "*", 25 | "ext-curl": "*", 26 | "besimple/soap-common": "0.3.*", 27 | "ass/xmlsecurity": "~1.0" 28 | }, 29 | "require-dev": { 30 | "mikey179/vfsStream": "~1.0", 31 | "symfony/filesystem": "~2.3", 32 | "symfony/process": "~2.3" 33 | }, 34 | "autoload": { 35 | "psr-0": { "BeSimple\\SoapClient": "" } 36 | }, 37 | "target-dir": "BeSimple/SoapClient", 38 | "extra": { 39 | "branch-alias": { 40 | "dev-master": "0.3-dev" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ./Tests/ 22 | 23 | 24 | 25 | 26 | 27 | ./ 28 | 29 | ./Tests/ 30 | ./vendor/ 31 | 32 | 33 | 34 | 35 | --------------------------------------------------------------------------------