| 1 |
lars |
1 |
<?php
|
|
|
2 |
/**
|
|
|
3 |
* This file contains the code for dealing with WSDL access and services.
|
|
|
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 |
require_once 'SOAP/Base.php';
|
|
|
26 |
require_once 'SOAP/Fault.php';
|
|
|
27 |
require_once 'HTTP/Request.php';
|
|
|
28 |
|
|
|
29 |
define('WSDL_CACHE_MAX_AGE', 43200);
|
|
|
30 |
|
|
|
31 |
/**
|
|
|
32 |
* This class parses WSDL files, and can be used by SOAP::Client to properly
|
|
|
33 |
* register soap values for services.
|
|
|
34 |
*
|
|
|
35 |
* Originally based on SOAPx4 by Dietrich Ayala
|
|
|
36 |
* http://dietrich.ganx4.com/soapx4
|
|
|
37 |
*
|
|
|
38 |
* @todo
|
|
|
39 |
* - refactor namespace handling ($namespace/$ns)
|
|
|
40 |
* - implement IDL type syntax declaration so we can generate WSDL
|
|
|
41 |
*
|
|
|
42 |
* @access public
|
|
|
43 |
* @package SOAP
|
|
|
44 |
* @author Shane Caraveo <shane@php.net> Conversion to PEAR and updates
|
|
|
45 |
* @author Dietrich Ayala <dietrich@ganx4.com> Original Author
|
|
|
46 |
*/
|
|
|
47 |
class SOAP_WSDL extends SOAP_Base
|
|
|
48 |
{
|
|
|
49 |
var $tns = null;
|
|
|
50 |
var $definition = array();
|
|
|
51 |
var $namespaces = array();
|
|
|
52 |
var $ns = array();
|
|
|
53 |
var $xsd = SOAP_XML_SCHEMA_VERSION;
|
|
|
54 |
var $complexTypes = array();
|
|
|
55 |
var $elements = array();
|
|
|
56 |
var $messages = array();
|
|
|
57 |
var $portTypes = array();
|
|
|
58 |
var $bindings = array();
|
|
|
59 |
var $imports = array();
|
|
|
60 |
var $services = array();
|
|
|
61 |
var $service = '';
|
|
|
62 |
|
|
|
63 |
/**
|
|
|
64 |
* URL to WSDL file.
|
|
|
65 |
*
|
|
|
66 |
* @var string
|
|
|
67 |
*/
|
|
|
68 |
var $uri;
|
|
|
69 |
|
|
|
70 |
/**
|
|
|
71 |
* Parse documentation in the WSDL?
|
|
|
72 |
*
|
|
|
73 |
* @var boolean
|
|
|
74 |
*/
|
|
|
75 |
var $docs;
|
|
|
76 |
|
|
|
77 |
/**
|
|
|
78 |
* Proxy parameters.
|
|
|
79 |
*
|
|
|
80 |
* @var array
|
|
|
81 |
*/
|
|
|
82 |
var $proxy;
|
|
|
83 |
|
|
|
84 |
/**
|
|
|
85 |
* Enable tracing in the generated proxy class?
|
|
|
86 |
*
|
|
|
87 |
* @var boolean
|
|
|
88 |
*/
|
|
|
89 |
var $trace = false;
|
|
|
90 |
|
|
|
91 |
/**
|
|
|
92 |
* Use WSDL cache?
|
|
|
93 |
*
|
|
|
94 |
* @var boolean
|
|
|
95 |
*/
|
|
|
96 |
var $cacheUse;
|
|
|
97 |
|
|
|
98 |
/**
|
|
|
99 |
* WSDL cache directory.
|
|
|
100 |
*
|
|
|
101 |
* @var string
|
|
|
102 |
*/
|
|
|
103 |
var $cacheDir;
|
|
|
104 |
|
|
|
105 |
/**
|
|
|
106 |
* Cache maximum lifetime (in seconds).
|
|
|
107 |
*
|
|
|
108 |
* @var integer
|
|
|
109 |
*/
|
|
|
110 |
var $cacheMaxAge;
|
|
|
111 |
|
|
|
112 |
/**
|
|
|
113 |
* Class to use for WSDL parsing. Can be overridden for special cases,
|
|
|
114 |
* subclasses, etc.
|
|
|
115 |
*
|
|
|
116 |
* @var string
|
|
|
117 |
*/
|
|
|
118 |
var $wsdlParserClass = 'SOAP_WSDL_Parser';
|
|
|
119 |
|
|
|
120 |
/**
|
|
|
121 |
* Reserved PHP keywords.
|
|
|
122 |
*
|
|
|
123 |
* @link http://www.php.net/manual/en/reserved.php
|
|
|
124 |
*
|
|
|
125 |
* @var array
|
|
|
126 |
*/
|
|
|
127 |
var $_reserved = array('abstract', 'and', 'array', 'as', 'break', 'case',
|
|
|
128 |
'catch', 'cfunction', 'class', 'clone', 'const',
|
|
|
129 |
'continue', 'declare', 'default', 'die', 'do',
|
|
|
130 |
'echo', 'else', 'elseif', 'empty', 'enddeclare',
|
|
|
131 |
'endfor', 'endforeach', 'endif', 'endswitch',
|
|
|
132 |
'endwhile', 'eval', 'exception', 'exit', 'extends',
|
|
|
133 |
'final', 'for', 'foreach', 'function', 'global',
|
|
|
134 |
'if', 'implements', 'include', 'include_once',
|
|
|
135 |
'interface', 'isset', 'list', 'new', 'old_function',
|
|
|
136 |
'or', 'php_user_filter', 'print', 'private',
|
|
|
137 |
'protected', 'public', 'require', 'require_once',
|
|
|
138 |
'return', 'static', 'switch', 'this', 'throw',
|
|
|
139 |
'try', 'unset', 'use', 'var', 'while', 'xor');
|
|
|
140 |
|
|
|
141 |
/**
|
|
|
142 |
* Regular expressions for invalid PHP labels.
|
|
|
143 |
*
|
|
|
144 |
* @link http://www.php.net/manual/en/language.variables.php.
|
|
|
145 |
*
|
|
|
146 |
* @var string
|
|
|
147 |
*/
|
|
|
148 |
var $_invalid = array('/^[^a-zA-Z_\x7f-\xff]/', '/[^a-zA-Z0-9_\x7f-\xff]/');
|
|
|
149 |
|
|
|
150 |
/**
|
|
|
151 |
* SOAP_WSDL constructor.
|
|
|
152 |
*
|
|
|
153 |
* @param string $wsdl_uri URL to WSDL file.
|
|
|
154 |
* @param array $proxy Options for HTTP_Request class
|
|
|
155 |
* @see HTTP_Request.
|
|
|
156 |
* @param boolean|string $cacheUse Use WSDL caching? The cache directory
|
|
|
157 |
* if a string.
|
|
|
158 |
* @param integer $cacheMaxAge Cache maximum lifetime (in seconds).
|
|
|
159 |
* @param boolean $docs Parse documentation in the WSDL?
|
|
|
160 |
*
|
|
|
161 |
* @access public
|
|
|
162 |
*/
|
|
|
163 |
function SOAP_WSDL($wsdl_uri = false,
|
|
|
164 |
$proxy = array(),
|
|
|
165 |
$cacheUse = false,
|
|
|
166 |
$cacheMaxAge = WSDL_CACHE_MAX_AGE,
|
|
|
167 |
$docs = false)
|
|
|
168 |
{
|
|
|
169 |
parent::SOAP_Base('WSDL');
|
|
|
170 |
$this->uri = $wsdl_uri;
|
|
|
171 |
$this->proxy = $proxy;
|
|
|
172 |
$this->cacheUse = !empty($cacheUse);
|
|
|
173 |
$this->cacheMaxAge = $cacheMaxAge;
|
|
|
174 |
$this->docs = $docs;
|
|
|
175 |
if (is_string($cacheUse)) {
|
|
|
176 |
$this->cacheDir = $cacheUse;
|
|
|
177 |
}
|
|
|
178 |
|
|
|
179 |
if ($wsdl_uri) {
|
|
|
180 |
if (!PEAR::isError($this->parseURL($wsdl_uri))) {
|
|
|
181 |
reset($this->services);
|
|
|
182 |
$this->service = key($this->services);
|
|
|
183 |
}
|
|
|
184 |
}
|
|
|
185 |
}
|
|
|
186 |
|
|
|
187 |
/**
|
|
|
188 |
* @deprecated Use setService().
|
|
|
189 |
*/
|
|
|
190 |
function set_service($service)
|
|
|
191 |
{
|
|
|
192 |
$this->setService($service);
|
|
|
193 |
}
|
|
|
194 |
|
|
|
195 |
/**
|
|
|
196 |
* Sets the service currently to be used.
|
|
|
197 |
*
|
|
|
198 |
* @param string $service An (existing) service name.
|
|
|
199 |
*/
|
|
|
200 |
function setService($service)
|
|
|
201 |
{
|
|
|
202 |
if (array_key_exists($service, $this->services)) {
|
|
|
203 |
$this->service = $service;
|
|
|
204 |
}
|
|
|
205 |
}
|
|
|
206 |
|
|
|
207 |
/**
|
|
|
208 |
* Fills the WSDL array tree with data from a WSDL file.
|
|
|
209 |
*
|
|
|
210 |
* @param string $wsdl_uri URL to WSDL file.
|
|
|
211 |
*/
|
|
|
212 |
function parseURL($wsdl_uri)
|
|
|
213 |
{
|
|
|
214 |
$parser =& new $this->wsdlParserClass($wsdl_uri, $this, $this->docs);
|
|
|
215 |
|
|
|
216 |
if ($parser->fault) {
|
|
|
217 |
$this->_raiseSoapFault($parser->fault);
|
|
|
218 |
}
|
|
|
219 |
}
|
|
|
220 |
|
|
|
221 |
/**
|
|
|
222 |
* Fills the WSDL array tree with data from one or more PHP class objects.
|
|
|
223 |
*
|
|
|
224 |
* @param mixed $wsdl_obj An object or array of objects to add to
|
|
|
225 |
* the internal WSDL tree.
|
|
|
226 |
* @param string $targetNamespace The target namespace of schema types
|
|
|
227 |
* etc.
|
|
|
228 |
* @param string $service_name Name of the WSDL service.
|
|
|
229 |
* @param string $service_desc Optional description of the WSDL
|
|
|
230 |
* service.
|
|
|
231 |
*/
|
|
|
232 |
function parseObject($wsdl_obj, $targetNamespace, $service_name,
|
|
|
233 |
$service_desc = '')
|
|
|
234 |
{
|
|
|
235 |
$parser = new SOAP_WSDL_ObjectParser($wsdl_obj, $this,
|
|
|
236 |
$targetNamespace, $service_name,
|
|
|
237 |
$service_desc);
|
|
|
238 |
|
|
|
239 |
if ($parser->fault) {
|
|
|
240 |
$this->_raiseSoapFault($parser->fault);
|
|
|
241 |
}
|
|
|
242 |
}
|
|
|
243 |
|
|
|
244 |
function getEndpoint($portName)
|
|
|
245 |
{
|
|
|
246 |
if ($this->_isfault()) {
|
|
|
247 |
return $this->_getfault();
|
|
|
248 |
}
|
|
|
249 |
|
|
|
250 |
return (isset($this->services[$this->service]['ports'][$portName]['address']['location']))
|
|
|
251 |
? $this->services[$this->service]['ports'][$portName]['address']['location']
|
|
|
252 |
: $this->_raiseSoapFault("No endpoint for port for $portName", $this->uri);
|
|
|
253 |
}
|
|
|
254 |
|
|
|
255 |
function _getPortName($operation, $service)
|
|
|
256 |
{
|
|
|
257 |
if (isset($this->services[$service]['ports'])) {
|
|
|
258 |
$ports = $this->services[$service]['ports'];
|
|
|
259 |
foreach ($ports as $port => $portAttrs) {
|
|
|
260 |
$type = $ports[$port]['type'];
|
|
|
261 |
if ($type == 'soap' &&
|
|
|
262 |
isset($this->bindings[$portAttrs['binding']]['operations'][$operation])) {
|
|
|
263 |
return $port;
|
|
|
264 |
}
|
|
|
265 |
}
|
|
|
266 |
}
|
|
|
267 |
return null;
|
|
|
268 |
}
|
|
|
269 |
|
|
|
270 |
/**
|
|
|
271 |
* Finds the name of the first port that contains an operation of name
|
|
|
272 |
* $operation. Always returns a SOAP portName.
|
|
|
273 |
*/
|
|
|
274 |
function getPortName($operation, $service = null)
|
|
|
275 |
{
|
|
|
276 |
if ($this->_isfault()) {
|
|
|
277 |
return $this->_getfault();
|
|
|
278 |
}
|
|
|
279 |
|
|
|
280 |
if (!$service) {
|
|
|
281 |
$service = $this->service;
|
|
|
282 |
}
|
|
|
283 |
if (isset($this->services[$service]['ports'])) {
|
|
|
284 |
if ($portName = $this->_getPortName($operation, $service)) {
|
|
|
285 |
return $portName;
|
|
|
286 |
}
|
|
|
287 |
}
|
|
|
288 |
// Try any service in the WSDL.
|
|
|
289 |
foreach ($this->services as $serviceName => $service) {
|
|
|
290 |
if (isset($this->services[$serviceName]['ports'])) {
|
|
|
291 |
if ($portName = $this->_getPortName($operation, $serviceName)) {
|
|
|
292 |
$this->service = $serviceName;
|
|
|
293 |
return $portName;
|
|
|
294 |
}
|
|
|
295 |
}
|
|
|
296 |
}
|
|
|
297 |
return $this->_raiseSoapFault("No operation $operation in WSDL.", $this->uri);
|
|
|
298 |
}
|
|
|
299 |
|
|
|
300 |
function getOperationData($portName, $operation)
|
|
|
301 |
{
|
|
|
302 |
if ($this->_isfault()) {
|
|
|
303 |
return $this->_getfault();
|
|
|
304 |
}
|
|
|
305 |
|
|
|
306 |
if (!isset($this->services[$this->service]['ports'][$portName]['binding']) ||
|
|
|
307 |
!($binding = $this->services[$this->service]['ports'][$portName]['binding'])) {
|
|
|
308 |
return $this->_raiseSoapFault("No binding for port $portName in WSDL.", $this->uri);
|
|
|
309 |
}
|
|
|
310 |
|
|
|
311 |
// Get operation data from binding.
|
|
|
312 |
if (is_array($this->bindings[$binding]['operations'][$operation])) {
|
|
|
313 |
$opData = $this->bindings[$binding]['operations'][$operation];
|
|
|
314 |
}
|
|
|
315 |
// Get operation data from porttype.
|
|
|
316 |
$portType = $this->bindings[$binding]['type'];
|
|
|
317 |
if (!$portType) {
|
|
|
318 |
return $this->_raiseSoapFault("No port type for binding $binding in WSDL.", $this->uri);
|
|
|
319 |
}
|
|
|
320 |
if (is_array($type = $this->portTypes[$portType][$operation])) {
|
|
|
321 |
if (isset($type['parameterOrder'])) {
|
|
|
322 |
$opData['parameterOrder'] = $type['parameterOrder'];
|
|
|
323 |
}
|
|
|
324 |
$opData['input'] = array_merge($opData['input'], $type['input']);
|
|
|
325 |
$opData['output'] = array_merge($opData['output'], $type['output']);
|
|
|
326 |
}
|
|
|
327 |
if (!$opData)
|
|
|
328 |
return $this->_raiseSoapFault("No operation $operation for port $portName in WSDL.", $this->uri);
|
|
|
329 |
$opData['parameters'] = false;
|
|
|
330 |
if (isset($this->bindings[$binding]['operations'][$operation]['input']['namespace']))
|
|
|
331 |
$opData['namespace'] = $this->bindings[$binding]['operations'][$operation]['input']['namespace'];
|
|
|
332 |
// Message data from messages.
|
|
|
333 |
$inputMsg = $opData['input']['message'];
|
|
|
334 |
if (is_array($this->messages[$inputMsg])) {
|
|
|
335 |
foreach ($this->messages[$inputMsg] as $pname => $pattrs) {
|
|
|
336 |
if ($opData['style'] == 'document' &&
|
|
|
337 |
$opData['input']['use'] == 'literal' &&
|
|
|
338 |
$pname == 'parameters') {
|
|
|
339 |
$opData['parameters'] = true;
|
|
|
340 |
$opData['namespace'] = $this->namespaces[$pattrs['namespace']];
|
|
|
341 |
$el = $this->elements[$pattrs['namespace']][$pattrs['type']];
|
|
|
342 |
if (isset($el['elements'])) {
|
|
|
343 |
foreach ($el['elements'] as $elname => $elattrs) {
|
|
|
344 |
$opData['input']['parts'][$elname] = $elattrs;
|
|
|
345 |
}
|
|
|
346 |
}
|
|
|
347 |
} else {
|
|
|
348 |
$opData['input']['parts'][$pname] = $pattrs;
|
|
|
349 |
}
|
|
|
350 |
}
|
|
|
351 |
}
|
|
|
352 |
$outputMsg = $opData['output']['message'];
|
|
|
353 |
if (is_array($this->messages[$outputMsg])) {
|
|
|
354 |
foreach ($this->messages[$outputMsg] as $pname => $pattrs) {
|
|
|
355 |
if ($opData['style'] == 'document' &&
|
|
|
356 |
$opData['output']['use'] == 'literal' &&
|
|
|
357 |
$pname == 'parameters') {
|
|
|
358 |
|
|
|
359 |
$el = $this->elements[$pattrs['namespace']][$pattrs['type']];
|
|
|
360 |
if (isset($el['elements'])) {
|
|
|
361 |
foreach ($el['elements'] as $elname => $elattrs) {
|
|
|
362 |
$opData['output']['parts'][$elname] = $elattrs;
|
|
|
363 |
}
|
|
|
364 |
}
|
|
|
365 |
} else {
|
|
|
366 |
$opData['output']['parts'][$pname] = $pattrs;
|
|
|
367 |
}
|
|
|
368 |
}
|
|
|
369 |
}
|
|
|
370 |
return $opData;
|
|
|
371 |
}
|
|
|
372 |
|
|
|
373 |
function matchMethod(&$operation)
|
|
|
374 |
{
|
|
|
375 |
if ($this->_isfault()) {
|
|
|
376 |
return $this->_getfault();
|
|
|
377 |
}
|
|
|
378 |
|
|
|
379 |
// Overloading lowercases function names :(
|
|
|
380 |
foreach ($this->services[$this->service]['ports'] as $portAttrs) {
|
|
|
381 |
foreach (array_keys($this->bindings[$portAttrs['binding']]['operations']) as $op) {
|
|
|
382 |
if (strcasecmp($op, $operation) == 0) {
|
|
|
383 |
$operation = $op;
|
|
|
384 |
}
|
|
|
385 |
}
|
|
|
386 |
}
|
|
|
387 |
}
|
|
|
388 |
|
|
|
389 |
/**
|
|
|
390 |
* Given a datatype, what function handles the processing?
|
|
|
391 |
*
|
|
|
392 |
* This is used for doc/literal requests where we receive a datatype, and
|
|
|
393 |
* we need to pass it to a method in out server class.
|
|
|
394 |
*
|
|
|
395 |
* @param string $datatype
|
|
|
396 |
* @param string $namespace
|
|
|
397 |
* @return string
|
|
|
398 |
* @access public
|
|
|
399 |
*/
|
|
|
400 |
function getDataHandler($datatype, $namespace)
|
|
|
401 |
{
|
|
|
402 |
// See if we have an element by this name.
|
|
|
403 |
if (isset($this->namespaces[$namespace])) {
|
|
|
404 |
$namespace = $this->namespaces[$namespace];
|
|
|
405 |
}
|
|
|
406 |
|
|
|
407 |
if (!isset($this->ns[$namespace])) {
|
|
|
408 |
return null;
|
|
|
409 |
}
|
|
|
410 |
|
|
|
411 |
$nsp = $this->ns[$namespace];
|
|
|
412 |
//if (!isset($this->elements[$nsp]))
|
|
|
413 |
// $nsp = $this->namespaces[$nsp];
|
|
|
414 |
if (!isset($this->elements[$nsp][$datatype])) {
|
|
|
415 |
return null;
|
|
|
416 |
}
|
|
|
417 |
|
|
|
418 |
$checkmessages = array();
|
|
|
419 |
// Find what messages use this datatype.
|
|
|
420 |
foreach ($this->messages as $messagename => $message) {
|
|
|
421 |
foreach ($message as $part) {
|
|
|
422 |
if ($part['type'] == $datatype) {
|
|
|
423 |
$checkmessages[] = $messagename;
|
|
|
424 |
break;
|
|
|
425 |
}
|
|
|
426 |
}
|
|
|
427 |
}
|
|
|
428 |
// Find the operation that uses this message.
|
|
|
429 |
foreach($this->portTypes as $porttype) {
|
|
|
430 |
foreach ($porttype as $opname => $opinfo) {
|
|
|
431 |
foreach ($checkmessages as $messagename) {
|
|
|
432 |
if ($opinfo['input']['message'] == $messagename) {
|
|
|
433 |
return $opname;
|
|
|
434 |
}
|
|
|
435 |
}
|
|
|
436 |
}
|
|
|
437 |
}
|
|
|
438 |
|
|
|
439 |
return null;
|
|
|
440 |
}
|
|
|
441 |
|
|
|
442 |
function getSoapAction($portName, $operation)
|
|
|
443 |
{
|
|
|
444 |
if ($this->_isfault()) {
|
|
|
445 |
return $this->_getfault();
|
|
|
446 |
}
|
|
|
447 |
|
|
|
448 |
if (!empty($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction'])) {
|
|
|
449 |
return $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['soapAction'];
|
|
|
450 |
}
|
|
|
451 |
|
|
|
452 |
return false;
|
|
|
453 |
}
|
|
|
454 |
|
|
|
455 |
function getNamespace($portName, $operation)
|
|
|
456 |
{
|
|
|
457 |
if ($this->_isfault()) {
|
|
|
458 |
return $this->_getfault();
|
|
|
459 |
}
|
|
|
460 |
|
|
|
461 |
if (!empty($this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'])) {
|
|
|
462 |
return $this->bindings[$this->services[$this->service]['ports'][$portName]['binding']]['operations'][$operation]['input']['namespace'];
|
|
|
463 |
}
|
|
|
464 |
|
|
|
465 |
return false;
|
|
|
466 |
}
|
|
|
467 |
|
|
|
468 |
function getNamespaceAttributeName($namespace)
|
|
|
469 |
{
|
|
|
470 |
/* If it doesn't exist at first, flip the array and check again. */
|
|
|
471 |
if (empty($this->ns[$namespace])) {
|
|
|
472 |
$this->ns = array_flip($this->namespaces);
|
|
|
473 |
}
|
|
|
474 |
|
|
|
475 |
/* If it doesn't exist now, add it. */
|
|
|
476 |
if (empty($this->ns[$namespace])) {
|
|
|
477 |
return $this->addNamespace($namespace);
|
|
|
478 |
}
|
|
|
479 |
|
|
|
480 |
return $this->ns[$namespace];
|
|
|
481 |
}
|
|
|
482 |
|
|
|
483 |
function addNamespace($namespace)
|
|
|
484 |
{
|
|
|
485 |
if (!empty($this->ns[$namespace])) {
|
|
|
486 |
return $this->ns[$namespace];
|
|
|
487 |
}
|
|
|
488 |
|
|
|
489 |
$n = count($this->ns);
|
|
|
490 |
$attr = 'ns' . $n;
|
|
|
491 |
$this->namespaces['ns' . $n] = $namespace;
|
|
|
492 |
$this->ns[$namespace] = $attr;
|
|
|
493 |
|
|
|
494 |
return $attr;
|
|
|
495 |
}
|
|
|
496 |
|
|
|
497 |
function _validateString($string)
|
|
|
498 |
{
|
|
|
499 |
return preg_match('/^[\w_:#\/]+$/', $string);
|
|
|
500 |
}
|
|
|
501 |
|
|
|
502 |
function _addArg(&$args, &$argarray, $argname)
|
|
|
503 |
{
|
|
|
504 |
if ($args) {
|
|
|
505 |
$args .= ', ';
|
|
|
506 |
}
|
|
|
507 |
$args .= '$' . $argname;
|
|
|
508 |
if (!$this->_validateString($argname)) {
|
|
|
509 |
return;
|
|
|
510 |
}
|
|
|
511 |
if ($argarray) {
|
|
|
512 |
$argarray .= ', ';
|
|
|
513 |
}
|
|
|
514 |
$argarray .= "'$argname' => $" . $argname;
|
|
|
515 |
}
|
|
|
516 |
|
|
|
517 |
function _elementArg(&$args, &$argarray, &$_argtype, $_argname)
|
|
|
518 |
{
|
|
|
519 |
$comments = '';
|
|
|
520 |
$el = $this->elements[$_argtype['namespace']][$_argtype['type']];
|
|
|
521 |
$tns = isset($this->ns[$el['namespace']])
|
|
|
522 |
? $this->ns[$el['namespace']]
|
|
|
523 |
: $_argtype['namespace'];
|
|
|
524 |
|
|
|
525 |
if (!empty($el['complex']) ||
|
|
|
526 |
(isset($el['type']) &&
|
|
|
527 |
isset($this->complexTypes[$tns][$el['type']]))) {
|
|
|
528 |
// The element is a complex type.
|
|
|
529 |
$comments .= " // {$_argtype['type']} is a ComplexType, refer to the WSDL for more info.\n";
|
|
|
530 |
$attrname = "{$_argtype['type']}_attr";
|
|
|
531 |
if (isset($el['type']) &&
|
|
|
532 |
isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
|
|
|
533 |
$comments .= " // {$_argtype['type']} may require attributes, refer to the WSDL for more info.\n";
|
|
|
534 |
}
|
|
|
535 |
$comments .= " \${$attrname}['xmlns'] = '{$this->namespaces[$_argtype['namespace']]}';\n";
|
|
|
536 |
$comments .= " \${$_argtype['type']} = new SOAP_Value('{$_argtype['type']}', false, \${$_argtype['type']}, \$$attrname);\n";
|
|
|
537 |
$this->_addArg($args, $argarray, $_argtype['type']);
|
|
|
538 |
if (isset($el['type']) &&
|
|
|
539 |
isset($this->complexTypes[$tns][$el['type']]['attribute'])) {
|
|
|
540 |
if ($args) {
|
|
|
541 |
$args .= ', ';
|
|
|
542 |
}
|
|
|
543 |
$args .= '$' . $attrname;
|
|
|
544 |
}
|
|
|
545 |
} elseif (isset($el['elements'])) {
|
|
|
546 |
foreach ($el['elements'] as $ename => $element) {
|
|
|
547 |
$comments .= " \$$ename = new SOAP_Value('{{$this->namespaces[$element['namespace']]}}$ename', '" .
|
|
|
548 |
(isset($element['type']) ? $element['type'] : false) .
|
|
|
549 |
"', \$$ename);\n";
|
|
|
550 |
$this->_addArg($args, $argarray, $ename);
|
|
|
551 |
}
|
|
|
552 |
} else {
|
|
|
553 |
$comments .= " \$$_argname = new SOAP_Value('{{$this->namespaces[$tns]}}$_argname', '{$el['type']}', \$$_argname);\n";
|
|
|
554 |
$this->_addArg($args, $argarray, $_argname);
|
|
|
555 |
}
|
|
|
556 |
|
|
|
557 |
return $comments;
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
function _complexTypeArg(&$args, &$argarray, &$_argtype, $_argname)
|
|
|
561 |
{
|
|
|
562 |
$comments = '';
|
|
|
563 |
if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']])) {
|
|
|
564 |
$comments = " // $_argname is a ComplexType {$_argtype['type']},\n" .
|
|
|
565 |
" // refer to wsdl for more info\n";
|
|
|
566 |
if (isset($this->complexTypes[$_argtype['namespace']][$_argtype['type']]['attribute'])) {
|
|
|
567 |
$comments .= " // $_argname may require attributes, refer to wsdl for more info\n";
|
|
|
568 |
}
|
|
|
569 |
$wrapname = '{' . $this->namespaces[$_argtype['namespace']].'}' . $_argtype['type'];
|
|
|
570 |
$comments .= " \$$_argname = new SOAP_Value('$_argname', '$wrapname', \$$_argname);\n";
|
|
|
571 |
}
|
|
|
572 |
|
|
|
573 |
$this->_addArg($args, $argarray, $_argname);
|
|
|
574 |
|
|
|
575 |
return $comments;
|
|
|
576 |
}
|
|
|
577 |
|
|
|
578 |
/**
|
|
|
579 |
* Generates stub code from the WSDL that can be saved to a file or eval'd
|
|
|
580 |
* into existence.
|
|
|
581 |
*/
|
|
|
582 |
function generateProxyCode($port = '', $classname = '')
|
|
|
583 |
{
|
|
|
584 |
if ($this->_isfault()) {
|
|
|
585 |
return $this->_getfault();
|
|
|
586 |
}
|
|
|
587 |
|
|
|
588 |
$multiport = count($this->services[$this->service]['ports']) > 1;
|
|
|
589 |
if (!$port) {
|
|
|
590 |
reset($this->services[$this->service]['ports']);
|
|
|
591 |
$port = current($this->services[$this->service]['ports']);
|
|
|
592 |
}
|
|
|
593 |
// XXX currently do not support HTTP ports
|
|
|
594 |
if ($port['type'] != 'soap') {
|
|
|
595 |
return null;
|
|
|
596 |
}
|
|
|
597 |
|
|
|
598 |
// XXX currentPort is BAD
|
|
|
599 |
$clienturl = $port['address']['location'];
|
|
|
600 |
if (!$classname) {
|
|
|
601 |
if ($multiport || $port) {
|
|
|
602 |
$classname = 'WebService_' . $this->service . '_' . $port['name'];
|
|
|
603 |
} else {
|
|
|
604 |
$classname = 'WebService_' . $this->service;
|
|
|
605 |
}
|
|
|
606 |
$classname = $this->_sanitize($classname);
|
|
|
607 |
}
|
|
|
608 |
|
|
|
609 |
if (!$this->_validateString($classname)) {
|
|
|
610 |
return null;
|
|
|
611 |
}
|
|
|
612 |
|
|
|
613 |
if (is_array($this->proxy) && count($this->proxy)) {
|
|
|
614 |
$class = "class $classname extends SOAP_Client\n{\n" .
|
|
|
615 |
" function $classname(\$path = '$clienturl')\n {\n" .
|
|
|
616 |
" \$this->SOAP_Client(\$path, 0, 0,\n" .
|
|
|
617 |
' array(';
|
|
|
618 |
|
|
|
619 |
foreach ($this->proxy as $key => $val) {
|
|
|
620 |
if (is_array($val)) {
|
|
|
621 |
$class .= "'$key' => array(";
|
|
|
622 |
foreach ($val as $key2 => $val2) {
|
|
|
623 |
$class .= "'$key2' => '$val2', ";
|
|
|
624 |
}
|
|
|
625 |
$class .= ')';
|
|
|
626 |
} else {
|
|
|
627 |
$class .= "'$key' => '$val', ";
|
|
|
628 |
}
|
|
|
629 |
}
|
|
|
630 |
$class .= "));\n }\n";
|
|
|
631 |
$class = str_replace(', ))', '))', $class);
|
|
|
632 |
} else {
|
|
|
633 |
$class = "class $classname extends SOAP_Client\n{\n" .
|
|
|
634 |
" function $classname(\$path = '$clienturl')\n {\n" .
|
|
|
635 |
" \$this->SOAP_Client(\$path, 0);\n" .
|
|
|
636 |
" }\n";
|
|
|
637 |
}
|
|
|
638 |
|
|
|
639 |
// Get the binding, from that get the port type.
|
|
|
640 |
$primaryBinding = $port['binding'];
|
|
|
641 |
$primaryBinding = preg_replace("/^(.*:)/", '', $primaryBinding);
|
|
|
642 |
$portType = $this->bindings[$primaryBinding]['type'];
|
|
|
643 |
$portType = preg_replace("/^(.*:)/", '', $portType);
|
|
|
644 |
$style = $this->bindings[$primaryBinding]['style'];
|
|
|
645 |
|
|
|
646 |
// XXX currentPortType is BAD
|
|
|
647 |
foreach ($this->portTypes[$portType] as $opname => $operation) {
|
|
|
648 |
$binding = $this->bindings[$primaryBinding]['operations'][$opname];
|
|
|
649 |
if (isset($binding['soapAction'])) {
|
|
|
650 |
$soapaction = $binding['soapAction'];
|
|
|
651 |
} else {
|
|
|
652 |
$soapaction = null;
|
|
|
653 |
}
|
|
|
654 |
if (isset($binding['style'])) {
|
|
|
655 |
$opstyle = $binding['style'];
|
|
|
656 |
} else {
|
|
|
657 |
$opstyle = $style;
|
|
|
658 |
}
|
|
|
659 |
$use = $binding['input']['use'];
|
|
|
660 |
if ($use == 'encoded') {
|
|
|
661 |
$namespace = $binding['input']['namespace'];
|
|
|
662 |
} else {
|
|
|
663 |
$bindingType = $this->bindings[$primaryBinding]['type'];
|
|
|
664 |
$ns = $this->portTypes[$bindingType][$opname]['input']['namespace'];
|
|
|
665 |
$namespace = $this->namespaces[$ns];
|
|
|
666 |
}
|
|
|
667 |
|
|
|
668 |
$args = '';
|
|
|
669 |
$argarray = '';
|
|
|
670 |
$comments = '';
|
|
|
671 |
$wrappers = '';
|
|
|
672 |
foreach ($operation['input'] as $argname => $argtype) {
|
|
|
673 |
if ($argname == 'message') {
|
|
|
674 |
foreach ($this->messages[$argtype] as $_argname => $_argtype) {
|
|
|
675 |
$_argname = $this->_sanitize($_argname);
|
|
|
676 |
if ($opstyle == 'document' && $use == 'literal' &&
|
|
|
677 |
$_argtype['name'] == 'parameters') {
|
|
|
678 |
// The type or element refered to is used for
|
|
|
679 |
// parameters.
|
|
|
680 |
$elattrs = null;
|
|
|
681 |
$el = $this->elements[$_argtype['namespace']][$_argtype['type']];
|
|
|
682 |
|
|
|
683 |
if ($el['complex']) {
|
|
|
684 |
$namespace = $this->namespaces[$_argtype['namespace']];
|
|
|
685 |
// XXX need to wrap the parameters in a
|
|
|
686 |
// SOAP_Value.
|
|
|
687 |
}
|
|
|
688 |
if (isset($el['elements'])) {
|
|
|
689 |
foreach ($el['elements'] as $elname => $elattrs) {
|
|
|
690 |
$elname = $this->_sanitize($elname);
|
|
|
691 |
// Is the element a complex type?
|
|
|
692 |
if (isset($this->complexTypes[$elattrs['namespace']][$elname])) {
|
|
|
693 |
$comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname);
|
|
|
694 |
} else {
|
|
|
695 |
$this->_addArg($args, $argarray, $elname);
|
|
|
696 |
}
|
|
|
697 |
}
|
|
|
698 |
}
|
|
|
699 |
if ($el['complex'] && $argarray) {
|
|
|
700 |
$wrapname = '{' . $this->namespaces[$_argtype['namespace']].'}' . $el['name'];
|
|
|
701 |
$comments .= " \${$el['name']} = new SOAP_Value('$wrapname', false, \$v = array($argarray));\n";
|
|
|
702 |
$argarray = "'{$el['name']}' => \${$el['name']}";
|
|
|
703 |
}
|
|
|
704 |
} else {
|
|
|
705 |
if (isset($_argtype['element'])) {
|
|
|
706 |
// Element argument.
|
|
|
707 |
$comments .= $this->_elementArg($args, $argarray, $_argtype, $_argtype['type']);
|
|
|
708 |
} else {
|
|
|
709 |
// Complex type argument.
|
|
|
710 |
$comments .= $this->_complexTypeArg($args, $argarray, $_argtype, $_argname);
|
|
|
711 |
}
|
|
|
712 |
}
|
|
|
713 |
}
|
|
|
714 |
}
|
|
|
715 |
}
|
|
|
716 |
|
|
|
717 |
// Validate entries.
|
|
|
718 |
|
|
|
719 |
// Operation names are function names, so try to make sure it's
|
|
|
720 |
// legal. This could potentially cause collisions, but let's try
|
|
|
721 |
// to make everything callable and see how many problems that
|
|
|
722 |
// causes.
|
|
|
723 |
$opname_php = $this->_sanitize($opname);
|
|
|
724 |
if (!$this->_validateString($opname_php)) {
|
|
|
725 |
return null;
|
|
|
726 |
}
|
|
|
727 |
|
|
|
728 |
if ($argarray) {
|
|
|
729 |
$argarray = "array($argarray)";
|
|
|
730 |
} else {
|
|
|
731 |
$argarray = 'null';
|
|
|
732 |
}
|
|
|
733 |
|
|
|
734 |
$class .= " function &$opname_php($args)\n {\n$comments$wrappers" .
|
|
|
735 |
" \$result = \$this->call('$opname',\n" .
|
|
|
736 |
" \$v = $argarray,\n" .
|
|
|
737 |
" array('namespace' => '$namespace',\n" .
|
|
|
738 |
" 'soapaction' => '$soapaction',\n" .
|
|
|
739 |
" 'style' => '$opstyle',\n" .
|
|
|
740 |
" 'use' => '$use'" .
|
|
|
741 |
($this->trace ? ",\n 'trace' => true" : '') . "));\n" .
|
|
|
742 |
" return \$result;\n" .
|
|
|
743 |
" }\n";
|
|
|
744 |
}
|
|
|
745 |
|
|
|
746 |
$class .= "}\n";
|
|
|
747 |
|
|
|
748 |
return $class;
|
|
|
749 |
}
|
|
|
750 |
|
|
|
751 |
function generateAllProxies()
|
|
|
752 |
{
|
|
|
753 |
$proxycode = '';
|
|
|
754 |
foreach (array_keys($this->services[$this->service]['ports']) as $key) {
|
|
|
755 |
$port =& $this->services[$this->service]['ports'][$key];
|
|
|
756 |
$proxycode .= $this->generateProxyCode($port);
|
|
|
757 |
}
|
|
|
758 |
return $proxycode;
|
|
|
759 |
}
|
|
|
760 |
|
|
|
761 |
function &getProxy($port = '', $name = '')
|
|
|
762 |
{
|
|
|
763 |
if ($this->_isfault()) {
|
|
|
764 |
$fault =& $this->_getfault();
|
|
|
765 |
return $fault;
|
|
|
766 |
}
|
|
|
767 |
|
|
|
768 |
$multiport = count($this->services[$this->service]['ports']) > 1;
|
|
|
769 |
|
|
|
770 |
if (!$port) {
|
|
|
771 |
reset($this->services[$this->service]['ports']);
|
|
|
772 |
$port = current($this->services[$this->service]['ports']);
|
|
|
773 |
}
|
|
|
774 |
|
|
|
775 |
if ($multiport || $port) {
|
|
|
776 |
$classname = 'WebService_' . $this->service . '_' . $port['name'];
|
|
|
777 |
} else {
|
|
|
778 |
$classname = 'WebService_' . $this->service;
|
|
|
779 |
}
|
|
|
780 |
|
|
|
781 |
if ($name) {
|
|
|
782 |
$classname = $name . '_' . $classname;
|
|
|
783 |
}
|
|
|
784 |
|
|
|
785 |
$classname = $this->_sanitize($classname);
|
|
|
786 |
if (!class_exists($classname)) {
|
|
|
787 |
$proxy = $this->generateProxyCode($port, $classname);
|
|
|
788 |
require_once 'SOAP/Client.php';
|
|
|
789 |
eval($proxy);
|
|
|
790 |
}
|
|
|
791 |
$proxy =& new $classname;
|
|
|
792 |
|
|
|
793 |
return $proxy;
|
|
|
794 |
}
|
|
|
795 |
|
|
|
796 |
/**
|
|
|
797 |
* Sanitizes a SOAP value, method or class name so that it can be used as
|
|
|
798 |
* a valid PHP identifier. Invalid characters are converted into
|
|
|
799 |
* underscores and reserved words are prefixed with an underscore.
|
|
|
800 |
*
|
|
|
801 |
* @param string $name The identifier to sanitize.
|
|
|
802 |
*
|
|
|
803 |
* @return string The sanitized identifier.
|
|
|
804 |
*/
|
|
|
805 |
function _sanitize($name)
|
|
|
806 |
{
|
|
|
807 |
$name = preg_replace($this->_invalid, '_', $name);
|
|
|
808 |
if (in_array($name, $this->_reserved)) {
|
|
|
809 |
$name = '_' . $name;
|
|
|
810 |
}
|
|
|
811 |
return $name;
|
|
|
812 |
}
|
|
|
813 |
|
|
|
814 |
function &_getComplexTypeForElement($name, $namespace)
|
|
|
815 |
{
|
|
|
816 |
$t = null;
|
|
|
817 |
if (isset($this->ns[$namespace]) &&
|
|
|
818 |
isset($this->elements[$this->ns[$namespace]][$name]['type'])) {
|
|
|
819 |
|
|
|
820 |
$type = $this->elements[$this->ns[$namespace]][$name]['type'];
|
|
|
821 |
$ns = $this->elements[$this->ns[$namespace]][$name]['namespace'];
|
|
|
822 |
|
|
|
823 |
if (isset($this->complexTypes[$ns][$type])) {
|
|
|
824 |
$t = $this->complexTypes[$ns][$type];
|
|
|
825 |
}
|
|
|
826 |
}
|
|
|
827 |
return $t;
|
|
|
828 |
}
|
|
|
829 |
|
|
|
830 |
function getComplexTypeNameForElement($name, $namespace)
|
|
|
831 |
{
|
|
|
832 |
$t = $this->_getComplexTypeForElement($name, $namespace);
|
|
|
833 |
if ($t) {
|
|
|
834 |
return $t['name'];
|
|
|
835 |
}
|
|
|
836 |
return null;
|
|
|
837 |
}
|
|
|
838 |
|
|
|
839 |
function getComplexTypeChildType($ns, $name, $child_ns, $child_name)
|
|
|
840 |
{
|
|
|
841 |
// Is the type an element?
|
|
|
842 |
$t = $this->_getComplexTypeForElement($name, $ns);
|
|
|
843 |
if ($t) {
|
|
|
844 |
// No, get it from complex types directly.
|
|
|
845 |
if (isset($t['elements'][$child_name]['type']))
|
|
|
846 |
return $t['elements'][$child_name]['type'];
|
|
|
847 |
} elseif (isset($this->ns[$ns]) &&
|
|
|
848 |
isset($this->elements[$this->ns[$ns]][$name]['complex']) &&
|
|
|
849 |
$this->elements[$this->ns[$ns]][$name]['complex']) {
|
|
|
850 |
// Type is not an element but complex.
|
|
|
851 |
return $this->elements[$this->ns[$ns]][$name]['elements'][$child_name]['type'];
|
|
|
852 |
}
|
|
|
853 |
return null;
|
|
|
854 |
}
|
|
|
855 |
|
|
|
856 |
/**
|
|
|
857 |
* @param QName $name A parameter name.
|
|
|
858 |
* @param QName $type A parameter type.
|
|
|
859 |
*
|
|
|
860 |
* @return array A list of [type, array element type, array element
|
|
|
861 |
* namespace, array length].
|
|
|
862 |
*/
|
|
|
863 |
function getSchemaType($type, $name)
|
|
|
864 |
{
|
|
|
865 |
// see if it's a complex type so we can deal properly with
|
|
|
866 |
// SOAPENC:arrayType.
|
|
|
867 |
if ($name && $type) {
|
|
|
868 |
// XXX TODO:
|
|
|
869 |
// look up the name in the wsdl and validate the type.
|
|
|
870 |
foreach ($this->complexTypes as $types) {
|
|
|
871 |
if (isset($types[$type->name])) {
|
|
|
872 |
if (isset($types[$type->name]['type'])) {
|
|
|
873 |
list($arraytype_ns, $arraytype, $array_depth) = isset($types[$type->name]['arrayType'])
|
|
|
874 |
? $this->_getDeepestArrayType($types[$type->name]['namespace'], $types[$type->name]['arrayType'])
|
|
|
875 |
: array($this->namespaces[$types[$type->name]['namespace']], null, 0);
|
|
|
876 |
return array($types[$type->name]['type'], $arraytype, $arraytype_ns, $array_depth);
|
|
|
877 |
}
|
|
|
878 |
if (isset($types[$type->name]['arrayType'])) {
|
|
|
879 |
list($arraytype_ns, $arraytype, $array_depth) =
|
|
|
880 |
$this->_getDeepestArrayType($types[$type->name]['namespace'], $types[$type->name]['arrayType']);
|
|
|
881 |
return array('Array', $arraytype, $arraytype_ns, $array_depth);
|
|
|
882 |
}
|
|
|
883 |
if (!empty($types[$type->name]['elements'][$name->name])) {
|
|
|
884 |
$type->name = $types[$type->name]['elements']['type'];
|
|
|
885 |
return array($type->name, null, $this->namespaces[$types[$type->name]['namespace']], null);
|
|
|
886 |
}
|
|
|
887 |
break;
|
|
|
888 |
}
|
|
|
889 |
}
|
|
|
890 |
}
|
|
|
891 |
if ($type && $type->namespace) {
|
|
|
892 |
$arrayType = null;
|
|
|
893 |
// XXX TODO:
|
|
|
894 |
// this code currently handles only one way of encoding array
|
|
|
895 |
// types in wsdl need to do a generalized function to figure out
|
|
|
896 |
// complex types
|
|
|
897 |
$p = $this->ns[$type->namespace];
|
|
|
898 |
if ($p && !empty($this->complexTypes[$p][$type->name])) {
|
|
|
899 |
if ($arrayType = $this->complexTypes[$p][$type->name]['arrayType']) {
|
|
|
900 |
$type->name = 'Array';
|
|
|
901 |
} elseif ($this->complexTypes[$p][$type->name]['order'] == 'sequence' &&
|
|
|
902 |
array_key_exists('elements', $this->complexTypes[$p][$type->name])) {
|
|
|
903 |
reset($this->complexTypes[$p][$type->name]['elements']);
|
|
|
904 |
// assume an array
|
|
|
905 |
if (count($this->complexTypes[$p][$type->name]['elements']) == 1) {
|
|
|
906 |
$arg = current($this->complexTypes[$p][$type->name]['elements']);
|
|
|
907 |
$arrayType = $arg['type'];
|
|
|
908 |
$type->name = 'Array';
|
|
|
909 |
} else {
|
|
|
910 |
foreach ($this->complexTypes[$p][$type->name]['elements'] as $element) {
|
|
|
911 |
if ($element['name'] == $type->name) {
|
|
|
912 |
$arrayType = $element['type'];
|
|
|
913 |
$type->name = $element['type'];
|
|
|
914 |
}
|
|
|
915 |
}
|
|
|
916 |
}
|
|
|
917 |
} else {
|
|
|
918 |
$type->name = 'Struct';
|
|
|
919 |
}
|
|
|
920 |
return array($type->name, $arrayType, $type->namespace, null);
|
|
|
921 |
}
|
|
|
922 |
}
|
|
|
923 |
return array(null, null, null, null);
|
|
|
924 |
}
|
|
|
925 |
|
|
|
926 |
/**
|
|
|
927 |
* Recurse through the WSDL structure looking for the innermost array type
|
|
|
928 |
* of multi-dimensional arrays.
|
|
|
929 |
*
|
|
|
930 |
* Takes a namespace prefix and a type, which can be in the form 'type' or
|
|
|
931 |
* 'type[]', and returns the full namespace URI, the type of the most
|
|
|
932 |
* deeply nested array type found, and the number of levels of nesting.
|
|
|
933 |
*
|
|
|
934 |
* @access private
|
|
|
935 |
* @return mixed array or nothing
|
|
|
936 |
*/
|
|
|
937 |
function _getDeepestArrayType($nsPrefix, $arrayType)
|
|
|
938 |
{
|
|
|
939 |
static $trail = array();
|
|
|
940 |
|
|
|
941 |
$arrayType = ereg_replace('\[\]$', '', $arrayType);
|
|
|
942 |
|
|
|
943 |
// Protect against circular references XXX We really need to remove
|
|
|
944 |
// trail from this altogether (it's very inefficient and in the wrong
|
|
|
945 |
// place!) and put circular reference checking in when the WSDL info
|
|
|
946 |
// is generated in the first place
|
|
|
947 |
if (array_search($nsPrefix . ':' . $arrayType, $trail)) {
|
|
|
948 |
return array(null, null, -count($trail));
|
|
|
949 |
}
|
|
|
950 |
|
|
|
951 |
if (array_key_exists($nsPrefix, $this->complexTypes) &&
|
|
|
952 |
array_key_exists($arrayType, $this->complexTypes[$nsPrefix]) &&
|
|
|
953 |
array_key_exists('arrayType', $this->complexTypes[$nsPrefix][$arrayType])) {
|
|
|
954 |
$trail[] = $nsPrefix . ':' . $arrayType;
|
|
|
955 |
$result = $this->_getDeepestArrayType($this->complexTypes[$nsPrefix][$arrayType]['namespace'],
|
|
|
956 |
$this->complexTypes[$nsPrefix][$arrayType]['arrayType']);
|
|
|
957 |
return array($result[0], $result[1], $result[2] + 1);
|
|
|
958 |
}
|
|
|
959 |
return array($this->namespaces[$nsPrefix], $arrayType, 0);
|
|
|
960 |
}
|
|
|
961 |
|
|
|
962 |
}
|
|
|
963 |
|
|
|
964 |
class SOAP_WSDL_Cache extends SOAP_Base
|
|
|
965 |
{
|
|
|
966 |
/**
|
|
|
967 |
* Use WSDL cache?
|
|
|
968 |
*
|
|
|
969 |
* @var boolean
|
|
|
970 |
*/
|
|
|
971 |
var $_cacheUse;
|
|
|
972 |
|
|
|
973 |
/**
|
|
|
974 |
* WSDL cache directory.
|
|
|
975 |
*
|
|
|
976 |
* @var string
|
|
|
977 |
*/
|
|
|
978 |
var $_cacheDir;
|
|
|
979 |
|
|
|
980 |
/**
|
|
|
981 |
* Cache maximum lifetime (in seconds)
|
|
|
982 |
*
|
|
|
983 |
* @var integer
|
|
|
984 |
*/
|
|
|
985 |
var $_cacheMaxAge;
|
|
|
986 |
|
|
|
987 |
/**
|
|
|
988 |
* Constructor.
|
|
|
989 |
*
|
|
|
990 |
* @param boolean $cashUse Use caching?
|
|
|
991 |
* @param integer $cacheMaxAge Cache maximum lifetime (in seconds)
|
|
|
992 |
*/
|
|
|
993 |
function SOAP_WSDL_Cache($cacheUse = false,
|
|
|
994 |
$cacheMaxAge = WSDL_CACHE_MAX_AGE,
|
|
|
995 |
$cacheDir = null)
|
|
|
996 |
{
|
|
|
997 |
parent::SOAP_Base('WSDLCACHE');
|
|
|
998 |
$this->_cacheUse = $cacheUse;
|
|
|
999 |
$this->_cacheDir = $cacheDir;
|
|
|
1000 |
$this->_cacheMaxAge = $cacheMaxAge;
|
|
|
1001 |
}
|
|
|
1002 |
|
|
|
1003 |
/**
|
|
|
1004 |
* Returns the path to the cache and creates it, if it doesn't exist.
|
|
|
1005 |
*
|
|
|
1006 |
* @private
|
|
|
1007 |
*
|
|
|
1008 |
* @return string The directory to use for the cache.
|
|
|
1009 |
*/
|
|
|
1010 |
function _cacheDir()
|
|
|
1011 |
{
|
|
|
1012 |
if (!empty($this->_cacheDir)) {
|
|
|
1013 |
$dir = $this->_cacheDir;
|
|
|
1014 |
} else {
|
|
|
1015 |
$dir = getenv('WSDLCACHE');
|
|
|
1016 |
if (empty($dir)) {
|
|
|
1017 |
$dir = './wsdlcache';
|
|
|
1018 |
}
|
|
|
1019 |
}
|
|
|
1020 |
@mkdir($dir, 0700);
|
|
|
1021 |
return $dir;
|
|
|
1022 |
}
|
|
|
1023 |
|
|
|
1024 |
/**
|
|
|
1025 |
* Retrieves a file from cache if it exists, otherwise retreive from net,
|
|
|
1026 |
* add to cache, and return from cache.
|
|
|
1027 |
*
|
|
|
1028 |
* @param string URL to WSDL
|
|
|
1029 |
* @param array proxy parameters
|
|
|
1030 |
* @param int expected MD5 of WSDL URL
|
|
|
1031 |
* @access public
|
|
|
1032 |
* @return string data
|
|
|
1033 |
*/
|
|
|
1034 |
function get($wsdl_fname, $proxy_params = array(), $cache = 0)
|
|
|
1035 |
{
|
|
|
1036 |
$cachename = $md5_wsdl = $file_data = '';
|
|
|
1037 |
if ($this->_cacheUse) {
|
|
|
1038 |
// Try to retrieve WSDL from cache
|
|
|
1039 |
$cachename = $this->_cacheDir() . '/' . md5($wsdl_fname). ' .wsdl';
|
|
|
1040 |
if (file_exists($cachename) &&
|
|
|
1041 |
$file_data = file_get_contents($cachename)) {
|
|
|
1042 |
$md5_wsdl = md5($file_data);
|
|
|
1043 |
if ($cache) {
|
|
|
1044 |
if ($cache != $md5_wsdl) {
|
|
|
1045 |
return $this->_raiseSoapFault('WSDL Checksum error!', $wsdl_fname);
|
|
|
1046 |
}
|
|
|
1047 |
} else {
|
|
|
1048 |
$fi = stat($cachename);
|
|
|
1049 |
$cache_mtime = $fi[8];
|
|
|
1050 |
if ($cache_mtime + $this->_cacheMaxAge < time()) {
|
|
|
1051 |
// Expired, refetch.
|
|
|
1052 |
$md5_wsdl = '';
|
|
|
1053 |
}
|
|
|
1054 |
}
|
|
|
1055 |
}
|
|
|
1056 |
}
|
|
|
1057 |
|
|
|
1058 |
// Not cached or not using cache. Retrieve WSDL from URL
|
|
|
1059 |
if (!$md5_wsdl) {
|
|
|
1060 |
// Is it a local file?
|
|
|
1061 |
if (strpos($wsdl_fname, 'file://') === 0) {
|
|
|
1062 |
$wsdl_fname = substr($wsdl_fname, 7);
|
|
|
1063 |
if (!file_exists($wsdl_fname)) {
|
|
|
1064 |
return $this->_raiseSoapFault('Unable to read local WSDL file', $wsdl_fname);
|
|
|
1065 |
}
|
|
|
1066 |
$file_data = file_get_contents($wsdl_fname);
|
|
|
1067 |
} elseif (!preg_match('|^https?://|', $wsdl_fname)) {
|
|
|
1068 |
return $this->_raiseSoapFault('Unknown schema of WSDL URL', $wsdl_fname);
|
|
|
1069 |
} else {
|
|
|
1070 |
$uri = explode('?', $wsdl_fname);
|
|
|
1071 |
$rq = new HTTP_Request($uri[0], $proxy_params);
|
|
|
1072 |
// the user agent HTTP_Request uses fouls things up
|
|
|
1073 |
if (isset($uri[1])) {
|
|
|
1074 |
$rq->addRawQueryString($uri[1]);
|
|
|
1075 |
}
|
|
|
1076 |
|
|
|
1077 |
if (isset($proxy_params['proxy_host']) &&
|
|
|
1078 |
isset($proxy_params['proxy_port']) &&
|
|
|
1079 |
isset($proxy_params['proxy_user']) &&
|
|
|
1080 |
isset($proxy_params['proxy_pass'])) {
|
|
|
1081 |
$rq->setProxy($proxy_params['proxy_host'],
|
|
|
1082 |
$proxy_params['proxy_port'],
|
|
|
1083 |
$proxy_params['proxy_user'],
|
|
|
1084 |
$proxy_params['proxy_pass']);
|
|
|
1085 |
} elseif (isset($proxy_params['proxy_host']) &&
|
|
|
1086 |
isset($proxy_params['proxy_port'])) {
|
|
|
1087 |
$rq->setProxy($proxy_params['proxy_host'],
|
|
|
1088 |
$proxy_params['proxy_port']);
|
|
|
1089 |
}
|
|
|
1090 |
|
|
|
1091 |
$result = $rq->sendRequest();
|
|
|
1092 |
if (PEAR::isError($result)) {
|
|
|
1093 |
return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname," . $rq->getResponseCode(), $wsdl_fname);
|
|
|
1094 |
}
|
|
|
1095 |
$file_data = $rq->getResponseBody();
|
|
|
1096 |
if (!$file_data) {
|
|
|
1097 |
return $this->_raiseSoapFault("Unable to retrieve WSDL $wsdl_fname, no http body", $wsdl_fname);
|
|
|
1098 |
}
|
|
|
1099 |
}
|
|
|
1100 |
|
|
|
1101 |
$md5_wsdl = md5($file_data);
|
|
|
1102 |
|
|
|
1103 |
if ($this->_cacheUse) {
|
|
|
1104 |
$fp = fopen($cachename, "wb");
|
|
|
1105 |
fwrite($fp, $file_data);
|
|
|
1106 |
fclose($fp);
|
|
|
1107 |
}
|
|
|
1108 |
}
|
|
|
1109 |
|
|
|
1110 |
if ($this->_cacheUse && $cache && $cache != $md5_wsdl) {
|
|
|
1111 |
return $this->_raiseSoapFault('WSDL Checksum error!', $wsdl_fname);
|
|
|
1112 |
}
|
|
|
1113 |
|
|
|
1114 |
return $file_data;
|
|
|
1115 |
}
|
|
|
1116 |
|
|
|
1117 |
}
|
|
|
1118 |
|
|
|
1119 |
class SOAP_WSDL_Parser extends SOAP_Base
|
|
|
1120 |
{
|
|
|
1121 |
|
|
|
1122 |
/**
|
|
|
1123 |
* Define internal arrays of bindings, ports, operations,
|
|
|
1124 |
* messages, etc.
|
|
|
1125 |
*/
|
|
|
1126 |
var $currentMessage;
|
|
|
1127 |
var $currentOperation;
|
|
|
1128 |
var $currentPortType;
|
|
|
1129 |
var $currentBinding;
|
|
|
1130 |
var $currentPort;
|
|
|
1131 |
|
|
|
1132 |
/**
|
|
|
1133 |
* Parser vars.
|
|
|
1134 |
*/
|
|
|
1135 |
var $cache;
|
|
|
1136 |
|
|
|
1137 |
var $tns = null;
|
|
|
1138 |
var $soapns = array('soap');
|
|
|
1139 |
var $uri = '';
|
|
|
1140 |
var $wsdl = null;
|
|
|
1141 |
|
|
|
1142 |
var $status = '';
|
|
|
1143 |
var $element_stack = array();
|
|
|
1144 |
var $parentElement = '';
|
|
|
1145 |
|
|
|
1146 |
var $schema = '';
|
|
|
1147 |
var $schemaStatus = '';
|
|
|
1148 |
var $schema_stack = array();
|
|
|
1149 |
var $currentComplexType;
|
|
|
1150 |
var $schema_element_stack = array();
|
|
|
1151 |
var $currentElement;
|
|
|
1152 |
|
|
|
1153 |
/**
|
|
|
1154 |
* Constructor.
|
|
|
1155 |
*/
|
|
|
1156 |
function SOAP_WSDL_Parser($uri, &$wsdl, $docs = false)
|
|
|
1157 |
{
|
|
|
1158 |
parent::SOAP_Base('WSDLPARSER');
|
|
|
1159 |
$this->cache =& new SOAP_WSDL_Cache($wsdl->cacheUse,
|
|
|
1160 |
$wsdl->cacheMaxAge,
|
|
|
1161 |
$wsdl->cacheDir);
|
|
|
1162 |
$this->uri = $uri;
|
|
|
1163 |
$this->wsdl = &$wsdl;
|
|
|
1164 |
$this->docs = $docs;
|
|
|
1165 |
$this->parse($uri);
|
|
|
1166 |
}
|
|
|
1167 |
|
|
|
1168 |
function parse($uri)
|
|
|
1169 |
{
|
|
|
1170 |
// Check whether content has been read.
|
|
|
1171 |
$fd = $this->cache->get($uri, $this->wsdl->proxy);
|
|
|
1172 |
if (PEAR::isError($fd)) {
|
|
|
1173 |
return $this->_raiseSoapFault($fd);
|
|
|
1174 |
}
|
|
|
1175 |
|
|
|
1176 |
// Create an XML parser.
|
|
|
1177 |
$parser = xml_parser_create();
|
|
|
1178 |
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
|
|
1179 |
xml_set_object($parser, $this);
|
|
|
1180 |
xml_set_element_handler($parser, 'startElement', 'endElement');
|
|
|
1181 |
if ($this->docs) {
|
|
|
1182 |
xml_set_character_data_handler($parser, 'characterData');
|
|
|
1183 |
}
|
|
|
1184 |
|
|
|
1185 |
if (!xml_parse($parser, $fd, true)) {
|
|
|
1186 |
$detail = sprintf('XML error on line %d: %s',
|
|
|
1187 |
xml_get_current_line_number($parser),
|
|
|
1188 |
xml_error_string(xml_get_error_code($parser)));
|
|
|
1189 |
return $this->_raiseSoapFault("Unable to parse WSDL file $uri\n$detail");
|
|
|
1190 |
}
|
|
|
1191 |
xml_parser_free($parser);
|
|
|
1192 |
return true;
|
|
|
1193 |
}
|
|
|
1194 |
|
|
|
1195 |
/**
|
|
|
1196 |
* start-element handler
|
|
|
1197 |
*/
|
|
|
1198 |
function startElement($parser, $name, $attrs)
|
|
|
1199 |
{
|
|
|
1200 |
// Get element prefix.
|
|
|
1201 |
$qname = new QName($name);
|
|
|
1202 |
if ($qname->ns) {
|
|
|
1203 |
$ns = $qname->ns;
|
|
|
1204 |
if ($ns && ((!$this->tns && strcasecmp($qname->name, 'definitions') == 0) || $ns == $this->tns)) {
|
|
|
1205 |
$name = $qname->name;
|
|
|
1206 |
}
|
|
|
1207 |
}
|
|
|
1208 |
$this->currentTag = $qname->name;
|
|
|
1209 |
$this->parentElement = '';
|
|
|
1210 |
$stack_size = count($this->element_stack);
|
|
|
1211 |
if ($stack_size) {
|
|
|
1212 |
$this->parentElement = $this->element_stack[$stack_size - 1];
|
|
|
1213 |
}
|
|
|
1214 |
$this->element_stack[] = $this->currentTag;
|
|
|
1215 |
|
|
|
1216 |
// Find status, register data.
|
|
|
1217 |
switch ($this->status) {
|
|
|
1218 |
case 'types':
|
|
|
1219 |
// sect 2.2 wsdl:types
|
|
|
1220 |
// children: xsd:schema
|
|
|
1221 |
$parent_tag = '';
|
|
|
1222 |
$stack_size = count($this->schema_stack);
|
|
|
1223 |
if ($stack_size) {
|
|
|
1224 |
$parent_tag = $this->schema_stack[$stack_size - 1];
|
|
|
1225 |
}
|
|
|
1226 |
|
|
|
1227 |
switch ($qname->name) {
|
|
|
1228 |
case 'schema':
|
|
|
1229 |
// No parent should be in the stack.
|
|
|
1230 |
if (!$parent_tag || $parent_tag == 'types') {
|
|
|
1231 |
if (array_key_exists('targetNamespace', $attrs)) {
|
|
|
1232 |
$this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']);
|
|
|
1233 |
} else {
|
|
|
1234 |
$this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns);
|
|
|
1235 |
}
|
|
|
1236 |
$this->wsdl->complexTypes[$this->schema] = array();
|
|
|
1237 |
$this->wsdl->elements[$this->schema] = array();
|
|
|
1238 |
}
|
|
|
1239 |
break;
|
|
|
1240 |
|
|
|
1241 |
case 'complexType':
|
|
|
1242 |
if ($parent_tag == 'schema') {
|
|
|
1243 |
$this->currentComplexType = $attrs['name'];
|
|
|
1244 |
if (!isset($attrs['namespace'])) {
|
|
|
1245 |
$attrs['namespace'] = $this->schema;
|
|
|
1246 |
}
|
|
|
1247 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType] = $attrs;
|
|
|
1248 |
if (array_key_exists('base', $attrs)) {
|
|
|
1249 |
$qn = new QName($attrs['base']);
|
|
|
1250 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name;
|
|
|
1251 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $qn->ns;
|
|
|
1252 |
} else {
|
|
|
1253 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
|
|
|
1254 |
}
|
|
|
1255 |
$this->schemaStatus = 'complexType';
|
|
|
1256 |
} else {
|
|
|
1257 |
$this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = true;
|
|
|
1258 |
}
|
|
|
1259 |
break;
|
|
|
1260 |
|
|
|
1261 |
case 'element':
|
|
|
1262 |
if (isset($attrs['type'])) {
|
|
|
1263 |
$qn = new QName($attrs['type']);
|
|
|
1264 |
$attrs['type'] = $qn->name;
|
|
|
1265 |
if ($qn->ns && array_key_exists($qn->ns, $this->wsdl->namespaces)) {
|
|
|
1266 |
$attrs['namespace'] = $qn->ns;
|
|
|
1267 |
}
|
|
|
1268 |
}
|
|
|
1269 |
|
|
|
1270 |
$parentElement = '';
|
|
|
1271 |
$stack_size = count($this->schema_element_stack);
|
|
|
1272 |
if ($stack_size > 0) {
|
|
|
1273 |
$parentElement = $this->schema_element_stack[$stack_size - 1];
|
|
|
1274 |
}
|
|
|
1275 |
|
|
|
1276 |
if (isset($attrs['ref'])) {
|
|
|
1277 |
$qn = new QName($attrs['ref']);
|
|
|
1278 |
$this->currentElement = $qn->name;
|
|
|
1279 |
} else {
|
|
|
1280 |
$this->currentElement = $attrs['name'];
|
|
|
1281 |
}
|
|
|
1282 |
$this->schema_element_stack[] = $this->currentElement;
|
|
|
1283 |
if (!isset($attrs['namespace'])) {
|
|
|
1284 |
$attrs['namespace'] = $this->schema;
|
|
|
1285 |
}
|
|
|
1286 |
|
|
|
1287 |
if ($parent_tag == 'schema') {
|
|
|
1288 |
$this->wsdl->elements[$this->schema][$this->currentElement] = $attrs;
|
|
|
1289 |
$this->wsdl->elements[$this->schema][$this->currentElement]['complex'] = false;
|
|
|
1290 |
$this->schemaStatus = 'element';
|
|
|
1291 |
} elseif ($this->currentComplexType) {
|
|
|
1292 |
// we're inside a complexType
|
|
|
1293 |
if ((isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order']) &&
|
|
|
1294 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] == 'sequence')
|
|
|
1295 |
&& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array') {
|
|
|
1296 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['arrayType'] = isset($attrs['type']) ? $attrs['type'] : null;
|
|
|
1297 |
}
|
|
|
1298 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement] = $attrs;
|
|
|
1299 |
} else {
|
|
|
1300 |
$this->wsdl->elements[$this->schema][$parentElement]['elements'][$this->currentElement] = $attrs;
|
|
|
1301 |
}
|
|
|
1302 |
break;
|
|
|
1303 |
|
|
|
1304 |
case 'complexContent':
|
|
|
1305 |
case 'simpleContent':
|
|
|
1306 |
break;
|
|
|
1307 |
|
|
|
1308 |
case 'extension':
|
|
|
1309 |
case 'restriction':
|
|
|
1310 |
if ($this->schemaStatus == 'complexType') {
|
|
|
1311 |
if (!empty($attrs['base'])) {
|
|
|
1312 |
$qn = new QName($attrs['base']);
|
|
|
1313 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = $qn->name;
|
|
|
1314 |
|
|
|
1315 |
// Types that extend from other types aren't
|
|
|
1316 |
// *of* those types. Reflect this by denoting
|
|
|
1317 |
// which type they extend. I'm leaving the
|
|
|
1318 |
// 'type' setting here since I'm not sure what
|
|
|
1319 |
// removing it might break at the moment.
|
|
|
1320 |
if ($qname->name == 'extension') {
|
|
|
1321 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['extends'] = $qn->name;
|
|
|
1322 |
}
|
|
|
1323 |
} else {
|
|
|
1324 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
|
|
|
1325 |
}
|
|
|
1326 |
}
|
|
|
1327 |
break;
|
|
|
1328 |
|
|
|
1329 |
case 'sequence':
|
|
|
1330 |
if ($this->schemaStatus == 'complexType') {
|
|
|
1331 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
|
|
|
1332 |
if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) {
|
|
|
1333 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
|
|
|
1334 |
}
|
|
|
1335 |
}
|
|
|
1336 |
break;
|
|
|
1337 |
|
|
|
1338 |
case 'all':
|
|
|
1339 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
|
|
|
1340 |
if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) {
|
|
|
1341 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
|
|
|
1342 |
}
|
|
|
1343 |
break;
|
|
|
1344 |
|
|
|
1345 |
case 'choice':
|
|
|
1346 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['order'] = $qname->name;
|
|
|
1347 |
if (!isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])) {
|
|
|
1348 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
|
|
|
1349 |
}
|
|
|
1350 |
|
|
|
1351 |
case 'attribute':
|
|
|
1352 |
if ($this->schemaStatus == 'complexType') {
|
|
|
1353 |
if (isset($attrs['name'])) {
|
|
|
1354 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['attribute'][$attrs['name']] = $attrs;
|
|
|
1355 |
} else {
|
|
|
1356 |
if (isset($attrs['ref'])) {
|
|
|
1357 |
$q = new QName($attrs['ref']);
|
|
|
1358 |
foreach ($attrs as $k => $v) {
|
|
|
1359 |
if ($k != 'ref' && strstr($k, $q->name)) {
|
|
|
1360 |
$vq = new QName($v);
|
|
|
1361 |
if ($q->name == 'arrayType') {
|
|
|
1362 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name. $vq->arrayInfo;
|
|
|
1363 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Array';
|
|
|
1364 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['namespace'] = $vq->ns;
|
|
|
1365 |
} else {
|
|
|
1366 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType][$q->name] = $vq->name;
|
|
|
1367 |
}
|
|
|
1368 |
}
|
|
|
1369 |
}
|
|
|
1370 |
}
|
|
|
1371 |
}
|
|
|
1372 |
}
|
|
|
1373 |
break;
|
|
|
1374 |
}
|
|
|
1375 |
|
|
|
1376 |
$this->schema_stack[] = $qname->name;
|
|
|
1377 |
break;
|
|
|
1378 |
|
|
|
1379 |
case 'message':
|
|
|
1380 |
// sect 2.3 wsdl:message child wsdl:part
|
|
|
1381 |
switch ($qname->name) {
|
|
|
1382 |
case 'part':
|
|
|
1383 |
$qn = null;
|
|
|
1384 |
if (isset($attrs['type'])) {
|
|
|
1385 |
$qn = new QName($attrs['type']);
|
|
|
1386 |
} elseif (isset($attrs['element'])) {
|
|
|
1387 |
$qn = new QName($attrs['element']);
|
|
|
1388 |
}
|
|
|
1389 |
if ($qn) {
|
|
|
1390 |
$attrs['type'] = $qn->name;
|
|
|
1391 |
$attrs['namespace'] = $qn->ns;
|
|
|
1392 |
}
|
|
|
1393 |
$this->wsdl->messages[$this->currentMessage][$attrs['name']] = $attrs;
|
|
|
1394 |
// error in wsdl
|
|
|
1395 |
|
|
|
1396 |
case 'documentation':
|
|
|
1397 |
break;
|
|
|
1398 |
|
|
|
1399 |
default:
|
|
|
1400 |
break;
|
|
|
1401 |
}
|
|
|
1402 |
break;
|
|
|
1403 |
|
|
|
1404 |
case 'portType':
|
|
|
1405 |
// sect 2.4
|
|
|
1406 |
switch ($qname->name) {
|
|
|
1407 |
case 'operation':
|
|
|
1408 |
// attributes: name
|
|
|
1409 |
// children: wsdl:input wsdl:output wsdl:fault
|
|
|
1410 |
$this->currentOperation = $attrs['name'];
|
|
|
1411 |
$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation] = $attrs;
|
|
|
1412 |
break;
|
|
|
1413 |
|
|
|
1414 |
case 'input':
|
|
|
1415 |
case 'output':
|
|
|
1416 |
case 'fault':
|
|
|
1417 |
// wsdl:input wsdl:output wsdl:fault
|
|
|
1418 |
// attributes: name message parameterOrder(optional)
|
|
|
1419 |
if ($this->currentOperation) {
|
|
|
1420 |
if (isset($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name])) {
|
|
|
1421 |
$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = array_merge($this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name], $attrs);
|
|
|
1422 |
} else {
|
|
|
1423 |
$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name] = $attrs;
|
|
|
1424 |
}
|
|
|
1425 |
if (array_key_exists('message', $attrs)) {
|
|
|
1426 |
$qn = new QName($attrs['message']);
|
|
|
1427 |
$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['message'] = $qn->name;
|
|
|
1428 |
$this->wsdl->portTypes[$this->currentPortType][$this->currentOperation][$name]['namespace'] = $qn->ns;
|
|
|
1429 |
}
|
|
|
1430 |
}
|
|
|
1431 |
break;
|
|
|
1432 |
|
|
|
1433 |
case 'documentation':
|
|
|
1434 |
break;
|
|
|
1435 |
|
|
|
1436 |
default:
|
|
|
1437 |
break;
|
|
|
1438 |
}
|
|
|
1439 |
break;
|
|
|
1440 |
|
|
|
1441 |
case 'binding':
|
|
|
1442 |
$ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
|
|
|
1443 |
switch ($ns) {
|
|
|
1444 |
case SCHEMA_SOAP:
|
|
|
1445 |
case SCHEMA_SOAP12:
|
|
|
1446 |
// this deals with wsdl section 3 soap binding
|
|
|
1447 |
switch ($qname->name) {
|
|
|
1448 |
case 'binding':
|
|
|
1449 |
// sect 3.3
|
|
|
1450 |
// soap:binding, attributes: transport(required), style(optional, default = document)
|
|
|
1451 |
// if style is missing, it is assumed to be 'document'
|
|
|
1452 |
if (!isset($attrs['style'])) {
|
|
|
1453 |
$attrs['style'] = 'document';
|
|
|
1454 |
}
|
|
|
1455 |
$this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding], $attrs);
|
|
|
1456 |
break;
|
|
|
1457 |
|
|
|
1458 |
case 'operation':
|
|
|
1459 |
// sect 3.4
|
|
|
1460 |
// soap:operation, attributes: soapAction(required), style(optional, default = soap:binding:style)
|
|
|
1461 |
if (!isset($attrs['style'])) {
|
|
|
1462 |
$attrs['style'] = $this->wsdl->bindings[$this->currentBinding]['style'];
|
|
|
1463 |
}
|
|
|
1464 |
if (isset($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation])) {
|
|
|
1465 |
$this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = array_merge($this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation], $attrs);
|
|
|
1466 |
} else {
|
|
|
1467 |
$this->wsdl->bindings[$this->currentBinding]['operations'][$this->currentOperation] = $attrs;
|
|
|
1468 |
}
|
|
|
1469 |
break;
|
|
|
1470 |
|
|
|
1471 |
case 'body':
|
|
|
1472 |
// sect 3.5
|
|
|
1473 |
// soap:body attributes:
|
|
|
1474 |
// part - optional. listed parts must appear in body, missing means all parts appear in body
|
|
|
1475 |
// use - required. encoded|literal
|
|
|
1476 |
// encodingStyle - optional. space seperated list of encodings (uri's)
|
|
|
1477 |
$this->wsdl->bindings[$this->currentBinding]
|
|
|
1478 |
['operations'][$this->currentOperation][$this->opStatus] = $attrs;
|
|
|
1479 |
break;
|
|
|
1480 |
|
|
|
1481 |
case 'fault':
|
|
|
1482 |
// sect 3.6
|
|
|
1483 |
// soap:fault attributes: name use encodingStyle namespace
|
|
|
1484 |
$this->wsdl->bindings[$this->currentBinding]
|
|
|
1485 |
['operations'][$this->currentOperation][$this->opStatus] = $attrs;
|
|
|
1486 |
break;
|
|
|
1487 |
|
|
|
1488 |
case 'header':
|
|
|
1489 |
// sect 3.7
|
|
|
1490 |
// soap:header attributes: message part use encodingStyle namespace
|
|
|
1491 |
$this->wsdl->bindings[$this->currentBinding]
|
|
|
1492 |
['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
|
|
|
1493 |
break;
|
|
|
1494 |
|
|
|
1495 |
case 'headerfault':
|
|
|
1496 |
// sect 3.7
|
|
|
1497 |
// soap:header attributes: message part use encodingStyle namespace
|
|
|
1498 |
$header = count($this->wsdl->bindings[$this->currentBinding]
|
|
|
1499 |
['operations'][$this->currentOperation][$this->opStatus]['headers'])-1;
|
|
|
1500 |
$this->wsdl->bindings[$this->currentBinding]
|
|
|
1501 |
['operations'][$this->currentOperation][$this->opStatus]['headers'][$header]['fault'] = $attrs;
|
|
|
1502 |
break;
|
|
|
1503 |
|
|
|
1504 |
case 'documentation':
|
|
|
1505 |
break;
|
|
|
1506 |
|
|
|
1507 |
default:
|
|
|
1508 |
// error! not a valid element inside binding
|
|
|
1509 |
break;
|
|
|
1510 |
}
|
|
|
1511 |
break;
|
|
|
1512 |
|
|
|
1513 |
case SCHEMA_WSDL:
|
|
|
1514 |
// XXX verify correct namespace
|
|
|
1515 |
// for now, default is the 'wsdl' namespace
|
|
|
1516 |
// other possible namespaces include smtp, http, etc. for alternate bindings
|
|
|
1517 |
switch ($qname->name) {
|
|
|
1518 |
case 'operation':
|
|
|
1519 |
// sect 2.5
|
|
|
1520 |
// wsdl:operation attributes: name
|
|
|
1521 |
$this->currentOperation = $attrs['name'];
|
|
|
1522 |
break;
|
|
|
1523 |
|
|
|
1524 |
case 'output':
|
|
|
1525 |
case 'input':
|
|
|
1526 |
case 'fault':
|
|
|
1527 |
// sect 2.5
|
|
|
1528 |
// wsdl:input attributes: name
|
|
|
1529 |
$this->opStatus = $qname->name;
|
|
|
1530 |
break;
|
|
|
1531 |
|
|
|
1532 |
case 'documentation':
|
|
|
1533 |
break;
|
|
|
1534 |
|
|
|
1535 |
default:
|
|
|
1536 |
break;
|
|
|
1537 |
}
|
|
|
1538 |
break;
|
|
|
1539 |
|
|
|
1540 |
case SCHEMA_WSDL_HTTP:
|
|
|
1541 |
switch ($qname->name) {
|
|
|
1542 |
case 'binding':
|
|
|
1543 |
// sect 4.4
|
|
|
1544 |
// http:binding attributes: verb
|
|
|
1545 |
// parent: wsdl:binding
|
|
|
1546 |
$this->wsdl->bindings[$this->currentBinding] = array_merge($this->wsdl->bindings[$this->currentBinding], $attrs);
|
|
|
1547 |
break;
|
|
|
1548 |
|
|
|
1549 |
case 'operation':
|
|
|
1550 |
// sect 4.5
|
|
|
1551 |
// http:operation attributes: location
|
|
|
1552 |
// parent: wsdl:operation
|
|
|
1553 |
$this->wsdl->bindings[$this->currentBinding]['operations']
|
|
|
1554 |
[$this->currentOperation] = $attrs;
|
|
|
1555 |
break;
|
|
|
1556 |
|
|
|
1557 |
case 'urlEncoded':
|
|
|
1558 |
// sect 4.6
|
|
|
1559 |
// http:urlEncoded attributes: location
|
|
|
1560 |
// parent: wsdl:input wsdl:output etc.
|
|
|
1561 |
$this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
|
|
|
1562 |
[$this->currentOperation]['uri'] = 'urlEncoded';
|
|
|
1563 |
break;
|
|
|
1564 |
|
|
|
1565 |
case 'urlReplacement':
|
|
|
1566 |
// sect 4.7
|
|
|
1567 |
// http:urlReplacement attributes: location
|
|
|
1568 |
// parent: wsdl:input wsdl:output etc.
|
|
|
1569 |
$this->wsdl->bindings[$this->currentBinding]['operations'][$this->opStatus]
|
|
|
1570 |
[$this->currentOperation]['uri'] = 'urlReplacement';
|
|
|
1571 |
break;
|
|
|
1572 |
|
|
|
1573 |
case 'documentation':
|
|
|
1574 |
break;
|
|
|
1575 |
|
|
|
1576 |
default:
|
|
|
1577 |
// error
|
|
|
1578 |
break;
|
|
|
1579 |
}
|
|
|
1580 |
|
|
|
1581 |
case SCHEMA_MIME:
|
|
|
1582 |
// sect 5
|
|
|
1583 |
// all mime parts are children of wsdl:input, wsdl:output, etc.
|
|
|
1584 |
// unsuported as of yet
|
|
|
1585 |
switch ($qname->name) {
|
|
|
1586 |
case 'content':
|
|
|
1587 |
// sect 5.3 mime:content
|
|
|
1588 |
// <mime:content part="nmtoken"? type="string"?/>
|
|
|
1589 |
// part attribute only required if content is child of multipart related,
|
|
|
1590 |
// it contains the name of the part
|
|
|
1591 |
// type attribute contains the mime type
|
|
|
1592 |
case 'multipartRelated':
|
|
|
1593 |
// sect 5.4 mime:multipartRelated
|
|
|
1594 |
case 'part':
|
|
|
1595 |
case 'mimeXml':
|
|
|
1596 |
// sect 5.6 mime:mimeXml
|
|
|
1597 |
// <mime:mimeXml part="nmtoken"?/>
|
|
|
1598 |
//
|
|
|
1599 |
case 'documentation':
|
|
|
1600 |
break;
|
|
|
1601 |
|
|
|
1602 |
default:
|
|
|
1603 |
// error
|
|
|
1604 |
break;
|
|
|
1605 |
}
|
|
|
1606 |
|
|
|
1607 |
case SCHEMA_DIME:
|
|
|
1608 |
// DIME is defined in:
|
|
|
1609 |
// http://gotdotnet.com/team/xml_wsspecs/dime/WSDL-Extension-for-DIME.htm
|
|
|
1610 |
// all DIME parts are children of wsdl:input, wsdl:output, etc.
|
|
|
1611 |
// unsuported as of yet
|
|
|
1612 |
switch ($qname->name) {
|
|
|
1613 |
case 'message':
|
|
|
1614 |
// sect 4.1 dime:message
|
|
|
1615 |
// appears in binding section
|
|
|
1616 |
$this->wsdl->bindings[$this->currentBinding]['dime'] = $attrs;
|
|
|
1617 |
break;
|
|
|
1618 |
|
|
|
1619 |
default:
|
|
|
1620 |
break;
|
|
|
1621 |
}
|
|
|
1622 |
|
|
|
1623 |
default:
|
|
|
1624 |
break;
|
|
|
1625 |
}
|
|
|
1626 |
break;
|
|
|
1627 |
|
|
|
1628 |
case 'service':
|
|
|
1629 |
$ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
|
|
|
1630 |
|
|
|
1631 |
switch ($qname->name) {
|
|
|
1632 |
case 'port':
|
|
|
1633 |
// sect 2.6 wsdl:port attributes: name binding
|
|
|
1634 |
$this->currentPort = $attrs['name'];
|
|
|
1635 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort] = $attrs;
|
|
|
1636 |
// XXX hack to deal with binding namespaces
|
|
|
1637 |
$qn = new QName($attrs['binding']);
|
|
|
1638 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['binding'] = $qn->name;
|
|
|
1639 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['namespace'] = $qn->ns;
|
|
|
1640 |
break;
|
|
|
1641 |
|
|
|
1642 |
case 'address':
|
|
|
1643 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['address'] = $attrs;
|
|
|
1644 |
// what TYPE of port is it? SOAP or HTTP?
|
|
|
1645 |
$ns = $qname->ns ? $this->wsdl->namespaces[$qname->ns] : SCHEMA_WSDL;
|
|
|
1646 |
switch ($ns) {
|
|
|
1647 |
case SCHEMA_WSDL_HTTP:
|
|
|
1648 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='http';
|
|
|
1649 |
break;
|
|
|
1650 |
|
|
|
1651 |
case SCHEMA_SOAP:
|
|
|
1652 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
|
|
|
1653 |
break;
|
|
|
1654 |
|
|
|
1655 |
default:
|
|
|
1656 |
// Shouldn't happen, we'll assume SOAP.
|
|
|
1657 |
$this->wsdl->services[$this->currentService]['ports'][$this->currentPort]['type']='soap';
|
|
|
1658 |
}
|
|
|
1659 |
|
|
|
1660 |
break;
|
|
|
1661 |
|
|
|
1662 |
case 'documentation':
|
|
|
1663 |
break;
|
|
|
1664 |
|
|
|
1665 |
default:
|
|
|
1666 |
break;
|
|
|
1667 |
}
|
|
|
1668 |
}
|
|
|
1669 |
|
|
|
1670 |
// Top level elements found under wsdl:definitions.
|
|
|
1671 |
switch ($qname->name) {
|
|
|
1672 |
case 'import':
|
|
|
1673 |
// sect 2.1.1 wsdl:import attributes: namespace location
|
|
|
1674 |
if ((isset($attrs['location']) || isset($attrs['schemaLocation'])) &&
|
|
|
1675 |
!isset($this->wsdl->imports[$attrs['namespace']])) {
|
|
|
1676 |
$uri = isset($attrs['location']) ? $attrs['location'] : $attrs['schemaLocation'];
|
|
|
1677 |
$location = @parse_url($uri);
|
|
|
1678 |
if (!isset($location['scheme'])) {
|
|
|
1679 |
$base = @parse_url($this->uri);
|
|
|
1680 |
$uri = $this->mergeUrl($base, $uri);
|
|
|
1681 |
}
|
|
|
1682 |
|
|
|
1683 |
$this->wsdl->imports[$attrs['namespace']] = $attrs;
|
|
|
1684 |
$import_parser_class = get_class($this);
|
|
|
1685 |
$import_parser =& new $import_parser_class($uri, $this->wsdl, $this->docs);
|
|
|
1686 |
if ($import_parser->fault) {
|
|
|
1687 |
unset($this->wsdl->imports[$attrs['namespace']]);
|
|
|
1688 |
return false;
|
|
|
1689 |
}
|
|
|
1690 |
$this->currentImport = $attrs['namespace'];
|
|
|
1691 |
}
|
|
|
1692 |
// Continue on to the 'types' case - lack of break; is
|
|
|
1693 |
// intentional.
|
|
|
1694 |
|
|
|
1695 |
case 'types':
|
|
|
1696 |
// sect 2.2 wsdl:types
|
|
|
1697 |
$this->status = 'types';
|
|
|
1698 |
break;
|
|
|
1699 |
|
|
|
1700 |
case 'schema':
|
|
|
1701 |
// We can hit this at the top level if we've been asked to
|
|
|
1702 |
// import an XSD file.
|
|
|
1703 |
if (!empty($attrs['targetNamespace'])) {
|
|
|
1704 |
$this->schema = $this->wsdl->getNamespaceAttributeName($attrs['targetNamespace']);
|
|
|
1705 |
} else {
|
|
|
1706 |
$this->schema = $this->wsdl->getNamespaceAttributeName($this->wsdl->tns);
|
|
|
1707 |
}
|
|
|
1708 |
$this->wsdl->complexTypes[$this->schema] = array();
|
|
|
1709 |
$this->wsdl->elements[$this->schema] = array();
|
|
|
1710 |
$this->schema_stack[] = $qname->name;
|
|
|
1711 |
$this->status = 'types';
|
|
|
1712 |
break;
|
|
|
1713 |
|
|
|
1714 |
case 'message':
|
|
|
1715 |
// sect 2.3 wsdl:message attributes: name children:wsdl:part
|
|
|
1716 |
$this->status = 'message';
|
|
|
1717 |
if (isset($attrs['name'])) {
|
|
|
1718 |
$this->currentMessage = $attrs['name'];
|
|
|
1719 |
$this->wsdl->messages[$this->currentMessage] = array();
|
|
|
1720 |
}
|
|
|
1721 |
break;
|
|
|
1722 |
|
|
|
1723 |
case 'portType':
|
|
|
1724 |
// sect 2.4 wsdl:portType
|
|
|
1725 |
// attributes: name
|
|
|
1726 |
// children: wsdl:operation
|
|
|
1727 |
$this->status = 'portType';
|
|
|
1728 |
$this->currentPortType = $attrs['name'];
|
|
|
1729 |
$this->wsdl->portTypes[$this->currentPortType] = array();
|
|
|
1730 |
break;
|
|
|
1731 |
|
|
|
1732 |
case 'binding':
|
|
|
1733 |
// sect 2.5 wsdl:binding attributes: name type
|
|
|
1734 |
// children: wsdl:operation soap:binding http:binding
|
|
|
1735 |
if ($qname->ns && $qname->ns != $this->tns) {
|
|
|
1736 |
break;
|
|
|
1737 |
}
|
|
|
1738 |
$this->status = 'binding';
|
|
|
1739 |
$this->currentBinding = $attrs['name'];
|
|
|
1740 |
$qn = new QName($attrs['type']);
|
|
|
1741 |
$this->wsdl->bindings[$this->currentBinding]['type'] = $qn->name;
|
|
|
1742 |
$this->wsdl->bindings[$this->currentBinding]['namespace'] = $qn->ns;
|
|
|
1743 |
break;
|
|
|
1744 |
|
|
|
1745 |
case 'service':
|
|
|
1746 |
// sect 2.7 wsdl:service attributes: name children: ports
|
|
|
1747 |
$this->currentService = $attrs['name'];
|
|
|
1748 |
$this->wsdl->services[$this->currentService]['ports'] = array();
|
|
|
1749 |
$this->status = 'service';
|
|
|
1750 |
break;
|
|
|
1751 |
|
|
|
1752 |
case 'definitions':
|
|
|
1753 |
// sec 2.1 wsdl:definitions
|
|
|
1754 |
// attributes: name targetNamespace xmlns:*
|
|
|
1755 |
// children: wsdl:import wsdl:types wsdl:message wsdl:portType wsdl:binding wsdl:service
|
|
|
1756 |
$this->wsdl->definition = $attrs;
|
|
|
1757 |
foreach ($attrs as $key => $value) {
|
|
|
1758 |
if (strstr($key, 'xmlns:') !== false) {
|
|
|
1759 |
$qn = new QName($key);
|
|
|
1760 |
// XXX need to refactor ns handling.
|
|
|
1761 |
$this->wsdl->namespaces[$qn->name] = $value;
|
|
|
1762 |
$this->wsdl->ns[$value] = $qn->name;
|
|
|
1763 |
if ($key == 'targetNamespace' ||
|
|
|
1764 |
strcasecmp($value,SOAP_SCHEMA) == 0) {
|
|
|
1765 |
$this->soapns[] = $qn->name;
|
|
|
1766 |
} else {
|
|
|
1767 |
if (in_array($value, $this->_XMLSchema)) {
|
|
|
1768 |
$this->wsdl->xsd = $value;
|
|
|
1769 |
}
|
|
|
1770 |
}
|
|
|
1771 |
}
|
|
|
1772 |
}
|
|
|
1773 |
if (isset($ns) && $ns) {
|
|
|
1774 |
$namespace = 'xmlns:' . $ns;
|
|
|
1775 |
if (!$this->wsdl->definition[$namespace]) {
|
|
|
1776 |
return $this->_raiseSoapFault("parse error, no namespace for $namespace", $this->uri);
|
|
|
1777 |
}
|
|
|
1778 |
$this->tns = $ns;
|
|
|
1779 |
}
|
|
|
1780 |
break;
|
|
|
1781 |
}
|
|
|
1782 |
}
|
|
|
1783 |
|
|
|
1784 |
/**
|
|
|
1785 |
* end-element handler.
|
|
|
1786 |
*/
|
|
|
1787 |
function endElement($parser, $name)
|
|
|
1788 |
{
|
|
|
1789 |
$stacksize = count($this->element_stack);
|
|
|
1790 |
if ($stacksize) {
|
|
|
1791 |
if ($this->element_stack[$stacksize - 1] == 'definitions') {
|
|
|
1792 |
$this->status = '';
|
|
|
1793 |
}
|
|
|
1794 |
array_pop($this->element_stack);
|
|
|
1795 |
}
|
|
|
1796 |
|
|
|
1797 |
if (stristr($name, 'schema')) {
|
|
|
1798 |
array_pop($this->schema_stack);
|
|
|
1799 |
$this->schema = '';
|
|
|
1800 |
}
|
|
|
1801 |
|
|
|
1802 |
if ($this->schema) {
|
|
|
1803 |
array_pop($this->schema_stack);
|
|
|
1804 |
if (count($this->schema_stack) <= 1) {
|
|
|
1805 |
/* Correct the type for sequences with multiple
|
|
|
1806 |
* elements. */
|
|
|
1807 |
if (isset($this->currentComplexType) && isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'])
|
|
|
1808 |
&& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] == 'Array'
|
|
|
1809 |
&& array_key_exists('elements', $this->wsdl->complexTypes[$this->schema][$this->currentComplexType])
|
|
|
1810 |
&& count($this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements']) > 1) {
|
|
|
1811 |
$this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['type'] = 'Struct';
|
|
|
1812 |
}
|
|
|
1813 |
}
|
|
|
1814 |
if (stristr($name, 'complexType')) {
|
|
|
1815 |
$this->currentComplexType = '';
|
|
|
1816 |
if (count($this->schema_element_stack)) {
|
|
|
1817 |
$this->currentElement = array_pop($this->schema_element_stack);
|
|
|
1818 |
} else {
|
|
|
1819 |
$this->currentElement = '';
|
|
|
1820 |
}
|
|
|
1821 |
} elseif (stristr($name, 'element')) {
|
|
|
1822 |
if (count($this->schema_element_stack)) {
|
|
|
1823 |
$this->currentElement = array_pop($this->schema_element_stack);
|
|
|
1824 |
} else {
|
|
|
1825 |
$this->currentElement = '';
|
|
|
1826 |
}
|
|
|
1827 |
}
|
|
|
1828 |
}
|
|
|
1829 |
}
|
|
|
1830 |
|
|
|
1831 |
/**
|
|
|
1832 |
* Element content handler.
|
|
|
1833 |
*/
|
|
|
1834 |
function characterData($parser, $data)
|
|
|
1835 |
{
|
|
|
1836 |
// Store the documentation in the WSDL file.
|
|
|
1837 |
if ($this->currentTag == 'documentation') {
|
|
|
1838 |
$data = trim(preg_replace('/\s+/', ' ', $data));
|
|
|
1839 |
if (!strlen($data)) {
|
|
|
1840 |
return;
|
|
|
1841 |
}
|
|
|
1842 |
|
|
|
1843 |
switch ($this->status) {
|
|
|
1844 |
case 'service':
|
|
|
1845 |
$ptr =& $this->wsdl->services[$this->currentService];
|
|
|
1846 |
break;
|
|
|
1847 |
|
|
|
1848 |
case 'portType':
|
|
|
1849 |
$ptr =& $this->wsdl->portTypes[$this->currentPortType][$this->currentOperation];
|
|
|
1850 |
break;
|
|
|
1851 |
|
|
|
1852 |
case 'binding':
|
|
|
1853 |
$ptr =& $this->wsdl->bindings[$this->currentBinding];
|
|
|
1854 |
break;
|
|
|
1855 |
|
|
|
1856 |
case 'message':
|
|
|
1857 |
$ptr =& $this->wsdl->messages[$this->currentMessage];
|
|
|
1858 |
break;
|
|
|
1859 |
|
|
|
1860 |
case 'operation':
|
|
|
1861 |
break;
|
|
|
1862 |
|
|
|
1863 |
case 'types':
|
|
|
1864 |
if (isset($this->currentComplexType) &&
|
|
|
1865 |
isset($this->wsdl->complexTypes[$this->schema][$this->currentComplexType])) {
|
|
|
1866 |
if ($this->currentElement) {
|
|
|
1867 |
$ptr =& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType]['elements'][$this->currentElement];
|
|
|
1868 |
} else {
|
|
|
1869 |
$ptr =& $this->wsdl->complexTypes[$this->schema][$this->currentComplexType];
|
|
|
1870 |
}
|
|
|
1871 |
}
|
|
|
1872 |
break;
|
|
|
1873 |
}
|
|
|
1874 |
|
|
|
1875 |
if (isset($ptr)) {
|
|
|
1876 |
if (!isset($ptr['documentation'])) {
|
|
|
1877 |
$ptr['documentation'] = '';
|
|
|
1878 |
} else {
|
|
|
1879 |
$ptr['documentation'] .= ' ';
|
|
|
1880 |
}
|
|
|
1881 |
$ptr['documentation'] .= $data;
|
|
|
1882 |
}
|
|
|
1883 |
}
|
|
|
1884 |
}
|
|
|
1885 |
|
|
|
1886 |
/**
|
|
|
1887 |
* $parsed is an array returned by parse_url().
|
|
|
1888 |
*
|
|
|
1889 |
* @access private
|
|
|
1890 |
*/
|
|
|
1891 |
function mergeUrl($parsed, $path)
|
|
|
1892 |
{
|
|
|
1893 |
if (!is_array($parsed)) {
|
|
|
1894 |
return false;
|
|
|
1895 |
}
|
|
|
1896 |
|
|
|
1897 |
$uri = '';
|
|
|
1898 |
if (!empty($parsed['scheme'])) {
|
|
|
1899 |
$sep = (strtolower($parsed['scheme']) == 'mailto' ? ':' : '://');
|
|
|
1900 |
$uri = $parsed['scheme'] . $sep;
|
|
|
1901 |
}
|
|
|
1902 |
|
|
|
1903 |
if (isset($parsed['pass'])) {
|
|
|
1904 |
$uri .= "$parsed[user]:$parsed[pass]@";
|
|
|
1905 |
} elseif (isset($parsed['user'])) {
|
|
|
1906 |
$uri .= "$parsed[user]@";
|
|
|
1907 |
}
|
|
|
1908 |
|
|
|
1909 |
if (isset($parsed['host'])) {
|
|
|
1910 |
$uri .= $parsed['host'];
|
|
|
1911 |
}
|
|
|
1912 |
if (isset($parsed['port'])) {
|
|
|
1913 |
$uri .= ":$parsed[port]";
|
|
|
1914 |
}
|
|
|
1915 |
if ($path[0] != '/' && isset($parsed['path'])) {
|
|
|
1916 |
if ($parsed['path'][strlen($parsed['path']) - 1] != '/') {
|
|
|
1917 |
$path = dirname($parsed['path']) . '/' . $path;
|
|
|
1918 |
} else {
|
|
|
1919 |
$path = $parsed['path'] . $path;
|
|
|
1920 |
}
|
|
|
1921 |
$path = $this->_normalize($path);
|
|
|
1922 |
}
|
|
|
1923 |
$sep = $path[0] == '/' ? '' : '/';
|
|
|
1924 |
$uri .= $sep . $path;
|
|
|
1925 |
|
|
|
1926 |
return $uri;
|
|
|
1927 |
}
|
|
|
1928 |
|
|
|
1929 |
function _normalize($path_str)
|
|
|
1930 |
{
|
|
|
1931 |
$pwd = '';
|
|
|
1932 |
$strArr = preg_split('/(\/)/', $path_str, -1, PREG_SPLIT_NO_EMPTY);
|
|
|
1933 |
$pwdArr = '';
|
|
|
1934 |
$j = 0;
|
|
|
1935 |
for ($i = 0; $i < count($strArr); $i++) {
|
|
|
1936 |
if ($strArr[$i] != ' ..') {
|
|
|
1937 |
if ($strArr[$i] != ' .') {
|
|
|
1938 |
$pwdArr[$j] = $strArr[$i];
|
|
|
1939 |
$j++;
|
|
|
1940 |
}
|
|
|
1941 |
} else {
|
|
|
1942 |
array_pop($pwdArr);
|
|
|
1943 |
$j--;
|
|
|
1944 |
}
|
|
|
1945 |
}
|
|
|
1946 |
$pStr = implode('/', $pwdArr);
|
|
|
1947 |
$pwd = (strlen($pStr) > 0) ? ('/' . $pStr) : '/';
|
|
|
1948 |
return $pwd;
|
|
|
1949 |
}
|
|
|
1950 |
|
|
|
1951 |
}
|
|
|
1952 |
|
|
|
1953 |
/**
|
|
|
1954 |
* Parses the types and methods used in web service objects into the internal
|
|
|
1955 |
* data structures used by SOAP_WSDL.
|
|
|
1956 |
*
|
|
|
1957 |
* Assumes the SOAP_WSDL class is unpopulated to start with.
|
|
|
1958 |
*
|
|
|
1959 |
* @author Chris Coe <info@intelligentstreaming.com>
|
|
|
1960 |
*/
|
|
|
1961 |
class SOAP_WSDL_ObjectParser extends SOAP_Base
|
|
|
1962 |
{
|
|
|
1963 |
/**
|
|
|
1964 |
* Target namespace for the WSDL document will have the following
|
|
|
1965 |
* prefix.
|
|
|
1966 |
*/
|
|
|
1967 |
var $tnsPrefix = 'tns';
|
|
|
1968 |
|
|
|
1969 |
/**
|
|
|
1970 |
* Reference to the SOAP_WSDL object to populate.
|
|
|
1971 |
*/
|
|
|
1972 |
var $wsdl = null;
|
|
|
1973 |
|
|
|
1974 |
/**
|
|
|
1975 |
* Constructor.
|
|
|
1976 |
*
|
|
|
1977 |
* @param object|array $objects Reference to the object or array of
|
|
|
1978 |
* objects to parse.
|
|
|
1979 |
* @param SOAP_WSDL $wsdl Reference to the SOAP_WSDL object to
|
|
|
1980 |
* populate.
|
|
|
1981 |
* @param string $targetNamespace The target namespace of schema types
|
|
|
1982 |
* etc.
|
|
|
1983 |
* @param string $service_name Name of the WSDL <service>.
|
|
|
1984 |
* @param string $service_desc Optional description of the WSDL
|
|
|
1985 |
* <service>.
|
|
|
1986 |
*/
|
|
|
1987 |
function SOAP_WSDL_ObjectParser($objects, &$wsdl, $targetNamespace,
|
|
|
1988 |
$service_name, $service_desc = '')
|
|
|
1989 |
{
|
|
|
1990 |
parent::SOAP_Base('WSDLOBJECTPARSER');
|
|
|
1991 |
|
|
|
1992 |
$this->wsdl = &$wsdl;
|
|
|
1993 |
|
|
|
1994 |
// Set up the SOAP_WSDL object
|
|
|
1995 |
$this->_initialise($service_name);
|
|
|
1996 |
|
|
|
1997 |
// Parse each web service object
|
|
|
1998 |
$wsdl_ref = is_array($objects) ? $objects : array($objects);
|
|
|
1999 |
|
|
|
2000 |
foreach ($wsdl_ref as $ref_item) {
|
|
|
2001 |
if (!is_object($ref_item)) {
|
|
|
2002 |
$this->_raiseSoapFault('Invalid web service object passed to object parser');
|
|
|
2003 |
continue;
|
|
|
2004 |
}
|
|
|
2005 |
|
|
|
2006 |
if (!$this->_parse($ref_item, $targetNamespace, $service_name)) {
|
|
|
2007 |
break;
|
|
|
2008 |
}
|
|
|
2009 |
}
|
|
|
2010 |
|
|
|
2011 |
// Build bindings from abstract data.
|
|
|
2012 |
if ($this->fault == null) {
|
|
|
2013 |
$this->_generateBindingsAndServices($targetNamespace, $service_name, $service_desc);
|
|
|
2014 |
}
|
|
|
2015 |
}
|
|
|
2016 |
|
|
|
2017 |
/**
|
|
|
2018 |
* Initialise the SOAP_WSDL tree (destructive).
|
|
|
2019 |
*
|
|
|
2020 |
* If the object has already been initialised, the only effect
|
|
|
2021 |
* will be to change the tns namespace to the new service name.
|
|
|
2022 |
*
|
|
|
2023 |
* @param $service_name Name of the WSDL <service>
|
|
|
2024 |
* @access private
|
|
|
2025 |
*/
|
|
|
2026 |
function _initialise($service_name)
|
|
|
2027 |
{
|
|
|
2028 |
// Set up the basic namespaces that all WSDL definitions use.
|
|
|
2029 |
$this->wsdl->namespaces['wsdl'] = SCHEMA_WSDL; // WSDL language
|
|
|
2030 |
$this->wsdl->namespaces['soap'] = SCHEMA_SOAP; // WSDL SOAP bindings
|
|
|
2031 |
$this->wsdl->namespaces[$this->tnsPrefix] = 'urn:' . $service_name; // Target namespace
|
|
|
2032 |
$this->wsdl->namespaces['xsd'] = array_search('xsd', $this->_namespaces); // XML Schema
|
|
|
2033 |
$this->wsdl->namespaces[SOAP_BASE::SOAPENCPrefix()] = array_search(SOAP_BASE::SOAPENCPrefix(), $this->_namespaces); // SOAP types
|
|
|
2034 |
|
|
|
2035 |
// XXX Refactor $namespace/$ns for Shane :-)
|
|
|
2036 |
unset($this->wsdl->ns['urn:' . $service_name]);
|
|
|
2037 |
$this->wsdl->ns += array_flip($this->wsdl->namespaces);
|
|
|
2038 |
|
|
|
2039 |
// Imports are not implemented in WSDL generation from classes.
|
|
|
2040 |
// *** <wsdl:import> ***
|
|
|
2041 |
}
|
|
|
2042 |
|
|
|
2043 |
/**
|
|
|
2044 |
* Parser - takes a single object to add to tree (non-destructive).
|
|
|
2045 |
*
|
|
|
2046 |
* @access private
|
|
|
2047 |
*
|
|
|
2048 |
* @param object $object Reference to the object to parse.
|
|
|
2049 |
* @param string $schemaNamespace
|
|
|
2050 |
* @param string $service_name Name of the WSDL <service>.
|
|
|
2051 |
*/
|
|
|
2052 |
function _parse($object, $schemaNamespace, $service_name)
|
|
|
2053 |
{
|
|
|
2054 |
// Create namespace prefix for the schema
|
|
|
2055 |
list($schPrefix,) = $this->_getTypeNs('{' . $schemaNamespace . '}');
|
|
|
2056 |
|
|
|
2057 |
// Parse all the types defined by the object in whatever
|
|
|
2058 |
// schema language we are using (currently __typedef arrays)
|
|
|
2059 |
// *** <wsdl:types> ***
|
|
|
2060 |
foreach ($object->__typedef as $typeName => $typeValue) {
|
|
|
2061 |
// Get/create namespace definition
|
|
|
2062 |
list($nsPrefix, $typeName) = $this->_getTypeNs($typeName);
|
|
|
2063 |
|
|
|
2064 |
// Create type definition
|
|
|
2065 |
$this->wsdl->complexTypes[$schPrefix][$typeName] = array('name' => $typeName);
|
|
|
2066 |
$thisType =& $this->wsdl->complexTypes[$schPrefix][$typeName];
|
|
|
2067 |
|
|
|
2068 |
// According to Dmitri's documentation, __typedef comes in two
|
|
|
2069 |
// flavors:
|
|
|
2070 |
// Array = array(array("item" => "value"))
|
|
|
2071 |
// Struct = array("item1" => "value1", "item2" => "value2", ...)
|
|
|
2072 |
if (is_array($typeValue)) {
|
|
|
2073 |
if (is_array(current($typeValue)) && count($typeValue) == 1
|
|
|
2074 |
&& count(current($typeValue)) == 1) {
|
|
|
2075 |
// It's an array
|
|
|
2076 |
$thisType['type'] = 'Array';
|
|
|
2077 |
$nsType = current(current($typeValue));
|
|
|
2078 |
list($nsPrefix, $typeName) = $this->_getTypeNs($nsType);
|
|
|
2079 |
$thisType['namespace'] = $nsPrefix;
|
|
|
2080 |
$thisType['arrayType'] = $typeName . '[]';
|
|
|
2081 |
} elseif (!is_array(current($typeValue))) {
|
|
|
2082 |
// It's a struct
|
|
|
2083 |
$thisType['type'] = 'Struct';
|
|
|
2084 |
$thisType['order'] = 'all';
|
|
|
2085 |
$thisType['namespace'] = $nsPrefix;
|
|
|
2086 |
$thisType['elements'] = array();
|
|
|
2087 |
|
|
|
2088 |
foreach ($typeValue as $elementName => $elementType) {
|
|
|
2089 |
list($nsPrefix, $typeName) = $this->_getTypeNs($elementType);
|
|
|
2090 |
$thisType['elements'][$elementName]['name'] = $elementName;
|
|
|
2091 |
$thisType['elements'][$elementName]['type'] = $typeName;
|
|
|
2092 |
$thisType['elements'][$elementName]['namespace'] = $nsPrefix;
|
|
|
2093 |
}
|
|
|
2094 |
} else {
|
|
|
2095 |
// It's erroneous
|
|
|
2096 |
return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object));
|
|
|
2097 |
}
|
|
|
2098 |
} else {
|
|
|
2099 |
// It's erroneous
|
|
|
2100 |
return $this->_raiseSoapFault("The type definition for $nsPrefix:$typeName is invalid.", 'urn:' . get_class($object));
|
|
|
2101 |
}
|
|
|
2102 |
}
|
|
|
2103 |
|
|
|
2104 |
// Create an empty element array with the target namespace
|
|
|
2105 |
// prefix, to match the results of WSDL parsing.
|
|
|
2106 |
$this->wsdl->elements[$schPrefix] = array();
|
|
|
2107 |
|
|
|
2108 |
// Populate tree with message information
|
|
|
2109 |
// *** <wsdl:message> ***
|
|
|
2110 |
foreach ($object->__dispatch_map as $operationName => $messages) {
|
|
|
2111 |
// We need at least 'in' and 'out' parameters.
|
|
|
2112 |
if (!isset($messages['in']) || !isset($messages['out'])) {
|
|
|
2113 |
return $this->_raiseSoapFault('The dispatch map for the method "' . $operationName . '" is missing an "in" or "out" definition.', 'urn:' . get_class($object));
|
|
|
2114 |
}
|
|
|
2115 |
foreach ($messages as $messageType => $messageParts) {
|
|
|
2116 |
unset($thisMessage);
|
|
|
2117 |
|
|
|
2118 |
switch ($messageType) {
|
|
|
2119 |
case 'in':
|
|
|
2120 |
$this->wsdl->messages[$operationName . 'Request'] = array();
|
|
|
2121 |
$thisMessage =& $this->wsdl->messages[$operationName . 'Request'];
|
|
|
2122 |
break;
|
|
|
2123 |
|
|
|
2124 |
case 'out':
|
|
|
2125 |
$this->wsdl->messages[$operationName . 'Response'] = array();
|
|
|
2126 |
$thisMessage =& $this->wsdl->messages[$operationName . 'Response'];
|
|
|
2127 |
break;
|
|
|
2128 |
|
|
|
2129 |
case 'alias':
|
|
|
2130 |
// Do nothing
|
|
|
2131 |
break;
|
|
|
2132 |
|
|
|
2133 |
default:
|
|
|
2134 |
// Error condition
|
|
|
2135 |
break;
|
|
|
2136 |
}
|
|
|
2137 |
|
|
|
2138 |
if (isset($thisMessage)) {
|
|
|
2139 |
foreach ($messageParts as $partName => $partType) {
|
|
|
2140 |
list ($nsPrefix, $typeName) = $this->_getTypeNs($partType);
|
|
|
2141 |
|
|
|
2142 |
$thisMessage[$partName] = array(
|
|
|
2143 |
'name' => $partName,
|
|
|
2144 |
'type' => $typeName,
|
|
|
2145 |
'namespace' => $nsPrefix
|
|
|
2146 |
);
|
|
|
2147 |
}
|
|
|
2148 |
}
|
|
|
2149 |
}
|
|
|
2150 |
}
|
|
|
2151 |
|
|
|
2152 |
// Populate tree with portType information
|
|
|
2153 |
// XXX Current implementation only supports one portType that
|
|
|
2154 |
// encompasses all of the operations available.
|
|
|
2155 |
// *** <wsdl:portType> ***
|
|
|
2156 |
if (!isset($this->wsdl->portTypes[$service_name . 'Port'])) {
|
|
|
2157 |
$this->wsdl->portTypes[$service_name . 'Port'] = array();
|
|
|
2158 |
}
|
|
|
2159 |
$thisPortType =& $this->wsdl->portTypes[$service_name . 'Port'];
|
|
|
2160 |
|
|
|
2161 |
foreach ($object->__dispatch_map as $operationName => $messages) {
|
|
|
2162 |
$thisPortType[$operationName] = array('name' => $operationName);
|
|
|
2163 |
|
|
|
2164 |
foreach ($messages as $messageType => $messageParts) {
|
|
|
2165 |
switch ($messageType) {
|
|
|
2166 |
case 'in':
|
|
|
2167 |
$thisPortType[$operationName]['input'] = array(
|
|
|
2168 |
'message' => $operationName . 'Request',
|
|
|
2169 |
'namespace' => $this->tnsPrefix);
|
|
|
2170 |
break;
|
|
|
2171 |
|
|
|
2172 |
case 'out':
|
|
|
2173 |
$thisPortType[$operationName]['output'] = array(
|
|
|
2174 |
'message' => $operationName . 'Response',
|
|
|
2175 |
'namespace' => $this->tnsPrefix);
|
|
|
2176 |
break;
|
|
|
2177 |
}
|
|
|
2178 |
}
|
|
|
2179 |
}
|
|
|
2180 |
|
|
|
2181 |
return true;
|
|
|
2182 |
}
|
|
|
2183 |
|
|
|
2184 |
/**
|
|
|
2185 |
* Takes all the abstract WSDL data and builds concrete bindings and
|
|
|
2186 |
* services (destructive).
|
|
|
2187 |
*
|
|
|
2188 |
* @access private
|
|
|
2189 |
* @todo Current implementation discards $service_desc.
|
|
|
2190 |
*
|
|
|
2191 |
* @param string $schemaNamespace Namespace for types etc.
|
|
|
2192 |
* @param string $service_name Name of the WSDL <service>.
|
|
|
2193 |
* @param string $service_desc Optional description of the WSDL
|
|
|
2194 |
* <service>.
|
|
|
2195 |
*/
|
|
|
2196 |
function _generateBindingsAndServices($schemaNamespace, $service_name,
|
|
|
2197 |
$service_desc = '')
|
|
|
2198 |
{
|
|
|
2199 |
// Populate tree with bindings information
|
|
|
2200 |
// XXX Current implementation only supports one binding that
|
|
|
2201 |
// matches the single portType and all of its operations.
|
|
|
2202 |
// XXX Is this the correct use of $schemaNamespace here?
|
|
|
2203 |
// *** <wsdl:binding> ***
|
|
|
2204 |
$this->wsdl->bindings[$service_name . 'Binding'] = array(
|
|
|
2205 |
'type' => $service_name . 'Port',
|
|
|
2206 |
'namespace' => $this->tnsPrefix,
|
|
|
2207 |
'style' => 'rpc',
|
|
|
2208 |
'transport' => SCHEMA_SOAP_HTTP,
|
|
|
2209 |
'operations' => array());
|
|
|
2210 |
$thisBinding =& $this->wsdl->bindings[$service_name . 'Binding'];
|
|
|
2211 |
|
|
|
2212 |
foreach ($this->wsdl->portTypes[$service_name . 'Port'] as $operationName => $operationData) {
|
|
|
2213 |
$thisBinding['operations'][$operationName] = array(
|
|
|
2214 |
'soapAction' => $schemaNamespace . '#' . $operationName,
|
|
|
2215 |
'style' => $thisBinding['style']);
|
|
|
2216 |
|
|
|
2217 |
foreach (array('input', 'output') as $messageType)
|
|
|
2218 |
if (isset($operationData[$messageType])) {
|
|
|
2219 |
$thisBinding['operations'][$operationName][$messageType] = array(
|
|
|
2220 |
'use' => 'encoded',
|
|
|
2221 |
'namespace' => $schemaNamespace,
|
|
|
2222 |
'encodingStyle' => SOAP_SCHEMA_ENCODING);
|
|
|
2223 |
}
|
|
|
2224 |
}
|
|
|
2225 |
|
|
|
2226 |
// Populate tree with service information
|
|
|
2227 |
// XXX Current implementation supports one service which groups
|
|
|
2228 |
// all of the ports together, one port per binding
|
|
|
2229 |
// *** <wsdl:service> ***
|
|
|
2230 |
|
|
|
2231 |
$this->wsdl->services[$service_name . 'Service'] = array('ports' => array());
|
|
|
2232 |
$thisService =& $this->wsdl->services[$service_name . 'Service']['ports'];
|
|
|
2233 |
$https = (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on')) ||
|
|
|
2234 |
getenv('SSL_PROTOCOL_VERSION');
|
|
|
2235 |
|
|
|
2236 |
foreach ($this->wsdl->bindings as $bindingName => $bindingData) {
|
|
|
2237 |
$thisService[$bindingData['type']] = array(
|
|
|
2238 |
'name' => $bindingData['type'],
|
|
|
2239 |
'binding' => $bindingName,
|
|
|
2240 |
'namespace' => $this->tnsPrefix,
|
|
|
2241 |
'address' => array('location' =>
|
|
|
2242 |
($https ? 'https://' : 'http://') .
|
|
|
2243 |
$_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] .
|
|
|
2244 |
(isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')),
|
|
|
2245 |
'type' => 'soap');
|
|
|
2246 |
}
|
|
|
2247 |
|
|
|
2248 |
// Set service
|
|
|
2249 |
$this->wsdl->set_service($service_name . 'Service');
|
|
|
2250 |
$this->wsdl->uri = $this->wsdl->namespaces[$this->tnsPrefix];
|
|
|
2251 |
|
|
|
2252 |
// Create WSDL definition
|
|
|
2253 |
// *** <wsdl:definitions> ***
|
|
|
2254 |
|
|
|
2255 |
$this->wsdl->definition = array(
|
|
|
2256 |
'name' => $service_name,
|
|
|
2257 |
'targetNamespace' => $this->wsdl->namespaces[$this->tnsPrefix],
|
|
|
2258 |
'xmlns' => SCHEMA_WSDL);
|
|
|
2259 |
|
|
|
2260 |
foreach ($this->wsdl->namespaces as $nsPrefix => $namespace) {
|
|
|
2261 |
$this->wsdl->definition['xmlns:' . $nsPrefix] = $namespace;
|
|
|
2262 |
}
|
|
|
2263 |
}
|
|
|
2264 |
|
|
|
2265 |
/**
|
|
|
2266 |
* This function is adapted from Dmitri V's implementation of
|
|
|
2267 |
* DISCO/WSDL generation. It separates namespace from type name in
|
|
|
2268 |
* a __typedef key and creates a new namespace entry in the WSDL
|
|
|
2269 |
* structure if the namespace has not been used before. The
|
|
|
2270 |
* namespace prefix and type name are returned. If no namespace is
|
|
|
2271 |
* specified, xsd is assumed.
|
|
|
2272 |
*
|
|
|
2273 |
* We will not need this function anymore once __typedef is
|
|
|
2274 |
* eliminated.
|
|
|
2275 |
*/
|
|
|
2276 |
function _getTypeNs($type)
|
|
|
2277 |
{
|
|
|
2278 |
preg_match_all('/\{(.*)\}/sm', $type, $m);
|
|
|
2279 |
if (!empty($m[1][0])) {
|
|
|
2280 |
if (!isset($this->wsdl->ns[$m[1][0]])) {
|
|
|
2281 |
$ns_pref = 'ns' . count($this->wsdl->namespaces);
|
|
|
2282 |
$this->wsdl->ns[$m[1][0]] = $ns_pref;
|
|
|
2283 |
$this->wsdl->namespaces[$ns_pref] = $m[1][0];
|
|
|
2284 |
}
|
|
|
2285 |
$typens = $this->wsdl->ns[$m[1][0]];
|
|
|
2286 |
$type = str_replace($m[0][0], '', $type);
|
|
|
2287 |
} else {
|
|
|
2288 |
$typens = 'xsd';
|
|
|
2289 |
}
|
|
|
2290 |
|
|
|
2291 |
return array($typens, $type);
|
|
|
2292 |
}
|
|
|
2293 |
|
|
|
2294 |
}
|