1 | <?php |
---|
2 | /** |
---|
3 | * This file contains the code for the SOAP client. |
---|
4 | * |
---|
5 | * PHP versions 4 and 5 |
---|
6 | * |
---|
7 | * LICENSE: This source file is subject to version 2.02 of the PHP license, |
---|
8 | * that is bundled with this package in the file LICENSE, and is available at |
---|
9 | * through the world-wide-web at http://www.php.net/license/2_02.txt. If you |
---|
10 | * did not receive a copy of the PHP license and are unable to obtain it |
---|
11 | * through the world-wide-web, please send a note to license@php.net so we can |
---|
12 | * mail you a copy immediately. |
---|
13 | * |
---|
14 | * @category Web Services |
---|
15 | * @package SOAP |
---|
16 | * @author Dietrich Ayala <dietrich@ganx4.com> Original Author |
---|
17 | * @author Shane Caraveo <Shane@Caraveo.com> Port to PEAR and more |
---|
18 | * @author Chuck Hagenbuch <chuck@horde.org> Maintenance |
---|
19 | * @author Jan Schneider <jan@horde.org> Maintenance |
---|
20 | * @copyright 2003-2005 The PHP Group |
---|
21 | * @license http://www.php.net/license/2_02.txt PHP License 2.02 |
---|
22 | * @link http://pear.php.net/package/SOAP |
---|
23 | */ |
---|
24 | |
---|
25 | /** SOAP_Value */ |
---|
26 | require_once 'SOAP/Value.php'; |
---|
27 | require_once 'SOAP/Base.php'; |
---|
28 | require_once 'SOAP/Transport.php'; |
---|
29 | require_once 'SOAP/WSDL.php'; |
---|
30 | require_once 'SOAP/Fault.php'; |
---|
31 | require_once 'SOAP/Parser.php'; |
---|
32 | |
---|
33 | // Arnaud: the following code was taken from DataObject and adapted to suit |
---|
34 | |
---|
35 | // this will be horrifically slow!!!! |
---|
36 | // NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer |
---|
37 | // these two are BC/FC handlers for call in PHP4/5 |
---|
38 | |
---|
39 | /** |
---|
40 | * @package SOAP |
---|
41 | */ |
---|
42 | if (!class_exists('SOAP_Client_Overload')) { |
---|
43 | if (substr(zend_version(), 0, 1) > 1) { |
---|
44 | class SOAP_Client_Overload extends SOAP_Base { |
---|
45 | function __call($method, $args) |
---|
46 | { |
---|
47 | $return = null; |
---|
48 | $this->_call($method, $args, $return); |
---|
49 | return $return; |
---|
50 | } |
---|
51 | } |
---|
52 | } else { |
---|
53 | if (!function_exists('clone')) { |
---|
54 | eval('function clone($t) { return $t; }'); |
---|
55 | } |
---|
56 | eval(' |
---|
57 | class SOAP_Client_Overload extends SOAP_Base { |
---|
58 | function __call($method, $args, &$return) |
---|
59 | { |
---|
60 | return $this->_call($method, $args, $return); |
---|
61 | } |
---|
62 | }'); |
---|
63 | } |
---|
64 | } |
---|
65 | |
---|
66 | /** |
---|
67 | * SOAP Client Class |
---|
68 | * |
---|
69 | * This class is the main interface for making soap requests. |
---|
70 | * |
---|
71 | * basic usage:<code> |
---|
72 | * $soapclient = new SOAP_Client( string path [ , boolean wsdl] ); |
---|
73 | * echo $soapclient->call( string methodname [ , array parameters] ); |
---|
74 | * </code> |
---|
75 | * or, if using PHP 5+ or the overload extension:<code> |
---|
76 | * $soapclient = new SOAP_Client( string path [ , boolean wsdl] ); |
---|
77 | * echo $soapclient->methodname( [ array parameters] ); |
---|
78 | * </code> |
---|
79 | * |
---|
80 | * Originally based on SOAPx4 by Dietrich Ayala |
---|
81 | * http://dietrich.ganx4.com/soapx4 |
---|
82 | * |
---|
83 | * @access public |
---|
84 | * @package SOAP |
---|
85 | * @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates |
---|
86 | * @author Stig Bakken <ssb@fast.no> Conversion to PEAR |
---|
87 | * @author Dietrich Ayala <dietrich@ganx4.com> Original Author |
---|
88 | */ |
---|
89 | class SOAP_Client extends SOAP_Client_Overload |
---|
90 | { |
---|
91 | /** |
---|
92 | * Communication endpoint. |
---|
93 | * |
---|
94 | * Currently the following transport formats are supported: |
---|
95 | * - HTTP |
---|
96 | * - SMTP |
---|
97 | * |
---|
98 | * Example endpoints: |
---|
99 | * http://www.example.com/soap/server.php |
---|
100 | * https://www.example.com/soap/server.php |
---|
101 | * mailto:soap@example.com |
---|
102 | * |
---|
103 | * @see SOAP_Client() |
---|
104 | * @var string |
---|
105 | */ |
---|
106 | var $_endpoint = ''; |
---|
107 | |
---|
108 | /** |
---|
109 | * The SOAP PORT name that is used by the client. |
---|
110 | * |
---|
111 | * @var string |
---|
112 | */ |
---|
113 | var $_portName = ''; |
---|
114 | |
---|
115 | /** |
---|
116 | * Endpoint type e.g. 'wdsl'. |
---|
117 | * |
---|
118 | * @var string |
---|
119 | */ |
---|
120 | var $_endpointType = ''; |
---|
121 | |
---|
122 | /** |
---|
123 | * The received xml. |
---|
124 | * |
---|
125 | * @var string |
---|
126 | */ |
---|
127 | var $xml; |
---|
128 | |
---|
129 | /** |
---|
130 | * The outgoing and incoming data stream for debugging. |
---|
131 | * |
---|
132 | * @var string |
---|
133 | */ |
---|
134 | var $wire; |
---|
135 | |
---|
136 | /** |
---|
137 | * The outgoing data stream for debugging. |
---|
138 | * |
---|
139 | * @var string |
---|
140 | */ |
---|
141 | var $_last_request = null; |
---|
142 | |
---|
143 | /** |
---|
144 | * The incoming data stream for debugging. |
---|
145 | * |
---|
146 | * @var string |
---|
147 | */ |
---|
148 | var $_last_response = null; |
---|
149 | |
---|
150 | /** |
---|
151 | * Options. |
---|
152 | * |
---|
153 | * @var array |
---|
154 | */ |
---|
155 | var $_options = array('trace' => false); |
---|
156 | |
---|
157 | /** |
---|
158 | * The character encoding used for XML parser, etc. |
---|
159 | * |
---|
160 | * @var string |
---|
161 | */ |
---|
162 | var $_encoding = SOAP_DEFAULT_ENCODING; |
---|
163 | |
---|
164 | /** |
---|
165 | * The array of SOAP_Headers that we are sending. |
---|
166 | * |
---|
167 | * @var array |
---|
168 | */ |
---|
169 | var $headersOut = null; |
---|
170 | |
---|
171 | /** |
---|
172 | * The headers we recieved back in the response. |
---|
173 | * |
---|
174 | * @var array |
---|
175 | */ |
---|
176 | var $headersIn = null; |
---|
177 | |
---|
178 | /** |
---|
179 | * Options for the HTTP_Request class (see HTTP/Request.php). |
---|
180 | * |
---|
181 | * @var array |
---|
182 | */ |
---|
183 | var $_proxy_params = array(); |
---|
184 | |
---|
185 | /** |
---|
186 | * The SOAP_Transport instance. |
---|
187 | * |
---|
188 | * @var SOAP_Transport |
---|
189 | */ |
---|
190 | var $_soap_transport = null; |
---|
191 | |
---|
192 | /** |
---|
193 | * Constructor. |
---|
194 | * |
---|
195 | * @access public |
---|
196 | * |
---|
197 | * @param string $endpoint An URL. |
---|
198 | * @param boolean $wsdl Whether the endpoint is a WSDL file. |
---|
199 | * @param string $portName The service's port name to use. |
---|
200 | * @param array $proxy_params Options for the HTTP_Request class |
---|
201 | * @see HTTP_Request |
---|
202 | * @param boolean|string $cache Use WSDL caching? The cache directory if |
---|
203 | * a string. |
---|
204 | */ |
---|
205 | function SOAP_Client($endpoint, $wsdl = false, $portName = false, |
---|
206 | $proxy_params = array(), $cache = false) |
---|
207 | { |
---|
208 | parent::SOAP_Base('Client'); |
---|
209 | |
---|
210 | $this->_endpoint = $endpoint; |
---|
211 | $this->_portName = $portName; |
---|
212 | $this->_proxy_params = $proxy_params; |
---|
213 | |
---|
214 | // This hack should perhaps be removed as it might cause unexpected |
---|
215 | // behaviour. |
---|
216 | $wsdl = $wsdl |
---|
217 | ? $wsdl |
---|
218 | : strtolower(substr($endpoint, -4)) == 'wsdl'; |
---|
219 | |
---|
220 | // make values |
---|
221 | if ($wsdl) { |
---|
222 | $this->_endpointType = 'wsdl'; |
---|
223 | // instantiate wsdl class |
---|
224 | $this->_wsdl = new SOAP_WSDL($this->_endpoint, |
---|
225 | $this->_proxy_params, |
---|
226 | $cache); |
---|
227 | if ($this->_wsdl->fault) { |
---|
228 | $this->_raiseSoapFault($this->_wsdl->fault); |
---|
229 | } |
---|
230 | } |
---|
231 | } |
---|
232 | |
---|
233 | function _reset() |
---|
234 | { |
---|
235 | $this->xml = null; |
---|
236 | $this->wire = null; |
---|
237 | $this->_last_request = null; |
---|
238 | $this->_last_response = null; |
---|
239 | $this->headersIn = null; |
---|
240 | $this->headersOut = null; |
---|
241 | } |
---|
242 | |
---|
243 | /** |
---|
244 | * Sets the character encoding. |
---|
245 | * |
---|
246 | * Limited to 'UTF-8', 'US_ASCII' and 'ISO-8859-1'. |
---|
247 | * |
---|
248 | * @access public |
---|
249 | * |
---|
250 | * @param string encoding |
---|
251 | * |
---|
252 | * @return mixed SOAP_Fault on error. |
---|
253 | */ |
---|
254 | function setEncoding($encoding) |
---|
255 | { |
---|
256 | if (in_array($encoding, $this->_encodings)) { |
---|
257 | $this->_encoding = $encoding; |
---|
258 | return; |
---|
259 | } |
---|
260 | return $this->_raiseSoapFault('Invalid Encoding'); |
---|
261 | } |
---|
262 | |
---|
263 | /** |
---|
264 | * Adds a header to the envelope. |
---|
265 | * |
---|
266 | * @access public |
---|
267 | * |
---|
268 | * @param SOAP_Header $soap_value A SOAP_Header or an array with the |
---|
269 | * elements 'name', 'namespace', |
---|
270 | * 'mustunderstand', and 'actor' to send |
---|
271 | * as a header. |
---|
272 | */ |
---|
273 | function addHeader($soap_value) |
---|
274 | { |
---|
275 | // Add a new header to the message. |
---|
276 | if (is_a($soap_value, 'SOAP_Header')) { |
---|
277 | $this->headersOut[] = $soap_value; |
---|
278 | } elseif (is_array($soap_value)) { |
---|
279 | // name, value, namespace, mustunderstand, actor |
---|
280 | $this->headersOut[] = new SOAP_Header($soap_value[0], |
---|
281 | null, |
---|
282 | $soap_value[1], |
---|
283 | $soap_value[2], |
---|
284 | $soap_value[3]); |
---|
285 | } else { |
---|
286 | $this->_raiseSoapFault('Invalid parameter provided to addHeader(). Must be an array or a SOAP_Header.'); |
---|
287 | } |
---|
288 | } |
---|
289 | |
---|
290 | /** |
---|
291 | * Calls a method on the SOAP endpoint. |
---|
292 | * |
---|
293 | * The namespace parameter is overloaded to accept an array of options |
---|
294 | * that can contain data necessary for various transports if it is used as |
---|
295 | * an array, it MAY contain a namespace value and a soapaction value. If |
---|
296 | * it is overloaded, the soapaction parameter is ignored and MUST be |
---|
297 | * placed in the options array. This is done to provide backwards |
---|
298 | * compatibility with current clients, but may be removed in the future. |
---|
299 | * The currently supported values are: |
---|
300 | * - 'namespace' |
---|
301 | * - 'soapaction' |
---|
302 | * - 'timeout': HTTP socket timeout |
---|
303 | * - 'transfer-encoding': SMTP transport, Content-Transfer-Encoding: header |
---|
304 | * - 'from': SMTP transport, From: header |
---|
305 | * - 'subject': SMTP transport, Subject: header |
---|
306 | * - 'headers': SMTP transport, hash of extra SMTP headers |
---|
307 | * - 'attachments': what encoding to use for attachments (Mime, Dime) |
---|
308 | * - 'trace': whether to trace the SOAP communication |
---|
309 | * - 'style': 'document' or 'rpc'; when set to 'document' the parameters |
---|
310 | * are not wrapped inside a tag with the SOAP action name |
---|
311 | * - 'use': 'literal' for literal encoding, anything else for section 5 |
---|
312 | * encoding; when set to 'literal' SOAP types will be omitted. |
---|
313 | * - 'keep_arrays_flat': use the tag name multiple times for each element |
---|
314 | * when passing in an array in literal mode |
---|
315 | * - 'no_type_prefix': supress adding of the namespace prefix |
---|
316 | * |
---|
317 | * @access public |
---|
318 | * |
---|
319 | * @param string $method The method to call. |
---|
320 | * @param array $params The method parameters. |
---|
321 | * @param string|array $namespace Namespace or hash with options. Note: |
---|
322 | * most options need to be repeated for |
---|
323 | * SOAP_Value instances. |
---|
324 | * @param string $soapAction |
---|
325 | * |
---|
326 | * @return mixed The method result or a SOAP_Fault on error. |
---|
327 | */ |
---|
328 | function call($method, $params, $namespace = false, $soapAction = false) |
---|
329 | { |
---|
330 | $this->headersIn = null; |
---|
331 | $this->_last_request = null; |
---|
332 | $this->_last_response = null; |
---|
333 | $this->wire = null; |
---|
334 | $this->xml = null; |
---|
335 | |
---|
336 | $soap_data = $this->_generate($method, $params, $namespace, $soapAction); |
---|
337 | if (PEAR::isError($soap_data)) { |
---|
338 | $fault = $this->_raiseSoapFault($soap_data); |
---|
339 | return $fault; |
---|
340 | } |
---|
341 | |
---|
342 | // _generate() may have changed the endpoint if the WSDL has more |
---|
343 | // than one service, so we need to see if we need to generate a new |
---|
344 | // transport to hook to a different URI. Since the transport protocol |
---|
345 | // can also change, we need to get an entirely new object. This could |
---|
346 | // probably be optimized. |
---|
347 | if (!$this->_soap_transport || |
---|
348 | $this->_endpoint != $this->_soap_transport->url) { |
---|
349 | $this->_soap_transport = SOAP_Transport::getTransport($this->_endpoint); |
---|
350 | if (PEAR::isError($this->_soap_transport)) { |
---|
351 | $fault = $this->_raiseSoapFault($this->_soap_transport); |
---|
352 | $this->_soap_transport = null; |
---|
353 | return $fault; |
---|
354 | } |
---|
355 | } |
---|
356 | $this->_soap_transport->encoding = $this->_encoding; |
---|
357 | |
---|
358 | // Send the message. |
---|
359 | $transport_options = array_merge_recursive($this->_proxy_params, |
---|
360 | $this->_options); |
---|
361 | $this->xml = $this->_soap_transport->send($soap_data, $transport_options); |
---|
362 | |
---|
363 | // Save the wire information for debugging. |
---|
364 | if ($this->_options['trace']) { |
---|
365 | $this->_last_request = $this->_soap_transport->outgoing_payload; |
---|
366 | $this->_last_response = $this->_soap_transport->incoming_payload; |
---|
367 | $this->wire = $this->getWire(); |
---|
368 | } |
---|
369 | if ($this->_soap_transport->fault) { |
---|
370 | $fault = $this->_raiseSoapFault($this->xml); |
---|
371 | return $fault; |
---|
372 | } |
---|
373 | |
---|
374 | if (isset($this->_options['result']) && |
---|
375 | $this->_options['result'] != 'parse') { |
---|
376 | return $this->xml; |
---|
377 | } |
---|
378 | |
---|
379 | $this->__result_encoding = $this->_soap_transport->result_encoding; |
---|
380 | |
---|
381 | $result = $this->parseResponse($this->xml, $this->__result_encoding, |
---|
382 | $this->_soap_transport->attachments); |
---|
383 | return $result; |
---|
384 | } |
---|
385 | |
---|
386 | /** |
---|
387 | * Sets an option to use with the transport layers. |
---|
388 | * |
---|
389 | * For example: |
---|
390 | * <code> |
---|
391 | * $soapclient->setOpt('curl', CURLOPT_VERBOSE, 1) |
---|
392 | * </code> |
---|
393 | * to pass a specific option to curl if using an SSL connection. |
---|
394 | * |
---|
395 | * @access public |
---|
396 | * |
---|
397 | * @param string $category Category to which the option applies or option |
---|
398 | * name. |
---|
399 | * @param string $option An option name if $category is a category name, |
---|
400 | * an option value if $category is an option name. |
---|
401 | * @param string $value An option value if $category is a category |
---|
402 | * name. |
---|
403 | */ |
---|
404 | function setOpt($category, $option, $value = null) |
---|
405 | { |
---|
406 | if (!is_null($value)) { |
---|
407 | if (!isset($this->_options[$category])) { |
---|
408 | $this->_options[$category] = array(); |
---|
409 | } |
---|
410 | $this->_options[$category][$option] = $value; |
---|
411 | } else { |
---|
412 | $this->_options[$category] = $option; |
---|
413 | } |
---|
414 | } |
---|
415 | |
---|
416 | /** |
---|
417 | * Call method supporting the overload extension. |
---|
418 | * |
---|
419 | * If the overload extension is loaded, you can call the client class with |
---|
420 | * a soap method name: |
---|
421 | * <code> |
---|
422 | * $soap = new SOAP_Client(....); |
---|
423 | * $value = $soap->getStockQuote('MSFT'); |
---|
424 | * </code> |
---|
425 | * |
---|
426 | * @access public |
---|
427 | * |
---|
428 | * @param string $method The method to call. |
---|
429 | * @param array $params The method parameters. |
---|
430 | * @param mixed $return_value Will get the method's return value |
---|
431 | * assigned. |
---|
432 | * |
---|
433 | * @return boolean Always true. |
---|
434 | */ |
---|
435 | function _call($method, $params, &$return_value) |
---|
436 | { |
---|
437 | // Overloading lowercases the method name, we need to look into the |
---|
438 | // WSDL and try to find the correct method name to get the correct |
---|
439 | // case for the call. |
---|
440 | if ($this->_wsdl) { |
---|
441 | $this->_wsdl->matchMethod($method); |
---|
442 | } |
---|
443 | |
---|
444 | $return_value = $this->call($method, $params); |
---|
445 | |
---|
446 | return true; |
---|
447 | } |
---|
448 | |
---|
449 | /** |
---|
450 | * Returns the XML content of the last SOAP request. |
---|
451 | * |
---|
452 | * @return string The last request. |
---|
453 | */ |
---|
454 | function getLastRequest() |
---|
455 | { |
---|
456 | return $this->_last_request; |
---|
457 | } |
---|
458 | |
---|
459 | /** |
---|
460 | * Returns the XML content of the last SOAP response. |
---|
461 | * |
---|
462 | * @return string The last response. |
---|
463 | */ |
---|
464 | function getLastResponse() |
---|
465 | { |
---|
466 | return $this->_last_response; |
---|
467 | } |
---|
468 | |
---|
469 | /** |
---|
470 | * Sets the SOAP encoding. |
---|
471 | * |
---|
472 | * The default encoding is section 5 encoded. |
---|
473 | * |
---|
474 | * @param string $use Either 'literal' or 'encoded' (section 5). |
---|
475 | */ |
---|
476 | function setUse($use) |
---|
477 | { |
---|
478 | $this->_options['use'] = $use; |
---|
479 | } |
---|
480 | |
---|
481 | /** |
---|
482 | * Sets the SOAP encoding style. |
---|
483 | * |
---|
484 | * The default style is rpc. |
---|
485 | * |
---|
486 | * @param string $style Either 'document' or 'rpc'. |
---|
487 | */ |
---|
488 | function setStyle($style) |
---|
489 | { |
---|
490 | $this->_options['style'] = $style; |
---|
491 | } |
---|
492 | |
---|
493 | /** |
---|
494 | * Sets whether to trace the traffic on the transport level. |
---|
495 | * |
---|
496 | * @see getWire() |
---|
497 | * |
---|
498 | * @param boolean $trace |
---|
499 | */ |
---|
500 | function setTrace($trace) |
---|
501 | { |
---|
502 | $this->_options['trace'] = $trace; |
---|
503 | } |
---|
504 | |
---|
505 | /** |
---|
506 | * Generates the complete XML SOAP message for an RPC call. |
---|
507 | * |
---|
508 | * @see call() |
---|
509 | * |
---|
510 | * @param string $method The method to call. |
---|
511 | * @param array $params The method parameters. |
---|
512 | * @param string|array $namespace Namespace or hash with options. Note: |
---|
513 | * most options need to be repeated for |
---|
514 | * SOAP_Value instances. |
---|
515 | * @param string $soapAction |
---|
516 | * |
---|
517 | * @return string The SOAP message including envelope. |
---|
518 | */ |
---|
519 | function _generate($method, $params, $namespace = false, |
---|
520 | $soapAction = false) |
---|
521 | { |
---|
522 | $this->fault = null; |
---|
523 | $this->_options['input'] = 'parse'; |
---|
524 | $this->_options['result'] = 'parse'; |
---|
525 | $this->_options['parameters'] = false; |
---|
526 | |
---|
527 | if ($params && !is_array($params)) { |
---|
528 | $params = array($params); |
---|
529 | } |
---|
530 | |
---|
531 | if (is_array($namespace)) { |
---|
532 | // Options passed as a hash. |
---|
533 | foreach ($namespace as $optname => $opt) { |
---|
534 | $this->_options[strtolower($optname)] = $opt; |
---|
535 | } |
---|
536 | } else { |
---|
537 | // We'll place $soapAction into our array for usage in the |
---|
538 | // transport. |
---|
539 | if ($soapAction) { |
---|
540 | $this->_options['soapaction'] = $soapAction; |
---|
541 | } |
---|
542 | if ($namespace) { |
---|
543 | $this->_options['namespace'] = $namespace; |
---|
544 | } |
---|
545 | } |
---|
546 | if (isset($this->_options['namespace'])) { |
---|
547 | $namespace = $this->_options['namespace']; |
---|
548 | } else { |
---|
549 | $namespace = false; |
---|
550 | } |
---|
551 | |
---|
552 | if ($this->_endpointType == 'wsdl') { |
---|
553 | $this->_setSchemaVersion($this->_wsdl->xsd); |
---|
554 | |
---|
555 | // Get port name. |
---|
556 | if (!$this->_portName) { |
---|
557 | $this->_portName = $this->_wsdl->getPortName($method); |
---|
558 | } |
---|
559 | if (PEAR::isError($this->_portName)) { |
---|
560 | return $this->_raiseSoapFault($this->_portName); |
---|
561 | } |
---|
562 | |
---|
563 | // Get endpoint. |
---|
564 | $this->_endpoint = $this->_wsdl->getEndpoint($this->_portName); |
---|
565 | if (PEAR::isError($this->_endpoint)) { |
---|
566 | return $this->_raiseSoapFault($this->_endpoint); |
---|
567 | } |
---|
568 | |
---|
569 | // Get operation data. |
---|
570 | $opData = $this->_wsdl->getOperationData($this->_portName, $method); |
---|
571 | |
---|
572 | if (PEAR::isError($opData)) { |
---|
573 | return $this->_raiseSoapFault($opData); |
---|
574 | } |
---|
575 | $namespace = $opData['namespace']; |
---|
576 | $this->_options['style'] = $opData['style']; |
---|
577 | $this->_options['use'] = $opData['input']['use']; |
---|
578 | $this->_options['soapaction'] = $opData['soapAction']; |
---|
579 | |
---|
580 | // Set input parameters. |
---|
581 | if ($this->_options['input'] == 'parse') { |
---|
582 | $this->_options['parameters'] = $opData['parameters']; |
---|
583 | $nparams = array(); |
---|
584 | if (isset($opData['input']['parts']) && |
---|
585 | count($opData['input']['parts'])) { |
---|
586 | foreach ($opData['input']['parts'] as $name => $part) { |
---|
587 | $xmlns = ''; |
---|
588 | $attrs = array(); |
---|
589 | // Is the name a complex type? |
---|
590 | if (isset($part['element'])) { |
---|
591 | $xmlns = $this->_wsdl->namespaces[$part['namespace']]; |
---|
592 | $part = $this->_wsdl->elements[$part['namespace']][$part['type']]; |
---|
593 | $name = $part['name']; |
---|
594 | } |
---|
595 | if (isset($params[$name]) || |
---|
596 | $this->_wsdl->getDataHandler($name, $part['namespace'])) { |
---|
597 | $nparams[$name] =& $params[$name]; |
---|
598 | } else { |
---|
599 | // We now force an associative array for |
---|
600 | // parameters if using WSDL. |
---|
601 | return $this->_raiseSoapFault("The named parameter $name is not in the call parameters."); |
---|
602 | } |
---|
603 | if (gettype($nparams[$name]) != 'object' || |
---|
604 | !is_a($nparams[$name], 'SOAP_Value')) { |
---|
605 | // Type is likely a qname, split it apart, and get |
---|
606 | // the type namespace from WSDL. |
---|
607 | $qname = new QName($part['type']); |
---|
608 | if ($qname->ns) { |
---|
609 | $type_namespace = $this->_wsdl->namespaces[$qname->ns]; |
---|
610 | } elseif (isset($part['namespace'])) { |
---|
611 | $type_namespace = $this->_wsdl->namespaces[$part['namespace']]; |
---|
612 | } else { |
---|
613 | $type_namespace = null; |
---|
614 | } |
---|
615 | $qname->namespace = $type_namespace; |
---|
616 | $pqname = $name; |
---|
617 | if ($xmlns) { |
---|
618 | $pqname = '{' . $xmlns . '}' . $name; |
---|
619 | } |
---|
620 | $nparams[$name] = new SOAP_Value($pqname, |
---|
621 | $qname->fqn(), |
---|
622 | $nparams[$name], |
---|
623 | $attrs); |
---|
624 | } else { |
---|
625 | // WSDL fixups to the SOAP value. |
---|
626 | } |
---|
627 | } |
---|
628 | } |
---|
629 | $params =& $nparams; |
---|
630 | unset($nparams); |
---|
631 | } |
---|
632 | } else { |
---|
633 | $this->_setSchemaVersion(SOAP_XML_SCHEMA_VERSION); |
---|
634 | } |
---|
635 | |
---|
636 | // Serialize the message. |
---|
637 | $this->_section5 = (!isset($this->_options['use']) || |
---|
638 | $this->_options['use'] != 'literal'); |
---|
639 | |
---|
640 | if (!isset($this->_options['style']) || |
---|
641 | $this->_options['style'] == 'rpc') { |
---|
642 | $this->_options['style'] = 'rpc'; |
---|
643 | $this->docparams = true; |
---|
644 | $mqname = new QName($method, $namespace); |
---|
645 | $methodValue = new SOAP_Value($mqname->fqn(), 'Struct', $params, |
---|
646 | array(), $this->_options); |
---|
647 | $soap_msg = $this->makeEnvelope($methodValue, |
---|
648 | $this->headersOut, |
---|
649 | $this->_encoding, |
---|
650 | $this->_options); |
---|
651 | } else { |
---|
652 | if (!$params) { |
---|
653 | $mqname = new QName($method, $namespace); |
---|
654 | $params = new SOAP_Value($mqname->fqn(), 'Struct', null); |
---|
655 | } elseif ($this->_options['input'] == 'parse') { |
---|
656 | if (is_array($params)) { |
---|
657 | $nparams = array(); |
---|
658 | $keys = array_keys($params); |
---|
659 | foreach ($keys as $k) { |
---|
660 | if (gettype($params[$k]) != 'object') { |
---|
661 | $nparams[] = new SOAP_Value($k, |
---|
662 | false, |
---|
663 | $params[$k]); |
---|
664 | } else { |
---|
665 | $nparams[] =& $params[$k]; |
---|
666 | } |
---|
667 | } |
---|
668 | $params =& $nparams; |
---|
669 | } |
---|
670 | if ($this->_options['parameters']) { |
---|
671 | $mqname = new QName($method, $namespace); |
---|
672 | $params = new SOAP_Value($mqname->fqn(), |
---|
673 | 'Struct', |
---|
674 | $params); |
---|
675 | } |
---|
676 | } |
---|
677 | $soap_msg = $this->makeEnvelope($params, |
---|
678 | $this->headersOut, |
---|
679 | $this->_encoding, |
---|
680 | $this->_options); |
---|
681 | } |
---|
682 | $this->headersOut = null; |
---|
683 | |
---|
684 | if (PEAR::isError($soap_msg)) { |
---|
685 | return $this->_raiseSoapFault($soap_msg); |
---|
686 | } |
---|
687 | |
---|
688 | // Handle MIME or DIME encoding. |
---|
689 | // TODO: DIME encoding should move to the transport, do it here for |
---|
690 | // now and for ease of getting it done. |
---|
691 | if (count($this->_attachments)) { |
---|
692 | if ((isset($this->_options['attachments']) && |
---|
693 | $this->_options['attachments'] == 'Mime') || |
---|
694 | isset($this->_options['Mime'])) { |
---|
695 | $soap_msg = $this->_makeMimeMessage($soap_msg, $this->_encoding); |
---|
696 | } else { |
---|
697 | // default is dime |
---|
698 | $soap_msg = $this->_makeDIMEMessage($soap_msg, $this->_encoding); |
---|
699 | $this->_options['headers']['Content-Type'] = 'application/dime'; |
---|
700 | } |
---|
701 | if (PEAR::isError($soap_msg)) { |
---|
702 | return $this->_raiseSoapFault($soap_msg); |
---|
703 | } |
---|
704 | } |
---|
705 | |
---|
706 | // Instantiate client. |
---|
707 | if (is_array($soap_msg)) { |
---|
708 | $soap_data = $soap_msg['body']; |
---|
709 | if (count($soap_msg['headers'])) { |
---|
710 | if (isset($this->_options['headers'])) { |
---|
711 | $this->_options['headers'] = array_merge($this->_options['headers'], $soap_msg['headers']); |
---|
712 | } else { |
---|
713 | $this->_options['headers'] = $soap_msg['headers']; |
---|
714 | } |
---|
715 | } |
---|
716 | } else { |
---|
717 | $soap_data = $soap_msg; |
---|
718 | } |
---|
719 | |
---|
720 | return $soap_data; |
---|
721 | } |
---|
722 | |
---|
723 | /** |
---|
724 | * Parses a SOAP response. |
---|
725 | * |
---|
726 | * @see SOAP_Parser:: |
---|
727 | * |
---|
728 | * @param string $response XML content of SOAP response. |
---|
729 | * @param string $encoding Character set encoding, defaults to 'UTF-8'. |
---|
730 | * @param array $attachments List of attachments. |
---|
731 | */ |
---|
732 | function parseResponse($response, $encoding, $attachments) |
---|
733 | { |
---|
734 | // Parse the response. |
---|
735 | $response = new SOAP_Parser($response, $encoding, $attachments); |
---|
736 | if ($response->fault) { |
---|
737 | $fault = $this->_raiseSoapFault($response->fault); |
---|
738 | return $fault; |
---|
739 | } |
---|
740 | |
---|
741 | // Return array of parameters. |
---|
742 | $return = $response->getResponse(); |
---|
743 | $headers = $response->getHeaders(); |
---|
744 | if ($headers) { |
---|
745 | $this->headersIn = $this->_decodeResponse($headers, false); |
---|
746 | } |
---|
747 | |
---|
748 | $decoded = $this->_decodeResponse($return); |
---|
749 | return $decoded; |
---|
750 | } |
---|
751 | |
---|
752 | /** |
---|
753 | * Converts a complex SOAP_Value into a PHP Array |
---|
754 | * |
---|
755 | * @param SOAP_Value $response Value object. |
---|
756 | * @param boolean $shift |
---|
757 | * |
---|
758 | * @return array |
---|
759 | */ |
---|
760 | function _decodeResponse($response, $shift = true) |
---|
761 | { |
---|
762 | if (!$response) { |
---|
763 | $decoded = null; |
---|
764 | return $decoded; |
---|
765 | } |
---|
766 | |
---|
767 | // Check for valid response. |
---|
768 | if (PEAR::isError($response)) { |
---|
769 | $fault = $this->_raiseSoapFault($response); |
---|
770 | return $fault; |
---|
771 | } elseif (!is_a($response, 'soap_value')) { |
---|
772 | $fault = $this->_raiseSoapFault("Didn't get SOAP_Value object back from client"); |
---|
773 | return $fault; |
---|
774 | } |
---|
775 | |
---|
776 | // Decode to native php datatype. |
---|
777 | $returnArray = $this->_decode($response); |
---|
778 | |
---|
779 | // Fault? |
---|
780 | if (PEAR::isError($returnArray)) { |
---|
781 | $fault = $this->_raiseSoapFault($returnArray); |
---|
782 | return $fault; |
---|
783 | } |
---|
784 | |
---|
785 | if (is_object($returnArray) && |
---|
786 | strcasecmp(get_class($returnArray), 'stdClass') == 0) { |
---|
787 | $returnArray = get_object_vars($returnArray); |
---|
788 | } |
---|
789 | |
---|
790 | if (is_array($returnArray)) { |
---|
791 | if (isset($returnArray['faultcode']) || |
---|
792 | isset($returnArray[SOAP_BASE::SOAPENVPrefix().':faultcode'])) { |
---|
793 | $faultcode = $faultstring = $faultdetail = $faultactor = ''; |
---|
794 | foreach ($returnArray as $k => $v) { |
---|
795 | if (stristr($k, 'faultcode')) $faultcode = $v; |
---|
796 | if (stristr($k, 'faultstring')) $faultstring = $v; |
---|
797 | if (stristr($k, 'detail')) $faultdetail = $v; |
---|
798 | if (stristr($k, 'faultactor')) $faultactor = $v; |
---|
799 | } |
---|
800 | $fault = $this->_raiseSoapFault($faultstring, $faultdetail, |
---|
801 | $faultactor, $faultcode); |
---|
802 | return $fault; |
---|
803 | } |
---|
804 | // Return array of return values. |
---|
805 | if ($shift && count($returnArray) == 1) { |
---|
806 | $decoded = array_shift($returnArray); |
---|
807 | return $decoded; |
---|
808 | } |
---|
809 | return $returnArray; |
---|
810 | } |
---|
811 | |
---|
812 | return $returnArray; |
---|
813 | } |
---|
814 | |
---|
815 | /** |
---|
816 | * Returns the outgoing and incoming traffic on the transport level. |
---|
817 | * |
---|
818 | * Tracing has to be enabled. |
---|
819 | * |
---|
820 | * @see setTrace() |
---|
821 | * |
---|
822 | * @return string The complete traffic between the client and the server. |
---|
823 | */ |
---|
824 | function getWire() |
---|
825 | { |
---|
826 | if ($this->_options['trace'] && |
---|
827 | ($this->_last_request || $this->_last_response)) { |
---|
828 | return "OUTGOING:\n\n" . |
---|
829 | $this->_last_request . |
---|
830 | "\n\nINCOMING\n\n" . |
---|
831 | preg_replace("/></",">\r\n<", $this->_last_response); |
---|
832 | } |
---|
833 | |
---|
834 | return null; |
---|
835 | } |
---|
836 | |
---|
837 | } |
---|