1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
|
5
|
|
|
NuSOAP - Web Services Toolkit for PHP |
6
|
|
|
|
7
|
|
|
Copyright (c) 2002 NuSphere Corporation |
8
|
|
|
|
9
|
|
|
This library is free software; you can redistribute it and/or |
10
|
|
|
modify it under the terms of the GNU Lesser General Public |
11
|
|
|
License as published by the Free Software Foundation; either |
12
|
|
|
version 2.1 of the License, or (at your option) any later version. |
13
|
|
|
|
14
|
|
|
This library is distributed in the hope that it will be useful, |
15
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17
|
|
|
Lesser General Public License for more details. |
18
|
|
|
|
19
|
|
|
You should have received a copy of the GNU Lesser General Public |
20
|
|
|
License along with this library; if not, write to the Free Software |
21
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22
|
|
|
|
23
|
|
|
If you have any questions or comments, please email: |
24
|
|
|
|
25
|
|
|
Dietrich Ayala |
26
|
|
|
[email protected] |
27
|
|
|
http://dietrich.ganx4.com/nusoap |
28
|
|
|
|
29
|
|
|
NuSphere Corporation |
30
|
|
|
http://www.nusphere.com |
31
|
|
|
|
32
|
|
|
*/ |
33
|
|
|
|
34
|
|
|
/* load classes |
35
|
|
|
|
36
|
|
|
// necessary classes |
37
|
|
|
require_once('class.soapclient.php'); |
38
|
|
|
require_once('class.soap_val.php'); |
39
|
|
|
require_once('class.soap_parser.php'); |
40
|
|
|
require_once('class.soap_fault.php'); |
41
|
|
|
|
42
|
|
|
// transport classes |
43
|
|
|
require_once('class.soap_transport_http.php'); |
44
|
|
|
|
45
|
|
|
// optional add-on classes |
46
|
|
|
require_once('class.xmlschema.php'); |
47
|
|
|
require_once('class.wsdl.php'); |
48
|
|
|
|
49
|
|
|
// server class |
50
|
|
|
require_once('class.soap_server.php');*/ |
51
|
|
|
|
52
|
|
|
|
53
|
|
|
// make errors handle properly in windows (thx, [email protected]) |
54
|
|
|
error_reporting(2039); |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* set schema version |
58
|
|
|
* |
59
|
|
|
* @var XMLSchemaVersion |
60
|
|
|
* @access public |
61
|
|
|
*/ |
62
|
|
|
$XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* load namespace uris into an array of uri => prefix |
66
|
|
|
* |
67
|
|
|
* @var namespaces |
68
|
|
|
* @access public |
69
|
|
|
*/ |
70
|
|
|
$namespaces = array( |
71
|
|
|
'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', |
72
|
|
|
'xsd' => $XMLSchemaVersion, |
73
|
|
|
'xsi' => $XMLSchemaVersion.'-instance', |
74
|
|
|
'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', |
75
|
|
|
'si' => 'http://soapinterop.org/xsd'); |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* |
79
|
|
|
* nusoap_base |
80
|
|
|
* |
81
|
|
|
* @author Dietrich Ayala <[email protected]> |
82
|
|
|
* @version v 0.6 |
83
|
|
|
* @access public |
84
|
|
|
*/ |
85
|
|
|
|
86
|
|
|
class nusoap_base { |
87
|
|
|
|
88
|
|
|
var $title = 'NuSOAP'; |
89
|
|
|
var $version = '0.6'; |
90
|
|
|
var $error_str = false; |
91
|
|
|
// toggles automatic encoding of special characters |
92
|
|
|
var $charencoding = true; |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* set default encoding |
96
|
|
|
* |
97
|
|
|
* @var soap_defencoding |
98
|
|
|
* @access public |
99
|
|
|
*/ |
100
|
|
|
var $soap_defencoding = 'UTF-8'; |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* load namespace uris into an array of uri => prefix |
104
|
|
|
* |
105
|
|
|
* @var namespaces |
106
|
|
|
* @access public |
107
|
|
|
*/ |
108
|
|
|
var $namespaces = array( |
109
|
|
|
'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', |
110
|
|
|
'xsd' => 'http://www.w3.org/2001/XMLSchema', |
111
|
|
|
'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', |
112
|
|
|
'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/', |
113
|
|
|
'si' => 'http://soapinterop.org/xsd'); |
114
|
|
|
/** |
115
|
|
|
* load types into typemap array |
116
|
|
|
* is this legacy yet? |
117
|
|
|
* @var typemap |
118
|
|
|
* @access public |
119
|
|
|
*/ |
120
|
|
|
var $typemap = array( |
121
|
|
|
'http://www.w3.org/2001/XMLSchema' => array( |
122
|
|
|
'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', |
123
|
|
|
'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', |
124
|
|
|
'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', |
125
|
|
|
// derived datatypes |
126
|
|
|
'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', |
127
|
|
|
'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', |
128
|
|
|
'negativeInteger'=>'integer','long'=>'','int'=>'integer','short'=>'','byte'=>'','nonNegativeInteger'=>'integer', |
129
|
|
|
'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), |
130
|
|
|
'http://www.w3.org/1999/XMLSchema' => array( |
131
|
|
|
'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', |
132
|
|
|
'float'=>'double','dateTime'=>'string', |
133
|
|
|
'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), |
134
|
|
|
'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), |
135
|
|
|
'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array') |
136
|
|
|
); |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* entities to convert |
140
|
|
|
* |
141
|
|
|
* @var xmlEntities |
142
|
|
|
* @access public |
143
|
|
|
*/ |
144
|
|
|
var $xmlEntities = array('quot' => '"','amp' => '&', |
145
|
|
|
'lt' => '<','gt' => '>','apos' => "'"); |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* constructor: loads schema version |
149
|
|
|
*/ |
150
|
|
|
function __construct(){ |
151
|
|
|
global $XMLSchemaVersion; |
152
|
|
|
$this->XMLSchemaVersion = $XMLSchemaVersion; |
|
|
|
|
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* adds debug data to the class level debug string |
157
|
|
|
* |
158
|
|
|
* @param string $string debug data |
159
|
|
|
* @access private |
160
|
|
|
*/ |
161
|
|
|
function debug($string){ |
162
|
|
|
$this->debug_str .= get_class($this).": $string\n"; |
|
|
|
|
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* returns error string if present |
167
|
|
|
* |
168
|
|
|
* @return boolean $string error string |
169
|
|
|
* @access public |
170
|
|
|
*/ |
171
|
|
|
function getError(){ |
172
|
|
|
if($this->error_str != ""){ |
173
|
|
|
return $this->error_str; |
174
|
|
|
} |
175
|
|
|
return false; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* sets error string |
180
|
|
|
* |
181
|
|
|
* @return boolean $string error string |
182
|
|
|
* @access private |
183
|
|
|
*/ |
184
|
|
|
function setError($str){ |
185
|
|
|
$this->error_str = $str; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* serializes PHP values in accordance w/ section 5 |
190
|
|
|
* @return string |
191
|
|
|
* @access public |
192
|
|
|
*/ |
193
|
|
|
function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false){ |
194
|
|
|
//print "in serialize_val: $val, $name, $type, $name_ns, $type_ns<br>"; |
195
|
|
|
// if no name, use item |
196
|
|
|
$name = (!$name|| is_numeric($name)) ? 'noname' : $name; |
197
|
|
|
// if name has ns, add ns prefix to name |
198
|
|
|
if($name_ns){ |
199
|
|
|
$prefix = 'nu'.rand(1000,9999); |
200
|
|
|
$name = $prefix.':'.$name; |
201
|
|
|
$xmlns .= " xmlns:$prefix=\"$name_ns\""; |
|
|
|
|
202
|
|
|
} |
203
|
|
|
// if type is prefixed, create type prefix |
204
|
|
|
if($type_ns == $this->namespaces['xsd'] || $type_ns == ''){ |
205
|
|
|
// need to fix this. shouldn't default to if no ns specified |
206
|
|
|
// w/o checking against typemap |
207
|
|
|
$type_prefix = 'xsd'; |
208
|
|
|
} elseif($type_ns){ |
209
|
|
|
$type_prefix = 'ns'.rand(1000,9999); |
210
|
|
|
$xmlns .= " xmlns:$type_prefix=\"$type_ns\""; |
211
|
|
|
} |
212
|
|
|
// serialize attributes if present |
213
|
|
|
if($attributes){ |
214
|
|
|
foreach($attributes as $k => $v){ |
|
|
|
|
215
|
|
|
$atts .= " $k=\"$v\""; |
|
|
|
|
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
// detect type and serialize |
219
|
|
|
switch(true) { |
220
|
|
|
case is_null($val): |
221
|
|
|
$xml .= "<$name$xmlns xsi:type=\"xsd:nil\"/>\n"; |
|
|
|
|
222
|
|
|
break; |
223
|
|
|
case (is_bool($val) || $type == 'boolean'): |
224
|
|
|
if(!$val){ |
225
|
|
|
$val = 0; |
226
|
|
|
} |
227
|
|
|
$xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":boolean\"$atts>$val</$name>\n"; |
|
|
|
|
228
|
|
|
break; |
229
|
|
|
case (is_int($val) || is_long($val) || $type == 'int'): |
230
|
|
|
$xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":int\"$atts>$val</$name>\n"; |
|
|
|
|
231
|
|
|
break; |
232
|
|
|
case (is_float($val)|| is_double($val) || $type == 'float'): |
233
|
|
|
$xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":float\"$atts>$val</$name>\n"; |
|
|
|
|
234
|
|
|
break; |
235
|
|
|
case (is_string($val) || $type == 'string'): |
236
|
|
|
if($this->charencoding){ |
237
|
|
|
$val = htmlspecialchars($val); |
238
|
|
|
} |
239
|
|
|
$xml .= "<$name$xmlns xsi:type=\"".$type_prefix.":string\"$atts>$val</$name>\n"; |
|
|
|
|
240
|
|
|
break; |
241
|
|
|
case is_object($val): |
242
|
|
|
break; |
243
|
|
|
break; |
244
|
|
|
case (is_array($val) || $type): |
245
|
|
|
// detect if struct or array |
246
|
|
|
if(preg_match("/^[0-9]+$/",key($val)) || preg_match('/^ArrayOf/',$type)){ |
247
|
|
|
foreach($val as $v){ |
248
|
|
|
$tt = gettype($v); |
249
|
|
|
$array_types[$tt] = 1; |
|
|
|
|
250
|
|
|
$xml .= $this->serialize_val($v,'item'); |
|
|
|
|
251
|
|
|
if(is_array($v) && is_numeric(key($v))){ |
252
|
|
|
$i += sizeof($v); |
|
|
|
|
253
|
|
|
} else { |
254
|
|
|
$i += 1; |
255
|
|
|
unset($array_types['array']); |
256
|
|
|
} |
257
|
|
|
} |
258
|
|
|
if(count($array_types) > 1){ |
|
|
|
|
259
|
|
|
$array_typename = "xsd:ur-type"; |
260
|
|
|
} else { |
261
|
|
|
$array_typename = "xsd:".$tt; |
|
|
|
|
262
|
|
|
} |
263
|
|
|
if($array_types['array']){ |
264
|
|
|
$array_type = $i.",".$i; |
265
|
|
|
} else { |
266
|
|
|
$array_type = $i; |
267
|
|
|
} |
268
|
|
|
$xml = "<$name xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"$atts>\n".$xml."</$name>\n"; |
269
|
|
|
} else { |
270
|
|
|
// got a struct |
271
|
|
|
if($type && $type_prefix){ |
272
|
|
|
$type_str = " xsi:type=\"$type_prefix:$type\""; |
273
|
|
|
} |
274
|
|
|
$xml .= "<$name$xmlns$type_str$atts>\n"; |
|
|
|
|
275
|
|
|
foreach($val as $k => $v){ |
276
|
|
|
$xml .= $this->serialize_val($v,$k); |
277
|
|
|
} |
278
|
|
|
$xml .= "</$name>\n"; |
279
|
|
|
} |
280
|
|
|
break; |
281
|
|
|
default: |
282
|
|
|
$xml .= "not detected, got ".gettype($val)." for $val\n"; |
283
|
|
|
break; |
284
|
|
|
} |
285
|
|
|
return $xml; |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* serialize message |
290
|
|
|
* |
291
|
|
|
* @param string body |
292
|
|
|
* @param string headers |
293
|
|
|
* @param array namespaces |
294
|
|
|
* @return string message |
295
|
|
|
* @access public |
296
|
|
|
*/ |
297
|
|
|
function serializeEnvelope($body,$headers=false,$namespaces=array()){ |
298
|
|
|
// serialize namespaces |
299
|
|
|
foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ |
300
|
|
|
$ns_string .= "\n xmlns:$k=\"$v\""; |
|
|
|
|
301
|
|
|
} |
302
|
|
|
// serialize headers |
303
|
|
|
if($headers){ |
304
|
|
|
$headers = "<SOAP-ENV:Header>\n".$headers."</SOAP-ENV:Header>\n"; |
305
|
|
|
} |
306
|
|
|
// serialize envelope |
307
|
|
|
return |
308
|
|
|
"<?xml version=\"1.0\"?".">\n". |
309
|
|
|
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"$ns_string>\n". |
310
|
|
|
$headers. |
311
|
|
|
"<SOAP-ENV:Body>\n". |
312
|
|
|
$body. |
313
|
|
|
"</SOAP-ENV:Body>\n". |
314
|
|
|
"</SOAP-ENV:Envelope>\n"; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
function formatDump($str){ |
318
|
|
|
$str = htmlspecialchars($str); |
319
|
|
|
return nl2br($str); |
320
|
|
|
} |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
// XML Schema Datatype Helper Functions |
324
|
|
|
|
325
|
|
|
//xsd:dateTime helpers |
326
|
|
|
|
327
|
|
|
/** |
328
|
|
|
* convert unix timestamp to ISO 8601 compliant date string |
329
|
|
|
* |
330
|
|
|
* @param string $timestamp Unix time stamp |
331
|
|
|
* @access public |
332
|
|
|
*/ |
333
|
|
|
function timestamp_to_iso8601($timestamp,$utc=true){ |
334
|
|
|
$datestr = date("Y-m-d\TH:i:sO",$timestamp); |
335
|
|
|
if($utc){ |
336
|
|
|
$pregStr = |
337
|
|
|
"/([0-9]{4})-". // centuries & years CCYY- |
338
|
|
|
"([0-9]{2})-". // months MM- |
339
|
|
|
"([0-9]{2})". // days DD |
340
|
|
|
"T". // separator T |
341
|
|
|
"([0-9]{2}):". // hours hh: |
342
|
|
|
"([0-9]{2}):". // minutes mm: |
343
|
|
|
"([0-9]{2})(\.[0-9]*)?". // seconds ss.ss... |
344
|
|
|
"(Z|[+\-][0-9]{2}:?[0-9]{2})?/"; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's |
345
|
|
|
|
346
|
|
|
if(preg_match($pregStr,$datestr,$regs)){ |
347
|
|
|
return sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); |
348
|
|
|
} |
349
|
|
|
return false; |
350
|
|
|
} else { |
351
|
|
|
return $datestr; |
352
|
|
|
} |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* convert ISO 8601 compliant date string to unix timestamp |
357
|
|
|
* |
358
|
|
|
* @param string $datestr ISO 8601 compliant date string |
359
|
|
|
* @access public |
360
|
|
|
*/ |
361
|
|
|
function iso8601_to_timestamp($datestr){ |
362
|
|
|
$pregStr = |
363
|
|
|
"/([0-9]{4})-". // centuries & years CCYY- |
364
|
|
|
"([0-9]{2})-". // months MM- |
365
|
|
|
"([0-9]{2})". // days DD |
366
|
|
|
"T". // separator T |
367
|
|
|
"([0-9]{2}):". // hours hh: |
368
|
|
|
"([0-9]{2}):". // minutes mm: |
369
|
|
|
"([0-9]{2})(\.[0-9]+)?". // seconds ss.ss... |
370
|
|
|
"(Z|[+\-][0-9]{2}:?[0-9]{2})?/"; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's |
371
|
|
|
if(preg_match($pregStr,$datestr,$regs)){ |
372
|
|
|
// not utc |
373
|
|
|
if($regs[8] != "Z"){ |
374
|
|
|
$op = substr($regs[8],0,1); |
375
|
|
|
$h = substr($regs[8],1,2); |
376
|
|
|
$m = substr($regs[8],strlen($regs[8])-2,2); |
377
|
|
|
if($op == "-"){ |
378
|
|
|
$regs[4] = $regs[4] + $h; |
379
|
|
|
$regs[5] = $regs[5] + $m; |
380
|
|
|
} elseif($op == "+"){ |
381
|
|
|
$regs[4] = $regs[4] - $h; |
382
|
|
|
$regs[5] = $regs[5] - $m; |
383
|
|
|
} |
384
|
|
|
} |
385
|
|
|
return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); |
386
|
|
|
} else { |
387
|
|
|
return false; |
388
|
|
|
} |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
|
392
|
|
|
?> |
393
|
|
|
<?php |
394
|
|
|
|
395
|
|
|
/** |
396
|
|
|
* soap_fault class, allows for creation of faults |
397
|
|
|
* mainly used for returning faults from deployed functions |
398
|
|
|
* in a server instance. |
399
|
|
|
* @access public |
400
|
|
|
*/ |
401
|
|
|
class soap_fault extends nusoap_base { |
402
|
|
|
|
403
|
|
|
var $faultcode; |
404
|
|
|
var $faultactor; |
405
|
|
|
var $faultstring; |
406
|
|
|
var $faultdetail; |
407
|
|
|
|
408
|
|
|
/** |
409
|
|
|
* constructor |
410
|
|
|
* |
411
|
|
|
* @param string $faultcode |
412
|
|
|
* @param string $faultactor (client | server) |
413
|
|
|
* @param string $faultstring |
414
|
|
|
* @param string $faultdetail |
415
|
|
|
*/ |
416
|
|
|
function __construct($faultcode,$faultactor,$faultstring='',$faultdetail=''){ |
417
|
|
|
$this->faultcode = $faultcode; |
418
|
|
|
$this->faultactor = $faultactor; |
419
|
|
|
$this->faultstring = $faultstring; |
420
|
|
|
$this->faultdetail = $faultdetail; |
421
|
|
|
} |
422
|
|
|
|
423
|
|
|
/** |
424
|
|
|
* serialize a fault |
425
|
|
|
* |
426
|
|
|
* @access public |
427
|
|
|
*/ |
428
|
|
|
function serialize(){ |
429
|
|
|
foreach($this->namespaces as $k => $v){ |
430
|
|
|
$ns_string .= "\n xmlns:$k=\"$v\""; |
|
|
|
|
431
|
|
|
} |
432
|
|
|
$return_msg = |
433
|
|
|
"<?xml version=\"1.0\"?".">\n". |
434
|
|
|
"<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"$ns_string>\n". |
435
|
|
|
"<SOAP-ENV:Body>\n". |
436
|
|
|
"<SOAP-ENV:Fault>\n". |
437
|
|
|
"<faultcode>$this->faultcode</faultcode>\n". |
438
|
|
|
"<faultactor>$this->faultactor</faultactor>\n". |
439
|
|
|
"<faultstring>$this->faultstring</faultstring>\n". |
440
|
|
|
"<faultdetail>$this->faultdetail</faultdetail>\n". |
441
|
|
|
"</SOAP-ENV:Fault>\n". |
442
|
|
|
"</SOAP-ENV:Body>\n". |
443
|
|
|
"</SOAP-ENV:Envelope>\n"; |
444
|
|
|
return $return_msg; |
445
|
|
|
} |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
?><?php |
449
|
|
|
/* |
450
|
|
|
|
451
|
|
|
NuSOAP - Web Services Toolkit for PHP |
452
|
|
|
|
453
|
|
|
Copyright (c) 2002 NuSphere Corporation |
454
|
|
|
|
455
|
|
|
This library is free software; you can redistribute it and/or |
456
|
|
|
modify it under the terms of the GNU Lesser General Public |
457
|
|
|
License as published by the Free Software Foundation; either |
458
|
|
|
version 2.1 of the License, or (at your option) any later version. |
459
|
|
|
|
460
|
|
|
This library is distributed in the hope that it will be useful, |
461
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
462
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
463
|
|
|
Lesser General Public License for more details. |
464
|
|
|
|
465
|
|
|
You should have received a copy of the GNU Lesser General Public |
466
|
|
|
License along with this library; if not, write to the Free Software |
467
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
468
|
|
|
|
469
|
|
|
*/ |
470
|
|
|
|
471
|
|
|
/** |
472
|
|
|
* parses an XML Schema, allows access to it's data, other utility methods |
473
|
|
|
* no validation... yet. |
474
|
|
|
* very experimental and limited. As is discussed on XML-DEV, I'm one of the people |
475
|
|
|
* that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty |
476
|
|
|
* tutorials I refer to :) |
477
|
|
|
* |
478
|
|
|
* @author Dietrich Ayala <[email protected]> |
479
|
|
|
* @access public |
480
|
|
|
*/ |
481
|
|
|
class XMLSchema extends nusoap_base { |
482
|
|
|
|
483
|
|
|
/** |
484
|
|
|
* constructor |
485
|
|
|
* |
486
|
|
|
* @param string $schema schema document URI |
487
|
|
|
* @param string $xml xml document URI |
488
|
|
|
* @access public |
489
|
|
|
*/ |
490
|
|
|
function __construct($schema="",$xml=""){ |
491
|
|
|
|
492
|
|
|
$this->debug('xmlschema class instantiated, inside constructor'); |
493
|
|
|
// files |
494
|
|
|
$this->schema = $schema; |
|
|
|
|
495
|
|
|
$this->xml = $xml; |
|
|
|
|
496
|
|
|
|
497
|
|
|
// define internal arrays of bindings, ports, operations, messages, etc. |
498
|
|
|
$this->complexTypes = array(); |
|
|
|
|
499
|
|
|
|
500
|
|
|
// parser vars |
501
|
|
|
$this->parser; |
|
|
|
|
502
|
|
|
$this->position; |
|
|
|
|
503
|
|
|
$this->depth; |
|
|
|
|
504
|
|
|
$this->depth_array = array(); |
|
|
|
|
505
|
|
|
|
506
|
|
|
// parse schema file |
507
|
|
|
if($schema != ""){ |
508
|
|
|
$this->debug("initial schema file: $schema"); |
509
|
|
|
$this->parseFile($schema); |
|
|
|
|
510
|
|
|
} |
511
|
|
|
|
512
|
|
|
// parse xml file |
513
|
|
|
if($xml != ""){ |
514
|
|
|
$this->debug("initial xml file: $xml"); |
515
|
|
|
$this->parseFile($xml); |
|
|
|
|
516
|
|
|
} |
517
|
|
|
|
518
|
|
|
} |
519
|
|
|
|
520
|
|
|
/** |
521
|
|
|
* parse an XML file |
522
|
|
|
* |
523
|
|
|
* @param string $xml, path/URL to XML file |
|
|
|
|
524
|
|
|
* @param string $type, (schema | xml) |
|
|
|
|
525
|
|
|
* @return boolean |
526
|
|
|
* @access public |
527
|
|
|
*/ |
528
|
|
|
function parseFile($xml,$type){ |
529
|
|
|
// parse xml file |
530
|
|
|
if($xml != ""){ |
531
|
|
|
$this->debug("parsing $xml"); |
532
|
|
|
$xmlStr = @join("",@file($xml)); |
533
|
|
|
if($xmlStr == ""){ |
534
|
|
|
$this->setError("No file at the specified URL: $xml."); |
535
|
|
|
return false; |
536
|
|
|
} else { |
537
|
|
|
$this->parseString($xmlStr,$type); |
538
|
|
|
return true; |
539
|
|
|
} |
540
|
|
|
} |
541
|
|
|
return false; |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
/** |
545
|
|
|
* parse an XML string |
546
|
|
|
* |
547
|
|
|
* @param string $xml path or URL |
548
|
|
|
* @param string $type, (schema|xml) |
|
|
|
|
549
|
|
|
* @access private |
550
|
|
|
*/ |
551
|
|
|
function parseString($xml,$type){ |
552
|
|
|
// parse xml string |
553
|
|
|
if($xml != ""){ |
554
|
|
|
|
555
|
|
|
// Create an XML parser. |
556
|
|
|
$this->parser = xml_parser_create(); |
557
|
|
|
// Set the options for parsing the XML data. |
558
|
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
559
|
|
|
|
560
|
|
|
// Set the object for the parser. |
561
|
|
|
xml_set_object($this->parser, $this); |
562
|
|
|
|
563
|
|
|
// Set the element handlers for the parser. |
564
|
|
|
if($type == "schema"){ |
565
|
|
|
xml_set_element_handler($this->parser, "schemaStartElement","schemaEndElement"); |
566
|
|
|
xml_set_character_data_handler($this->parser,"schemaCharacterData"); |
567
|
|
|
} elseif($type == "xml"){ |
568
|
|
|
xml_set_element_handler($this->parser, "xmlStartElement","xmlEndElement"); |
569
|
|
|
xml_set_character_data_handler($this->parser,"xmlCharacterData"); |
570
|
|
|
} |
571
|
|
|
|
572
|
|
|
// Parse the XML file. |
573
|
|
View Code Duplication |
if(!xml_parse($this->parser,$xml,true)){ |
574
|
|
|
// Display an error message. |
575
|
|
|
$errstr = sprintf("XML error on line %d: %s", |
576
|
|
|
xml_get_current_line_number($this->parser), |
577
|
|
|
xml_error_string(xml_get_error_code($this->parser)) |
578
|
|
|
); |
579
|
|
|
$this->debug("XML parse error: $errstr"); |
580
|
|
|
$this->setError("Parser error: $errstr"); |
581
|
|
|
} |
582
|
|
|
xml_parser_free($this->parser); |
583
|
|
|
} else{ |
584
|
|
|
$this->debug("no xml passed to parseString()!!"); |
585
|
|
|
$this->setError("no xml passed to parseString()!!"); |
586
|
|
|
} |
587
|
|
|
} |
588
|
|
|
|
589
|
|
|
/** |
590
|
|
|
* start-element handler |
591
|
|
|
* |
592
|
|
|
* @param string $parser XML parser object |
593
|
|
|
* @param string $name element name |
594
|
|
|
* @param string $attrs associative array of attributes |
595
|
|
|
* @access private |
596
|
|
|
*/ |
597
|
|
|
function schemaStartElement($parser, $name, $attrs) { |
|
|
|
|
598
|
|
|
|
599
|
|
|
// position in the total number of elements, starting from 0 |
600
|
|
|
$pos = $this->position++; |
601
|
|
|
$depth = $this->depth++; |
602
|
|
|
// set self as current value for this depth |
603
|
|
|
$this->depth_array[$depth] = $pos; |
604
|
|
|
|
605
|
|
|
// loop through atts, logging ns declarations |
606
|
|
View Code Duplication |
foreach($attrs as $key => $value){ |
|
|
|
|
607
|
|
|
// if ns declarations, add to class level array of valid namespaces |
608
|
|
|
if(preg_match("/^xmlns/",$key)){ |
609
|
|
|
if($ns_prefix = substr(strrchr($key,":"),1)){ |
610
|
|
|
$this->namespaces[$ns_prefix] = $value; |
611
|
|
|
} else { |
612
|
|
|
$this->namespaces['ns'.(count($this->namespaces)+1)] = $value; |
613
|
|
|
} |
614
|
|
|
if($value == 'http://www.w3.org/2001/XMLSchema'){ |
615
|
|
|
$this->XMLSchemaVersion = $value; |
|
|
|
|
616
|
|
|
$this->namespaces['xsi'] = $value.'-instance'; |
617
|
|
|
} elseif($value == 'http://www.w3.org/1999/XMLSchema'){ |
618
|
|
|
$this->XMLSchemaVersion = $value; |
|
|
|
|
619
|
|
|
$this->namespaces['xsi'] = $value.'-instance'; |
620
|
|
|
} |
621
|
|
|
} |
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
// get element prefix |
625
|
|
View Code Duplication |
if(preg_match("/:/",$name)){ |
626
|
|
|
// get ns prefix |
627
|
|
|
$prefix = substr($name,0,strpos($name,":")); |
628
|
|
|
// get unqualified name |
629
|
|
|
$name = substr(strstr($name,":"),1); |
630
|
|
|
} |
631
|
|
|
//$this->debug("name: $name, prefix: $prefix"); |
632
|
|
|
|
633
|
|
|
// find status, register data |
634
|
|
|
switch($name){ |
635
|
|
|
case "all": |
636
|
|
|
$this->complexTypes[$this->currentComplexType]["compositor"] = "all"; |
|
|
|
|
637
|
|
|
$this->complexTypes[$this->currentComplexType]["phpType"] = "struct"; |
638
|
|
|
break; |
639
|
|
|
case "attribute": |
640
|
|
|
if($attrs["name"]){ |
641
|
|
|
$this->attributes[$attrs["name"]] = $attrs; |
|
|
|
|
642
|
|
|
$aname = $attrs["name"]; |
643
|
|
|
} elseif($attrs["ref"]){ |
644
|
|
|
$aname = $this->expandQName($attrs["ref"]); |
645
|
|
|
} |
646
|
|
|
|
647
|
|
|
if($this->currentComplexType){ |
648
|
|
|
$this->complexTypes[$this->currentComplexType]["attrs"][$aname] = $attrs; |
|
|
|
|
649
|
|
|
} elseif($this->currentElement){ |
|
|
|
|
650
|
|
|
$this->elements[$this->currentElement]['attrs'][$aname] = $attrs; |
|
|
|
|
651
|
|
|
} |
652
|
|
|
|
653
|
|
|
if($aname == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ |
654
|
|
|
foreach($attrs as $k => $v){ |
|
|
|
|
655
|
|
|
if(strstr($k,':') == ':arrayType'){ |
656
|
|
|
if(strpos($v,'[,]')){ |
657
|
|
|
$this->complexTypes[$this->currentComplexType]["multidimensional"] = true; |
658
|
|
|
} |
659
|
|
|
$v = substr($v,0,strpos($v,'[')); // clip the [] |
660
|
|
|
if(strpos($v,':')){ |
661
|
|
|
$v = $this->expandQName($v); |
662
|
|
|
} else { |
663
|
|
|
$v = $this->XMLSchemaVersion.':'.$v; |
|
|
|
|
664
|
|
|
} |
665
|
|
|
$this->complexTypes[$this->currentComplexType]["arrayType"] = $v; |
666
|
|
|
break; |
667
|
|
|
} |
668
|
|
|
} |
669
|
|
|
} |
670
|
|
|
break; |
671
|
|
|
case "complexContent": |
672
|
|
|
|
673
|
|
|
break; |
674
|
|
|
case 'complexType': |
675
|
|
|
if($attrs['name']){ |
676
|
|
|
$this->currentElement = false; |
677
|
|
|
$this->currentComplexType = $attrs['name']; |
678
|
|
|
$this->complexTypes[$this->currentComplexType] = $attrs; |
679
|
|
|
$this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; |
680
|
|
|
if(preg_match('/:Array$/',$attrs['base'])){ |
681
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; |
682
|
|
|
} else { |
683
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
684
|
|
|
} |
685
|
|
|
$this->xdebug("processing complexType $attrs[name]"); |
686
|
|
|
} |
687
|
|
|
break; |
688
|
|
|
case 'element': |
689
|
|
|
if(isset($attrs['type'])){ |
690
|
|
|
$this->xdebug("processing element ".$attrs['name']); |
691
|
|
|
$this->currentElement = $attrs['name']; |
692
|
|
|
$this->elements[ $attrs['name'] ] = $attrs; |
693
|
|
|
$this->elements[ $attrs['name'] ]['typeClass'] = 'element'; |
694
|
|
|
$ename = $attrs['name']; |
695
|
|
|
} elseif(isset($attrs['ref'])){ |
696
|
|
|
$ename = $attrs['ref']; |
697
|
|
|
} else { |
698
|
|
|
$this->xdebug("adding complexType $attrs[name]"); |
699
|
|
|
$this->currentComplexType = $attrs['name']; |
700
|
|
|
$this->complexTypes[ $attrs['name'] ] = $attrs; |
701
|
|
|
$this->complexTypes[ $attrs['name'] ]['element'] = 1; |
702
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; |
703
|
|
|
} |
704
|
|
|
if($ename && $this->currentComplexType){ |
705
|
|
|
$this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; |
|
|
|
|
706
|
|
|
} |
707
|
|
|
break; |
708
|
|
|
case 'restriction': |
709
|
|
|
$this->xdebug("in restriction for ct: $this->currentComplexType and ce: $this->currentElement"); |
710
|
|
|
if($this->currentElement){ |
711
|
|
|
$this->elements[$this->currentElement]['type'] = $attrs['base']; |
712
|
|
|
} elseif($this->currentComplexType){ |
713
|
|
|
$this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; |
714
|
|
|
if(strstr($attrs['base'],':') == ':Array'){ |
715
|
|
|
$this->complexTypes[$this->currentComplexType]['phpType'] = "array"; |
716
|
|
|
} |
717
|
|
|
} |
718
|
|
|
break; |
719
|
|
|
case 'schema': |
720
|
|
|
$this->schema = $attrs; |
721
|
|
|
$this->schema['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); |
|
|
|
|
722
|
|
|
break; |
723
|
|
|
case 'sequence': |
724
|
|
|
$this->complexTypes[$this->currentComplexType]['compositor'] = 'sequence'; |
725
|
|
|
break; |
726
|
|
|
case 'simpleType': |
727
|
|
|
$this->currentElement = $attrs['name']; |
728
|
|
|
$this->elements[ $attrs['name'] ] = $attrs; |
729
|
|
|
$this->elements[ $attrs['name'] ]['typeClass'] = 'element'; |
730
|
|
|
break; |
731
|
|
|
} |
732
|
|
|
} |
733
|
|
|
|
734
|
|
|
/** |
735
|
|
|
* end-element handler |
736
|
|
|
* |
737
|
|
|
* @param string $parser XML parser object |
738
|
|
|
* @param string $name element name |
739
|
|
|
* @access private |
740
|
|
|
*/ |
741
|
|
|
function schemaEndElement($parser, $name) { |
|
|
|
|
742
|
|
|
// position of current element is equal to the last value left in depth_array for my depth |
743
|
|
|
$pos = $this->depth_array[$this->depth]; |
|
|
|
|
744
|
|
|
// bring depth down a notch |
745
|
|
|
$this->depth--; |
746
|
|
|
// move on... |
747
|
|
|
if($name == 'complexType'){ |
748
|
|
|
$this->currentComplexType = false; |
749
|
|
|
$this->currentElement = false; |
750
|
|
|
} |
751
|
|
|
if($name == 'element'){ |
752
|
|
|
$this->currentElement = false; |
753
|
|
|
} |
754
|
|
|
} |
755
|
|
|
|
756
|
|
|
/** |
757
|
|
|
* element content handler |
758
|
|
|
* |
759
|
|
|
* @param string $parser XML parser object |
760
|
|
|
* @param string $data element content |
761
|
|
|
* @access private |
762
|
|
|
*/ |
763
|
|
|
function schemaCharacterData($parser, $data){ |
|
|
|
|
764
|
|
|
$pos = $this->depth_array[$this->depth]; |
765
|
|
|
$this->message[$pos]["cdata"] .= $data; |
|
|
|
|
766
|
|
|
} |
767
|
|
|
|
768
|
|
|
/** |
769
|
|
|
* serialize the schema |
770
|
|
|
* |
771
|
|
|
* @access public |
772
|
|
|
*/ |
773
|
|
|
function serializeSchema(){ |
774
|
|
|
|
775
|
|
|
$schemaPrefix = $this->getPrefixFromNamespace($this->schema['schemaVersion']); |
776
|
|
|
// complex types |
777
|
|
|
foreach($this->complexTypes as $typeName => $attrs){ |
778
|
|
|
$contentStr = ""; |
779
|
|
|
// serialize child elements |
780
|
|
|
if(count($attrs["elements"]) > 0){ |
781
|
|
|
foreach($attrs["elements"] as $element => $eParts){ |
782
|
|
|
$contentStr .= "<element ref=\"$element\"/>\n"; |
783
|
|
|
} |
784
|
|
|
} |
785
|
|
|
// serialize attributes |
786
|
|
|
if(count($attrs["attrs"]) > 0){ |
787
|
|
|
foreach($attrs["attrs"] as $attr => $aParts){ |
788
|
|
|
$contentStr .= "<attribute ref=\"$attr\"/>\n"; |
789
|
|
|
} |
790
|
|
|
} |
791
|
|
|
|
792
|
|
|
// if restriction |
793
|
|
|
if($attrs["restrictionBase"]){ |
794
|
|
|
$contentStr = "<$schemaPrefix:restriction base=\"".$attrs["restrictionBase"]."\">\n". |
795
|
|
|
$contentStr."</$schemaPrefix:restriction>\n"; |
796
|
|
|
} |
797
|
|
|
if($attrs["complexContent"]){ |
798
|
|
|
$contentStr = "<$schemaPrefix:complexContent>\n". |
799
|
|
|
$contentStr."</$schemaPrefix:complexContent>\n"; |
800
|
|
|
} elseif($attrs["sequence"]){ |
801
|
|
|
$contentStr = "<$schemaPrefix:sequence>\n". |
802
|
|
|
$contentStr."</$schemaPrefix:sequence>\n"; |
803
|
|
|
} elseif($attrs["all"]){ |
804
|
|
|
$contentStr = "<$schemaPrefix:all>\n". |
805
|
|
|
$contentStr."</$schemaPrefix:all>\n"; |
806
|
|
|
} |
807
|
|
|
if($attrs['element']){ |
808
|
|
|
if($contentStr != ""){ |
809
|
|
|
$contentStr = "<$schemaPrefix:element name=\"$typeName\">\n"."<$schemaPrefix:complexType>\n". |
810
|
|
|
$contentStr."</$schemaPrefix:complexType>\n"."</$schemaPrefix:element>\n"; |
811
|
|
|
} else { |
812
|
|
|
$contentStr = "<$schemaPrefix:element name=\"$typeName\">\n"."<$schemaPrefix:complexType/>\n". |
813
|
|
|
"</$schemaPrefix:element>\n"; |
814
|
|
|
} |
815
|
|
|
} else { |
816
|
|
|
if($contentStr != ""){ |
817
|
|
|
$contentStr = "<$schemaPrefix:complexType name=\"$typeName\">\n". |
818
|
|
|
$contentStr."</$schemaPrefix:complexType>\n"; |
819
|
|
|
} else { |
820
|
|
|
$contentStr = "<$schemaPrefix:complexType name=\"$typeName\"/>\n"; |
821
|
|
|
} |
822
|
|
|
} |
823
|
|
|
$xml .= $contentStr; |
|
|
|
|
824
|
|
|
} |
825
|
|
|
// elements |
826
|
|
|
if(count($this->elements) > 0){ |
827
|
|
|
foreach($this->elements as $element => $eParts){ |
828
|
|
|
$xml .= "<$schemaPrefix:element name=\"$element\" type=\"".$eParts['type']."\"/>\n"; |
829
|
|
|
} |
830
|
|
|
} |
831
|
|
|
// attributes |
832
|
|
|
if(count($this->attributes) > 0){ |
833
|
|
|
foreach($this->attributes as $attr => $aParts){ |
834
|
|
|
$xml .= "<$schemaPrefix:attribute name=\"$attr\" type=\"".$aParts['type']."\"/>\n"; |
835
|
|
|
} |
836
|
|
|
} |
837
|
|
|
$xml = "<$schemaPrefix:schema targetNamespace=\"".$this->schema["targetNamespace"]."\">\n". |
838
|
|
|
$xml."</$schemaPrefix:schema>\n"; |
839
|
|
|
|
840
|
|
|
return $xml; |
841
|
|
|
} |
842
|
|
|
|
843
|
|
|
/** |
844
|
|
|
* expands a qualified name |
845
|
|
|
* |
846
|
|
|
* @param string $string qname |
|
|
|
|
847
|
|
|
* @return string expanded qname |
848
|
|
|
* @access private |
849
|
|
|
*/ |
850
|
|
|
function expandQname($qname){ |
851
|
|
|
// get element prefix |
852
|
|
|
if(preg_match("/:/",$qname)){ |
853
|
|
|
// get unqualified name |
854
|
|
|
$name = substr(strstr($qname,":"),1); |
855
|
|
|
// get ns prefix |
856
|
|
|
$prefix = substr($qname,0,strpos($qname,":")); |
857
|
|
|
if(isset($this->namespaces[$prefix])){ |
858
|
|
|
return $this->namespaces[$prefix].":".$name; |
859
|
|
|
} else { |
860
|
|
|
return false; |
861
|
|
|
} |
862
|
|
|
} else { |
863
|
|
|
return $qname; |
864
|
|
|
} |
865
|
|
|
} |
866
|
|
|
|
867
|
|
|
/** |
868
|
|
|
* adds debug data to the clas level debug string |
869
|
|
|
* |
870
|
|
|
* @param string $string debug data |
871
|
|
|
* @access private |
872
|
|
|
*/ |
873
|
|
|
function xdebug($string){ |
874
|
|
|
$this->debug(" xmlschema: $string"); |
875
|
|
|
} |
876
|
|
|
|
877
|
|
|
/** |
878
|
|
|
* get the PHP type of a user defined type in the schema |
879
|
|
|
* PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays |
880
|
|
|
* returns false if no type exists, or not w/ the given namespace |
881
|
|
|
* else returns a string that is either a native php type, or 'struct' |
882
|
|
|
* |
883
|
|
|
* @param string $type, name of defined type |
|
|
|
|
884
|
|
|
* @param string $ns, namespace of type |
|
|
|
|
885
|
|
|
* @return mixed |
886
|
|
|
* @access public |
887
|
|
|
*/ |
888
|
|
|
function getPHPType($type,$ns){ |
889
|
|
|
global $typemap; |
890
|
|
|
if(isset($typemap[$ns][$type])){ |
891
|
|
|
//print "found type '$type' and ns $ns in typemap<br>"; |
892
|
|
|
return $typemap[$ns][$type]; |
893
|
|
|
} elseif(isset($this->complexTypes[$type])){ |
894
|
|
|
//print "getting type '$type' and ns $ns from complexTypes array<br>"; |
895
|
|
|
return $this->complexTypes[$type]["phpType"]; |
896
|
|
|
} |
897
|
|
|
return false; |
898
|
|
|
} |
899
|
|
|
|
900
|
|
|
/** |
901
|
|
|
* returns the local part of a prefixed string |
902
|
|
|
* returns the original string, if not prefixed |
903
|
|
|
* |
904
|
|
|
* @param string |
905
|
|
|
* @return string |
906
|
|
|
* @access public |
907
|
|
|
*/ |
908
|
|
|
function getLocalPart($str){ |
909
|
|
|
if($sstr = strrchr($str,':')){ |
910
|
|
|
// get unqualified name |
911
|
|
|
return substr( $sstr, 1 ); |
912
|
|
|
} else { |
913
|
|
|
return $str; |
914
|
|
|
} |
915
|
|
|
} |
916
|
|
|
|
917
|
|
|
/** |
918
|
|
|
* returns the prefix part of a prefixed string |
919
|
|
|
* returns false, if not prefixed |
920
|
|
|
* |
921
|
|
|
* @param string |
922
|
|
|
* @return mixed |
923
|
|
|
* @access public |
924
|
|
|
*/ |
925
|
|
|
function getPrefix($str){ |
926
|
|
|
if($pos = strrpos($str,':')){ |
927
|
|
|
// get prefix |
928
|
|
|
return substr($str,0,$pos); |
929
|
|
|
} |
930
|
|
|
return false; |
931
|
|
|
} |
932
|
|
|
|
933
|
|
|
/** |
934
|
|
|
* pass it a prefix, it returns a namespace |
935
|
|
|
* or false if no prefixes registered for the given namespace |
936
|
|
|
* |
937
|
|
|
* @param string |
938
|
|
|
* @return mixed |
939
|
|
|
* @access public |
940
|
|
|
*/ |
941
|
|
|
function getNamespaceFromPrefix($prefix){ |
942
|
|
|
if(isset($this->namespaces[$prefix])){ |
943
|
|
|
return $this->namespaces[$prefix]; |
944
|
|
|
} |
945
|
|
|
//$this->setError("No namespace registered for prefix '$prefix'"); |
946
|
|
|
return false; |
947
|
|
|
} |
948
|
|
|
|
949
|
|
|
/** |
950
|
|
|
* returns the prefix for a given namespace |
951
|
|
|
* returns false if no namespace registered with the given prefix |
952
|
|
|
* |
953
|
|
|
* @param string |
954
|
|
|
* @return mixed |
955
|
|
|
* @access public |
956
|
|
|
*/ |
957
|
|
|
function getPrefixFromNamespace($ns){ |
958
|
|
|
foreach($this->namespaces as $p => $n){ |
959
|
|
|
if($ns == $n){ |
960
|
|
|
$this->usedNamespaces[$p] = $ns; |
|
|
|
|
961
|
|
|
return $p; |
962
|
|
|
} |
963
|
|
|
} |
964
|
|
|
return false; |
965
|
|
|
} |
966
|
|
|
|
967
|
|
|
/** |
968
|
|
|
* returns an array of information about a given type |
969
|
|
|
* returns false if no type exists by the given name |
970
|
|
|
* |
971
|
|
|
* typeDef = array( |
972
|
|
|
* 'elements' => array(), // refs to elements array |
973
|
|
|
* 'restrictionBase' => '', |
974
|
|
|
* 'phpType' => '', |
975
|
|
|
* 'order' => '(sequence|all)', |
976
|
|
|
* 'attrs' => array() // refs to attributes array |
977
|
|
|
* ) |
978
|
|
|
* |
979
|
|
|
* @param string |
980
|
|
|
* @return mixed |
981
|
|
|
* @access public |
982
|
|
|
*/ |
983
|
|
|
function getTypeDef($type){ |
984
|
|
|
if(isset($this->complexTypes[$type])){ |
985
|
|
|
return $this->complexTypes[$type]; |
986
|
|
|
} elseif(isset($this->elements[$type])){ |
987
|
|
|
return $this->elements[$type]; |
988
|
|
|
} elseif(isset($this->attributes[$type])){ |
989
|
|
|
return $this->attributes[$type]; |
990
|
|
|
} |
991
|
|
|
return false; |
992
|
|
|
} |
993
|
|
|
|
994
|
|
|
/** |
995
|
|
|
* returns a sample serialization of a given type, or false if no type by the given name |
996
|
|
|
* |
997
|
|
|
* @param string $type, name of type |
|
|
|
|
998
|
|
|
* @return mixed |
999
|
|
|
* @access public |
1000
|
|
|
*/ |
1001
|
|
|
function serializeTypeDef($type){ |
1002
|
|
|
//print "in sTD() for type $type<br>"; |
1003
|
|
|
if($typeDef = $this->getTypeDef($type)){ |
1004
|
|
|
$str .= "<$type"; |
|
|
|
|
1005
|
|
|
if(is_array($typeDef['attrs'])){ |
1006
|
|
|
foreach($attrs as $attName => $data){ |
|
|
|
|
1007
|
|
|
$str .= " $attName=\"{type = ".$data['type']."}\""; |
1008
|
|
|
} |
1009
|
|
|
} |
1010
|
|
|
$str .= " xmlns=\"".$this->schema['targetNamespace']."\""; |
1011
|
|
|
if(count($typeDef['elements']) > 0){ |
1012
|
|
|
$str .= ">\n"; |
1013
|
|
|
foreach($typeDef['elements'] as $element => $eData){ |
1014
|
|
|
$str .= $this->serializeTypeDef($element); |
1015
|
|
|
} |
1016
|
|
|
$str .= "</$type>\n"; |
1017
|
|
|
} elseif($typeDef['typeClass'] == 'element') { |
1018
|
|
|
$str .= "></$type>\n"; |
1019
|
|
|
} else { |
1020
|
|
|
$str .= "/>\n"; |
1021
|
|
|
} |
1022
|
|
|
return $str; |
1023
|
|
|
} |
1024
|
|
|
return false; |
1025
|
|
|
} |
1026
|
|
|
|
1027
|
|
|
/** |
1028
|
|
|
* returns HTML form elements that allow a user |
1029
|
|
|
* to enter values for creating an instance of the given type. |
1030
|
|
|
* |
1031
|
|
|
* @param string $name, name for type instance |
|
|
|
|
1032
|
|
|
* @param string $type, name of type |
|
|
|
|
1033
|
|
|
* @return string |
1034
|
|
|
* @access public |
1035
|
|
|
*/ |
1036
|
|
|
function typeToForm($name,$type){ |
1037
|
|
|
// get typedef |
1038
|
|
|
if($typeDef = $this->getTypeDef($type)){ |
1039
|
|
|
// if struct |
1040
|
|
|
if($typeDef['phpType'] == 'struct'){ |
1041
|
|
|
$buffer .= '<table>'; |
|
|
|
|
1042
|
|
|
foreach($typeDef['elements'] as $child => $childDef){ |
1043
|
|
|
$buffer .= " |
1044
|
|
|
<tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td> |
1045
|
|
|
<td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>"; |
1046
|
|
|
} |
1047
|
|
|
$buffer .= '</table>'; |
1048
|
|
|
// if array |
1049
|
|
|
} elseif($typeDef['phpType'] == 'array'){ |
1050
|
|
|
$buffer .= '<table>'; |
1051
|
|
|
for($i=0;$i < 3; $i++){ |
1052
|
|
|
$buffer .= " |
1053
|
|
|
<tr><td align='right'>array item (type: $typeDef[arrayType]):</td> |
1054
|
|
|
<td><input type='text' name='parameters[".$name."][]'></td></tr>"; |
1055
|
|
|
} |
1056
|
|
|
$buffer .= '</table>'; |
1057
|
|
|
// if scalar |
1058
|
|
|
} else { |
1059
|
|
|
$buffer .= "<input type='text' name='parameters[$name]'>"; |
1060
|
|
|
} |
1061
|
|
|
} else { |
1062
|
|
|
$buffer .= "<input type='text' name='parameters[$name]'>"; |
1063
|
|
|
} |
1064
|
|
|
return $buffer; |
1065
|
|
|
} |
1066
|
|
|
} |
1067
|
|
|
|
1068
|
|
|
?> |
1069
|
|
|
<?php |
1070
|
|
|
|
1071
|
|
|
/* |
1072
|
|
|
|
1073
|
|
|
NuSOAP - Web Services Toolkit for PHP |
1074
|
|
|
|
1075
|
|
|
Copyright (c) 2002 NuSphere Corporation |
1076
|
|
|
|
1077
|
|
|
This library is free software; you can redistribute it and/or |
1078
|
|
|
modify it under the terms of the GNU Lesser General Public |
1079
|
|
|
License as published by the Free Software Foundation; either |
1080
|
|
|
version 2.1 of the License, or (at your option) any later version. |
1081
|
|
|
|
1082
|
|
|
This library is distributed in the hope that it will be useful, |
1083
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1084
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1085
|
|
|
Lesser General Public License for more details. |
1086
|
|
|
|
1087
|
|
|
You should have received a copy of the GNU Lesser General Public |
1088
|
|
|
License along with this library; if not, write to the Free Software |
1089
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1090
|
|
|
|
1091
|
|
|
*/ |
1092
|
|
|
|
1093
|
|
|
/** |
1094
|
|
|
* for creating serializable abstractions of native PHP types |
1095
|
|
|
* NOTE: this is only really used when WSDL is not available. |
1096
|
|
|
* |
1097
|
|
|
* @author Dietrich Ayala <[email protected]> |
1098
|
|
|
* @version v 0.6 |
1099
|
|
|
* @access public |
1100
|
|
|
*/ |
1101
|
|
|
class soapval extends nusoap_base { |
1102
|
|
|
/** |
1103
|
|
|
* constructor |
1104
|
|
|
* |
1105
|
|
|
* @param string $name optional value name |
1106
|
|
|
* @param string $type optional type name |
1107
|
|
|
* @param mixed $value optional content of value |
1108
|
|
|
* @param string $namespace optional namespace of value |
|
|
|
|
1109
|
|
|
* @param string $type_namespace optional namespace of type |
|
|
|
|
1110
|
|
|
* @param array $attributes associative array of attributes to add to element serialization |
1111
|
|
|
* @access public |
1112
|
|
|
*/ |
1113
|
|
|
function __construct($name="noname",$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { |
1114
|
|
|
$this->name = $name; |
|
|
|
|
1115
|
|
|
$this->value = $value; |
|
|
|
|
1116
|
|
|
$this->type = $type; |
|
|
|
|
1117
|
|
|
$this->element_ns = $element_ns; |
|
|
|
|
1118
|
|
|
$this->type_ns = $type_ns; |
|
|
|
|
1119
|
|
|
$this->attributes = $attributes; |
|
|
|
|
1120
|
|
|
} |
1121
|
|
|
|
1122
|
|
|
/** |
1123
|
|
|
* return serialized value |
1124
|
|
|
* |
1125
|
|
|
* @return string XML data |
1126
|
|
|
* @access private |
1127
|
|
|
*/ |
1128
|
|
|
function serialize() { |
1129
|
|
|
return $this->serialize_val($this->value,$this->name,$this->type,$this->element_ns,$this->type_ns,$this->attributes); |
1130
|
|
|
} |
1131
|
|
|
|
1132
|
|
|
/** |
1133
|
|
|
* decodes a soapval object into a PHP native type |
1134
|
|
|
* |
1135
|
|
|
* @param object $soapval optional SOAPx4 soapval object, else uses self |
|
|
|
|
1136
|
|
|
* @return mixed |
1137
|
|
|
* @access public |
1138
|
|
|
*/ |
1139
|
|
|
function decode(){ |
1140
|
|
|
return $this->value; |
1141
|
|
|
} |
1142
|
|
|
} |
1143
|
|
|
|
1144
|
|
|
?> |
1145
|
|
|
<?php |
1146
|
|
|
/* |
1147
|
|
|
|
1148
|
|
|
NuSOAP - Web Services Toolkit for PHP |
1149
|
|
|
|
1150
|
|
|
Copyright (c) 2002 NuSphere Corporation |
1151
|
|
|
|
1152
|
|
|
This library is free software; you can redistribute it and/or |
1153
|
|
|
modify it under the terms of the GNU Lesser General Public |
1154
|
|
|
License as published by the Free Software Foundation; either |
1155
|
|
|
version 2.1 of the License, or (at your option) any later version. |
1156
|
|
|
|
1157
|
|
|
This library is distributed in the hope that it will be useful, |
1158
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1159
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1160
|
|
|
Lesser General Public License for more details. |
1161
|
|
|
|
1162
|
|
|
You should have received a copy of the GNU Lesser General Public |
1163
|
|
|
License along with this library; if not, write to the Free Software |
1164
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1165
|
|
|
|
1166
|
|
|
*/ |
1167
|
|
|
|
1168
|
|
|
/** |
1169
|
|
|
* transport class for sending/receiving data via HTTP and HTTPS |
1170
|
|
|
* NOTE: PHP must be compiled with the CURL extension for HTTPS support |
1171
|
|
|
* HTTPS support is experimental! |
1172
|
|
|
* |
1173
|
|
|
* @access public |
1174
|
|
|
*/ |
1175
|
|
|
class soap_transport_http extends nusoap_base { |
1176
|
|
|
|
1177
|
|
|
var $username; |
1178
|
|
|
var $password; |
1179
|
|
|
var $url; |
1180
|
|
|
/** |
1181
|
|
|
* constructor |
1182
|
|
|
*/ |
1183
|
|
|
function __construct($url){ |
1184
|
|
|
$this->url = $url; |
1185
|
|
|
$u = parse_url($url); |
1186
|
|
|
foreach($u as $k => $v){ |
|
|
|
|
1187
|
|
|
$this->debug("$k = $v"); |
1188
|
|
|
$this->$k = $v; |
1189
|
|
|
} |
1190
|
|
|
if($u['query'] != ''){ |
1191
|
|
|
$this->path .= $u['query']; |
|
|
|
|
1192
|
|
|
} |
1193
|
|
|
if(!isset($u['port']) && $u['scheme'] == 'http'){ |
1194
|
|
|
$this->port = 80; |
|
|
|
|
1195
|
|
|
} |
1196
|
|
|
} |
1197
|
|
|
|
1198
|
|
|
/** |
1199
|
|
|
* if authenticating, set user credentials here |
1200
|
|
|
* |
1201
|
|
|
* @param string $user |
1202
|
|
|
* @param string $pass |
1203
|
|
|
* @access public |
1204
|
|
|
*/ |
1205
|
|
|
function setCredentials($user, $pass) { |
|
|
|
|
1206
|
|
|
$this->user = $username; |
|
|
|
|
1207
|
|
|
$this->pass = $pword; |
|
|
|
|
1208
|
|
|
} |
1209
|
|
|
|
1210
|
|
|
/** |
1211
|
|
|
* set the soapaction value |
1212
|
|
|
* |
1213
|
|
|
* @param string $soapaction |
1214
|
|
|
* @access public |
1215
|
|
|
*/ |
1216
|
|
|
function setSOAPAction($soapaction) { |
1217
|
|
|
$this->soapaction = $soapaction; |
|
|
|
|
1218
|
|
|
} |
1219
|
|
|
|
1220
|
|
|
/** |
1221
|
|
|
* set proxy info here |
1222
|
|
|
* |
1223
|
|
|
* @param string $proxyhost |
1224
|
|
|
* @param string $proxyport |
1225
|
|
|
* @access public |
1226
|
|
|
*/ |
1227
|
|
|
function setProxy($proxyhost, $proxyport) { |
1228
|
|
|
$this->proxyhost = $proxyhost; |
|
|
|
|
1229
|
|
|
$this->proxyport = $proxyport; |
|
|
|
|
1230
|
|
|
} |
1231
|
|
|
|
1232
|
|
|
/** |
1233
|
|
|
* send the SOAP message via HTTP 1.0 |
1234
|
|
|
* |
1235
|
|
|
* @param string $msg message data |
|
|
|
|
1236
|
|
|
* @param integer $timeout set timeout in seconds |
1237
|
|
|
* @return string data |
1238
|
|
|
* @access public |
1239
|
|
|
*/ |
1240
|
|
|
function send($data, $timeout=0) { |
1241
|
|
|
flush(); |
1242
|
|
|
$this->debug('entered send() with data of length: '.strlen($data)); |
1243
|
|
|
|
1244
|
|
View Code Duplication |
if($this->proxyhost && $this->proxyport){ |
1245
|
|
|
$host = $this->proxyhost; |
1246
|
|
|
$port = $this->proxyport; |
1247
|
|
|
} else { |
1248
|
|
|
$host = $this->host; |
|
|
|
|
1249
|
|
|
$port = $this->port; |
1250
|
|
|
} |
1251
|
|
|
if($timeout > 0){ |
1252
|
|
|
$fp = fsockopen($host, $port, $this->errno, $this->error_str, $timeout); |
|
|
|
|
1253
|
|
|
} else { |
1254
|
|
|
$fp = fsockopen($host, $port, $this->errno, $this->error_str); |
1255
|
|
|
} |
1256
|
|
|
//socket_set_blocking($fp,0); |
1257
|
|
|
if (!$fp) { |
1258
|
|
|
$this->debug("Couldn't open socket connection to server: $server!"); |
|
|
|
|
1259
|
|
|
$this->setError("Couldn't open socket connection to server: $server."); |
1260
|
|
|
return false; |
1261
|
|
|
} |
1262
|
|
|
|
1263
|
|
|
$credentials = ''; |
1264
|
|
|
if($this->user != '') { |
1265
|
|
|
$credentials = 'Authorization: Basic '.base64_encode('$this->user:$this->pass').'\r\n'; |
1266
|
|
|
} |
1267
|
|
|
|
1268
|
|
View Code Duplication |
if($this->proxyhost && $this->proxyport){ |
1269
|
|
|
$this-> outgoing_payload = "POST $this->url HTTP/1.0\r\n"; |
|
|
|
|
1270
|
|
|
} else { |
1271
|
|
|
$this->outgoing_payload = "POST $this->path HTTP/1.0\r\n"; |
1272
|
|
|
} |
1273
|
|
|
|
1274
|
|
|
$this->outgoing_payload .= |
1275
|
|
|
"User-Agent: $this->title v$this->version\r\n". |
1276
|
|
|
"Host: ".$this->host."\r\n". |
1277
|
|
|
$credentials. |
1278
|
|
|
"Content-Type: text/xml\r\nContent-Length: ".strlen($data)."\r\n". |
1279
|
|
|
"SOAPAction: \"$this->soapaction\""."\r\n\r\n". |
1280
|
|
|
$data; |
1281
|
|
|
|
1282
|
|
|
// send |
1283
|
|
|
if(!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { |
1284
|
|
|
$this->setError("couldn't write message data to socket"); |
1285
|
|
|
$this->debug("Write error"); |
1286
|
|
|
} |
1287
|
|
|
|
1288
|
|
|
// get response |
1289
|
|
|
$this->incoming_payload = ""; |
|
|
|
|
1290
|
|
|
while ($data = fread($fp, 32768)) { |
1291
|
|
|
$this->incoming_payload .= $data; |
1292
|
|
|
} |
1293
|
|
|
|
1294
|
|
|
// close filepointer |
1295
|
|
|
fclose($fp); |
1296
|
|
|
$data = $this->incoming_payload; |
1297
|
|
|
//print "data: <xmp>$data</xmp>"; |
1298
|
|
|
// separate content from HTTP headers |
1299
|
|
View Code Duplication |
if(preg_match("/([^<]*?)\r?\n\r?\n(<.*>)/s",$data,$result)) { |
1300
|
|
|
$this->debug("found proper separation of headers and document"); |
1301
|
|
|
$this->debug("getting rid of headers, stringlen: ".strlen($data)); |
1302
|
|
|
$clean_data = $result[2]; |
1303
|
|
|
$this->debug("cleaned data, stringlen: ".strlen($clean_data)); |
1304
|
|
|
/* |
1305
|
|
|
if(preg_match("/^(.*)\r?\n\r?\n/",$data)) { |
1306
|
|
|
$this->debug("found proper separation of headers and document"); |
1307
|
|
|
$this->debug("getting rid of headers, stringlen: ".strlen($data)); |
1308
|
|
|
$clean_data = preg_replace("/^[^<]*\r\n\r\n/","", $data); |
1309
|
|
|
$this->debug("cleaned data, stringlen: ".strlen($clean_data)); |
1310
|
|
|
*/ |
1311
|
|
|
} else { |
1312
|
|
|
$this->setError('no proper separation of headers and document.'); |
1313
|
|
|
return false; |
1314
|
|
|
} |
1315
|
|
|
if(strlen($clean_data) == 0){ |
1316
|
|
|
$this->debug("no data after headers!"); |
1317
|
|
|
$this->setError("no data present after HTTP headers."); |
1318
|
|
|
return false; |
1319
|
|
|
} |
1320
|
|
|
|
1321
|
|
|
return $clean_data; |
1322
|
|
|
} |
1323
|
|
|
|
1324
|
|
|
|
1325
|
|
|
/** |
1326
|
|
|
* send the SOAP message via HTTPS 1.0 using CURL |
1327
|
|
|
* |
1328
|
|
|
* @param string $msg message data |
|
|
|
|
1329
|
|
|
* @param integer $timeout set timeout in seconds |
1330
|
|
|
* @return string data |
1331
|
|
|
* @access public |
1332
|
|
|
*/ |
1333
|
|
|
function sendHTTPS($data, $timeout=0) { |
1334
|
|
|
flush(); |
1335
|
|
|
$this->debug('entered sendHTTPS() with data of length: '.strlen($data)); |
1336
|
|
|
// init CURL |
1337
|
|
|
$ch = curl_init(); |
1338
|
|
|
|
1339
|
|
|
// set proxy |
1340
|
|
View Code Duplication |
if($this->proxyhost && $this->proxyport){ |
1341
|
|
|
$host = $this->proxyhost; |
1342
|
|
|
$port = $this->proxyport; |
1343
|
|
|
} else { |
1344
|
|
|
$host = $this->host; |
1345
|
|
|
$port = $this->port; |
1346
|
|
|
} |
1347
|
|
|
// set url |
1348
|
|
|
$hostURL = ($port != '') ? "https://$host:$port" : "https://$host"; |
1349
|
|
|
// add path |
1350
|
|
|
$hostURL .= $this->path; |
1351
|
|
|
|
1352
|
|
|
curl_setopt($ch, CURLOPT_URL, $hostURL); |
1353
|
|
|
// set other options |
1354
|
|
|
curl_setopt($ch, CURLOPT_HEADER, 1); |
1355
|
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
1356
|
|
|
// set timeout |
1357
|
|
|
if($timeout != 0){ |
1358
|
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); |
1359
|
|
|
} |
1360
|
|
|
|
1361
|
|
|
$credentials = ''; |
1362
|
|
|
if($this->user != '') { |
1363
|
|
|
$credentials = 'Authorization: Basic '.base64_encode('$this->user:$this->pass').'\r\n'; |
1364
|
|
|
} |
1365
|
|
|
|
1366
|
|
View Code Duplication |
if($this->proxyhost && $this->proxyport){ |
1367
|
|
|
$this-> outgoing_payload = "POST $this->url HTTP/1.0\r\n"; |
1368
|
|
|
} else { |
1369
|
|
|
$this->outgoing_payload = "POST $this->path HTTP/1.0\r\n"; |
1370
|
|
|
} |
1371
|
|
|
|
1372
|
|
|
$this->outgoing_payload .= |
1373
|
|
|
"User-Agent: $this->title v$this->version\r\n". |
1374
|
|
|
"Host: ".$this->host."\r\n". |
1375
|
|
|
$credentials. |
1376
|
|
|
"Content-Type: text/xml\r\nContent-Length: ".strlen($data)."\r\n". |
1377
|
|
|
"SOAPAction: \"$this->soapaction\""."\r\n\r\n". |
1378
|
|
|
$data; |
1379
|
|
|
|
1380
|
|
|
// set payload |
1381
|
|
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); |
1382
|
|
|
|
1383
|
|
|
// send and receive |
1384
|
|
|
$this->incoming_payload = curl_exec($ch); |
1385
|
|
|
$data = $this->incoming_payload; |
1386
|
|
|
|
1387
|
|
|
$err = "cURL ERROR: ".curl_errno($ch).": ".curl_error($ch)."<br>"; |
1388
|
|
|
|
1389
|
|
|
if($err != ''){ |
1390
|
|
|
foreach(curl_getinfo($ch) as $k => $v){ |
1391
|
|
|
$err .= "$k: $v<br>"; |
1392
|
|
|
} |
1393
|
|
|
$this->setError($err); |
1394
|
|
|
curl_close($ch); |
1395
|
|
|
return false; |
1396
|
|
|
} |
1397
|
|
|
|
1398
|
|
|
curl_close($ch); |
1399
|
|
|
|
1400
|
|
|
// separate content from HTTP headers |
1401
|
|
View Code Duplication |
if(preg_match("/^(.*)\r?\n\r?\n/",$data)) { |
1402
|
|
|
$this->debug("found proper separation of headers and document"); |
1403
|
|
|
$this->debug("getting rid of headers, stringlen: ".strlen($data)); |
1404
|
|
|
$clean_data = preg_replace("/^[^<]*\r\n\r\n/","", $data); |
1405
|
|
|
$this->debug("cleaned data, stringlen: ".strlen($clean_data)); |
1406
|
|
|
} else { |
1407
|
|
|
$this->setError('no proper separation of headers and document.'); |
1408
|
|
|
return false; |
1409
|
|
|
} |
1410
|
|
|
if(strlen($clean_data) == 0){ |
1411
|
|
|
$this->debug("no data after headers!"); |
1412
|
|
|
$this->setError("no data present after HTTP headers."); |
1413
|
|
|
return false; |
1414
|
|
|
} |
1415
|
|
|
|
1416
|
|
|
return $clean_data; |
1417
|
|
|
} |
1418
|
|
|
} |
1419
|
|
|
|
1420
|
|
|
?> |
1421
|
|
|
<?php |
1422
|
|
|
/* |
1423
|
|
|
|
1424
|
|
|
NuSOAP - Web Services Toolkit for PHP |
1425
|
|
|
|
1426
|
|
|
Copyright (c) 2002 NuSphere Corporation |
1427
|
|
|
|
1428
|
|
|
This library is free software; you can redistribute it and/or |
1429
|
|
|
modify it under the terms of the GNU Lesser General Public |
1430
|
|
|
License as published by the Free Software Foundation; either |
1431
|
|
|
version 2.1 of the License, or (at your option) any later version. |
1432
|
|
|
|
1433
|
|
|
This library is distributed in the hope that it will be useful, |
1434
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1435
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1436
|
|
|
Lesser General Public License for more details. |
1437
|
|
|
|
1438
|
|
|
You should have received a copy of the GNU Lesser General Public |
1439
|
|
|
License along with this library; if not, write to the Free Software |
1440
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1441
|
|
|
|
1442
|
|
|
*/ |
1443
|
|
|
|
1444
|
|
|
/** |
1445
|
|
|
* |
1446
|
|
|
* soap_server allows the user to create a SOAP server |
1447
|
|
|
* that is capable of receiving messages and returning responses |
1448
|
|
|
* |
1449
|
|
|
* NOTE: WSDL functionality is experimental |
1450
|
|
|
* |
1451
|
|
|
* @author Dietrich Ayala <[email protected]> |
1452
|
|
|
* @version v 0.6 |
1453
|
|
|
* @access public |
1454
|
|
|
*/ |
1455
|
|
|
class soap_server extends nusoap_base { |
1456
|
|
|
|
1457
|
|
|
// assoc array of operations => opData |
1458
|
|
|
var $operations = array(); |
1459
|
|
|
var $responseHeaders = false; |
1460
|
|
|
var $headers = ""; |
1461
|
|
|
var $request = ""; |
1462
|
|
|
var $charset_encoding = "UTF-8"; |
1463
|
|
|
var $fault = false; |
1464
|
|
|
var $result = "successful"; |
1465
|
|
|
|
1466
|
|
|
/** |
1467
|
|
|
* constructor |
1468
|
|
|
* |
1469
|
|
|
* @param string $wsdl path or URL to a WSDL file |
1470
|
|
|
* @access public |
1471
|
|
|
*/ |
1472
|
|
|
function __construct($wsdl=false){ |
1473
|
|
|
|
1474
|
|
|
// turn on debugging? |
1475
|
|
|
global $debug; |
1476
|
|
|
if(isset($debug)){ |
1477
|
|
|
$this->debug_flag = true; |
|
|
|
|
1478
|
|
|
} |
1479
|
|
|
|
1480
|
|
|
$this->wsdl = false; |
|
|
|
|
1481
|
|
|
|
1482
|
|
|
// wsdl |
1483
|
|
|
if($wsdl){ |
|
|
|
|
1484
|
|
|
$this->wsdl = new wsdl($wsdl); |
1485
|
|
|
if($err = $this->wsdl->getError()){ |
1486
|
|
|
die("WSDL ERROR: $err"); |
1487
|
|
|
} |
1488
|
|
|
} |
1489
|
|
|
} |
1490
|
|
|
|
1491
|
|
|
/** |
1492
|
|
|
* processes request and returns response |
1493
|
|
|
* |
1494
|
|
|
* @param string $data usually is the value of $HTTP_RAW_POST_DATA |
1495
|
|
|
* @access public |
1496
|
|
|
*/ |
1497
|
|
|
function service($data){ |
1498
|
|
|
// print wsdl |
1499
|
|
|
if(preg_match('/^wsdl/',$GLOBALS['QUERY_STRING'])){ |
1500
|
|
|
header("Content-Type: text/xml\r\n"); |
1501
|
|
|
print $this->wsdl->serialize(); |
1502
|
|
|
// print web interface |
1503
|
|
|
} elseif($data == '' && $this->wsdl){ |
1504
|
|
|
print $this->webDescription(); |
1505
|
|
|
} else { |
1506
|
|
|
// $response is the serialized response message |
1507
|
|
|
$response = $this->parse_request($data); |
1508
|
|
|
$this->debug("server sending..."); |
1509
|
|
|
$payload = $response; |
1510
|
|
|
//$payload .= "<!--\n$this->debug_str\n-->"; |
1511
|
|
|
// print headers |
1512
|
|
|
if($this->fault){ |
1513
|
|
|
$header[] = "Status: 500 Internal Server Error\r\n"; |
|
|
|
|
1514
|
|
|
} else { |
1515
|
|
|
$header[] = "Status: 200 OK\r\n"; |
|
|
|
|
1516
|
|
|
} |
1517
|
|
|
$header[] = "Server: $this->title Server v$this->version\r\n"; |
1518
|
|
|
$header[] = "Connection: Close\r\n"; |
1519
|
|
|
$header[] = "Content-Type: text/xml; charset=$this->charset_encoding\r\n"; |
1520
|
|
|
$header[] = "Content-Length: ".strlen($payload)."\r\n\r\n"; |
1521
|
|
|
reset($header); |
1522
|
|
|
foreach($header as $hdr){ |
1523
|
|
|
header($hdr); |
1524
|
|
|
} |
1525
|
|
|
$this->response = join("\n",$header).$payload; |
|
|
|
|
1526
|
|
|
print $payload; |
1527
|
|
|
} |
1528
|
|
|
} |
1529
|
|
|
|
1530
|
|
|
|
1531
|
|
|
|
1532
|
|
|
|
1533
|
|
|
|
1534
|
|
|
/** |
1535
|
|
|
* parses request and returns |
1536
|
|
|
* |
1537
|
|
|
* @param string $data XML string |
1538
|
|
|
* @return object SOAPx4 soapmsg object |
1539
|
|
|
* @access private |
1540
|
|
|
*/ |
1541
|
|
|
function get_request($data="") { |
1542
|
|
|
$this->debug("entering parseRequest() on ".date("H:i Y-m-d")); |
1543
|
|
|
// get headers |
1544
|
|
View Code Duplication |
if(function_exists("getallheaders")){ |
1545
|
|
|
$this->headers = getallheaders(); |
1546
|
|
|
foreach($this->headers as $k=>$v){ |
1547
|
|
|
$dump .= "$k: $v\r\n"; |
|
|
|
|
1548
|
|
|
$this->debug("$k: $v"); |
1549
|
|
|
} |
1550
|
|
|
// get SOAPAction header |
1551
|
|
|
if($this->headers['SOAPAction']){ |
1552
|
|
|
$this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']); |
|
|
|
|
1553
|
|
|
} |
1554
|
|
|
// get the character encoding of the incoming request |
1555
|
|
|
if(strpos($headers_array['Content-Type'],"=")){ |
1556
|
|
|
$enc = str_replace("\"","",substr(strstr($headers_array["Content-Type"],"="),1)); |
|
|
|
|
1557
|
|
|
if(preg_match("/^(ISO-8859-1|US-ASCII|UTF-8)$/i",$enc)){ |
1558
|
|
|
$this->xml_encoding = $enc; |
|
|
|
|
1559
|
|
|
} else { |
1560
|
|
|
$this->xml_encoding = 'us-ascii'; |
1561
|
|
|
} |
1562
|
|
|
} |
1563
|
|
|
$this->debug("got encoding: $this->xml_encoding"); |
1564
|
|
|
} elseif(is_array($_SERVER)){ |
1565
|
|
|
$this->headers['User-Agent'] = $_SERVER['HTTP_USER_AGENT']; |
1566
|
|
|
$this->SOAPAction = $_SERVER['SOAPAction']; |
1567
|
|
|
} |
1568
|
|
|
$this->request = $dump."\r\n\r\n".$data; |
1569
|
|
|
// parse response, get soap parser obj |
1570
|
|
|
$parser = new soap_parser($data,$this->xml_encoding); |
1571
|
|
|
// if fault occurred during message parsing |
1572
|
|
|
if($err = $parser->getError()){ |
1573
|
|
|
// parser debug |
1574
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
|
|
|
|
1575
|
|
|
$this->result = "fault: error in msg parsing or eval: $err"; |
1576
|
|
|
$this->fault("Server","error in msg parsing or eval:\n".$err); |
1577
|
|
|
// return soapresp |
1578
|
|
|
return $this->fault->serialize(); |
|
|
|
|
1579
|
|
|
// else successfully parsed request into soapval object |
1580
|
|
|
} else { |
1581
|
|
|
// get/set methodname |
1582
|
|
|
$this->methodname = $parser->root_struct_name; |
|
|
|
|
1583
|
|
|
$this->debug("method name: $this->methodname"); |
1584
|
|
|
|
1585
|
|
|
// evaluate message, getting back parameters |
1586
|
|
|
$this->debug("calling parser->get_response()"); |
1587
|
|
|
$request_data = $parser->get_response(); |
1588
|
|
|
$this->debug('Parsed response dump: $request_data'); |
1589
|
|
|
|
1590
|
|
|
// parser debug |
1591
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
1592
|
|
|
return $request_data; |
1593
|
|
|
} |
1594
|
|
|
} |
1595
|
|
|
|
1596
|
|
|
|
1597
|
|
|
|
1598
|
|
|
|
1599
|
|
|
function send_returnvalue($method_response) { |
1600
|
|
|
// if we got nothing back. this might be ok (echoVoid) |
1601
|
|
View Code Duplication |
if(isset($method_response) && $method_response != "" || is_bool($method_response)) { |
1602
|
|
|
// if fault |
1603
|
|
|
if(get_class($method_response) == 'soap_fault'){ |
1604
|
|
|
debug('soapserver::send_returnvalue got a fault object from method', 'loader'); |
1605
|
|
|
$this->fault = $method_response; |
|
|
|
|
1606
|
|
|
$return_val = $method_response->serialize(); |
1607
|
|
|
// if return val is soapval object |
1608
|
|
|
} elseif(get_class($method_response) == 'soapval'){ |
1609
|
|
|
$this->debug('got a soapval object from method'); |
1610
|
|
|
$return_val = $method_response->serialize(); |
1611
|
|
|
// returned other |
1612
|
|
|
} else { |
1613
|
|
|
$this->debug("got a ".gettype($method_response)." from method"); |
1614
|
|
|
$this->debug("serializing return value"); |
1615
|
|
|
if($this->wsdl){ |
1616
|
|
|
if(sizeof($this->opData['output']['parts']) > 1){ |
|
|
|
|
1617
|
|
|
$opParams = $method_response; |
1618
|
|
|
} else { |
1619
|
|
|
$opParams = array($method_response); |
1620
|
|
|
} |
1621
|
|
|
$return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); |
1622
|
|
|
} else { |
1623
|
|
|
$return_val = $this->serialize_val($method_response); |
1624
|
|
|
} |
1625
|
|
|
} |
1626
|
|
|
} |
1627
|
|
|
if (!$this->fault) { |
1628
|
|
|
$this->debug("serializing response"); |
1629
|
|
|
$payload = "<".$this->methodname."Response>\n".$return_val."</".$this->methodname."Response>\n"; |
|
|
|
|
1630
|
|
|
$this->result = "successful"; |
1631
|
|
|
if($this->wsdl){ |
1632
|
|
|
//$this->debug("WSDL debug data:\n".$this->wsdl->debug_str); |
1633
|
|
|
} |
1634
|
|
|
// $response is the serialized response message |
1635
|
|
|
$response = $this->serializeEnvelope($payload,$this->responseHeaders); |
1636
|
|
|
} else { |
1637
|
|
|
$response = $return_val; |
1638
|
|
|
} |
1639
|
|
|
|
1640
|
|
|
$this->debug("server sending..."); |
1641
|
|
|
$payload = $response; |
1642
|
|
|
//$payload .= "<!--\n$this->debug_str\n-->"; |
1643
|
|
|
// print headers |
1644
|
|
|
if($this->fault){ |
1645
|
|
|
$header[] = "Status: 500 Internal Server Error\r\n"; |
|
|
|
|
1646
|
|
|
} else { |
1647
|
|
|
$header[] = "Status: 200 OK\r\n"; |
|
|
|
|
1648
|
|
|
} |
1649
|
|
|
$header[] = "Server: $this->title Server v$this->version\r\n"; |
1650
|
|
|
$header[] = "Connection: Close\r\n"; |
1651
|
|
|
$header[] = "Content-Type: text/xml; charset=$this->charset_encoding\r\n"; |
1652
|
|
|
$header[] = "Content-Length: ".strlen($payload)."\r\n\r\n"; |
1653
|
|
|
reset($header); |
1654
|
|
|
foreach($header as $hdr){ |
1655
|
|
|
header($hdr); |
1656
|
|
|
} |
1657
|
|
|
$this->response = join("\n",$header).$payload; |
|
|
|
|
1658
|
|
|
debug("soapserver::sending ($payload)", "loader"); |
1659
|
|
|
print $payload; |
1660
|
|
|
} |
1661
|
|
|
|
1662
|
|
|
|
1663
|
|
|
/** |
1664
|
|
|
* parses request and posts response |
1665
|
|
|
* |
1666
|
|
|
* @param string $data XML string |
1667
|
|
|
* @return object SOAPx4 soapmsg object |
1668
|
|
|
* @access private |
1669
|
|
|
*/ |
1670
|
|
|
function parse_request($data="") { |
1671
|
|
|
$this->debug("entering parseRequest() on ".date("H:i Y-m-d")); |
1672
|
|
|
// get headers |
1673
|
|
View Code Duplication |
if(function_exists("getallheaders")){ |
1674
|
|
|
$this->headers = getallheaders(); |
1675
|
|
|
foreach($this->headers as $k=>$v){ |
1676
|
|
|
$dump .= "$k: $v\r\n"; |
|
|
|
|
1677
|
|
|
$this->debug("$k: $v"); |
1678
|
|
|
} |
1679
|
|
|
// get SOAPAction header |
1680
|
|
|
if($this->headers['SOAPAction']){ |
1681
|
|
|
$this->SOAPAction = str_replace('"','',$this->headers['SOAPAction']); |
1682
|
|
|
} |
1683
|
|
|
// get the character encoding of the incoming request |
1684
|
|
|
if(strpos($headers_array['Content-Type'],"=")){ |
1685
|
|
|
$enc = str_replace("\"","",substr(strstr($headers_array["Content-Type"],"="),1)); |
|
|
|
|
1686
|
|
|
if(preg_match("/^(ISO-8859-1|US-ASCII|UTF-8)$/i",$enc)){ |
1687
|
|
|
$this->xml_encoding = $enc; |
1688
|
|
|
} else { |
1689
|
|
|
$this->xml_encoding = 'us-ascii'; |
1690
|
|
|
} |
1691
|
|
|
} |
1692
|
|
|
$this->debug("got encoding: $this->xml_encoding"); |
1693
|
|
|
} elseif(is_array($_SERVER)){ |
1694
|
|
|
$this->headers['User-Agent'] = $_SERVER['HTTP_USER_AGENT']; |
1695
|
|
|
$this->SOAPAction = $_SERVER['SOAPAction']; |
1696
|
|
|
} |
1697
|
|
|
$this->request = $dump."\r\n\r\n".$data; |
1698
|
|
|
// parse response, get soap parser obj |
1699
|
|
|
$parser = new soap_parser($data,$this->xml_encoding); |
1700
|
|
|
// if fault occurred during message parsing |
1701
|
|
|
if($err = $parser->getError()){ |
1702
|
|
|
// parser debug |
1703
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
|
|
|
|
1704
|
|
|
$this->result = "fault: error in msg parsing or eval: $err"; |
1705
|
|
|
$this->fault("Server","error in msg parsing or eval:\n".$err); |
1706
|
|
|
// return soapresp |
1707
|
|
|
return $this->fault->serialize(); |
|
|
|
|
1708
|
|
|
// else successfully parsed request into soapval object |
1709
|
|
|
} else { |
1710
|
|
|
// get/set methodname |
1711
|
|
|
$this->methodname = $parser->root_struct_name; |
|
|
|
|
1712
|
|
|
$this->debug("method name: $this->methodname"); |
1713
|
|
|
// does method exist? |
1714
|
|
|
if(!function_exists($this->methodname)){ |
1715
|
|
|
// "method not found" fault here |
1716
|
|
|
$this->debug("method '$this->methodname' not found!"); |
1717
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
1718
|
|
|
$this->result = "fault: method not found"; |
1719
|
|
|
$this->fault("Server","method '$this->methodname' not defined in service '$this->service'"); |
|
|
|
|
1720
|
|
|
return $this->fault->serialize(); |
|
|
|
|
1721
|
|
|
} |
1722
|
|
|
if($this->wsdl){ |
1723
|
|
|
if(!$this->opData = $this->wsdl->getOperationData($this->methodname)){ |
1724
|
|
|
$this->fault('Server',"Operation '$this->methodname' is not defined in the WSDL for this service"); |
1725
|
|
|
return $this->fault->serialize(); |
|
|
|
|
1726
|
|
|
} |
1727
|
|
|
} |
1728
|
|
|
$this->debug("method '$this->methodname' exists"); |
1729
|
|
|
// evaluate message, getting back parameters |
1730
|
|
|
$this->debug("calling parser->get_response()"); |
1731
|
|
|
$request_data = $parser->get_response(); |
1732
|
|
|
$this->debug('Parsed response dump: $request_data'); |
1733
|
|
|
// parser debug |
1734
|
|
|
$this->debug("parser debug: \n".$parser->debug_str); |
1735
|
|
|
// verify that request parameters match the method's signature |
1736
|
|
|
if($this->verify_method($this->methodname,$request_data)){ |
1737
|
|
|
// if there are parameters to pass |
1738
|
|
|
if($request_data){ |
1739
|
|
|
$this->debug("calling '$this->methodname' with params"); |
1740
|
|
|
if (! function_exists('call_user_func_array')) { |
1741
|
|
|
$this->debug("calling method using eval()"); |
1742
|
|
|
$funcCall = $this->methodname."("; |
1743
|
|
|
foreach($request_data as $param) { |
1744
|
|
|
$funcCall .= "\"$param\","; |
1745
|
|
|
} |
1746
|
|
|
$funcCall = substr($funcCall, 0, -1).')'; |
1747
|
|
|
$this->debug("function call:<br>$funcCall"); |
1748
|
|
|
eval("\$method_response = $funcCall;"); |
1749
|
|
|
} else { |
1750
|
|
|
$this->debug("calling method using call_user_func_array()"); |
1751
|
|
|
$method_response = call_user_func_array("$this->methodname",$request_data); |
1752
|
|
|
} |
1753
|
|
|
} else { |
1754
|
|
|
// call method w/ no parameters |
1755
|
|
|
$this->debug("calling $this->methodname w/ no params"); |
1756
|
|
|
//$method_response = call_user_func($this->methodname); |
1757
|
|
|
$m = $this->methodname; |
1758
|
|
|
$method_response = $m(); |
1759
|
|
|
} |
1760
|
|
|
$this->debug("done calling method: $this->methodname, received $method_response of type".gettype($method_response)); |
|
|
|
|
1761
|
|
|
// if we got nothing back. this might be ok (echoVoid) |
1762
|
|
View Code Duplication |
if(isset($method_response) && $method_response != "" || is_bool($method_response)) { |
1763
|
|
|
// if fault |
1764
|
|
|
if(get_class($method_response) == 'soap_fault'){ |
1765
|
|
|
$this->debug('got a fault object from method'); |
1766
|
|
|
$this->fault = $method_response; |
|
|
|
|
1767
|
|
|
return $method_response->serialize(); |
1768
|
|
|
// if return val is soapval object |
1769
|
|
|
} elseif(get_class($method_response) == 'soapval'){ |
1770
|
|
|
$this->debug('got a soapval object from method'); |
1771
|
|
|
$return_val = $method_response->serialize(); |
1772
|
|
|
// returned other |
1773
|
|
|
} else { |
1774
|
|
|
$this->debug("got a ".gettype($method_response)." from method"); |
1775
|
|
|
$this->debug("serializing return value"); |
1776
|
|
|
if($this->wsdl){ |
1777
|
|
|
if(sizeof($this->opData['output']['parts']) > 1){ |
1778
|
|
|
$opParams = $method_response; |
1779
|
|
|
} else { |
1780
|
|
|
$opParams = array($method_response); |
1781
|
|
|
} |
1782
|
|
|
$return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); |
1783
|
|
|
} else { |
1784
|
|
|
$return_val = $this->serialize_val($method_response); |
1785
|
|
|
} |
1786
|
|
|
} |
1787
|
|
|
} |
1788
|
|
|
$this->debug("serializing response"); |
1789
|
|
|
$payload = "<".$this->methodname."Response>\n".$return_val."</".$this->methodname."Response>\n"; |
|
|
|
|
1790
|
|
|
$this->result = "successful"; |
1791
|
|
|
if($this->wsdl){ |
1792
|
|
|
//$this->debug("WSDL debug data:\n".$this->wsdl->debug_str); |
1793
|
|
|
} |
1794
|
|
|
return $this->serializeEnvelope($payload,$this->responseHeaders); |
1795
|
|
|
} else { |
1796
|
|
|
// debug |
1797
|
|
|
$this->debug("ERROR: request not verified against method signature"); |
1798
|
|
|
$this->result = "fault: request failed validation against method signature"; |
1799
|
|
|
// return fault |
1800
|
|
|
$this->fault("Server","Sorry, operation '$this->methodname' not defined in service."); |
1801
|
|
|
return $this->fault->serialize(); |
|
|
|
|
1802
|
|
|
} |
1803
|
|
|
} |
1804
|
|
|
} |
1805
|
|
|
|
1806
|
|
|
/** |
1807
|
|
|
* takes the soapval object that was created by parsing the request |
1808
|
|
|
* and compares to the method's signature, if available. |
1809
|
|
|
* |
1810
|
|
|
* @param object SOAPx4 soapval object |
1811
|
|
|
* @return boolean |
1812
|
|
|
* @access private |
1813
|
|
|
*/ |
1814
|
|
|
function verify_method($operation,$request){ |
|
|
|
|
1815
|
|
|
if(isset($this->operations[$operation])){ |
1816
|
|
|
return true; |
1817
|
|
|
} |
1818
|
|
|
return false; |
1819
|
|
|
} |
1820
|
|
|
|
1821
|
|
|
/** |
1822
|
|
|
* add a method to the dispatch map |
1823
|
|
|
* |
1824
|
|
|
* @param string $methodname |
1825
|
|
|
* @param string $in array of input values |
1826
|
|
|
* @param string $out array of output values |
1827
|
|
|
* @access public |
1828
|
|
|
*/ |
1829
|
|
|
function add_to_map($methodname,$in,$out){ |
1830
|
|
|
$this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); |
1831
|
|
|
} |
1832
|
|
|
|
1833
|
|
|
/** |
1834
|
|
|
* register a service with the server |
1835
|
|
|
* |
1836
|
|
|
* @param string $methodname |
|
|
|
|
1837
|
|
|
* @param string $in array of input values |
1838
|
|
|
* @param string $out array of output values |
1839
|
|
|
* @param string $namespace |
1840
|
|
|
* @param string $soapaction |
1841
|
|
|
* @param string $style (rpc|literal) |
1842
|
|
|
* @access public |
1843
|
|
|
*/ |
1844
|
|
|
function register($name,$in=false,$out=false,$namespace=false,$soapaction=false,$style=false){ |
|
|
|
|
1845
|
|
|
$this->operations[$name] = array( |
1846
|
|
|
'name' => $name, |
1847
|
|
|
'in' => $in, |
1848
|
|
|
'out' => $out, |
1849
|
|
|
'namespace' => $namespage, |
|
|
|
|
1850
|
|
|
'soapaction' => $soapaction, |
1851
|
|
|
'style' => $style); |
1852
|
|
|
return true; |
1853
|
|
|
} |
1854
|
|
|
|
1855
|
|
|
/** |
1856
|
|
|
* create a fault. this also acts as a flag to the server that a fault has occured. |
1857
|
|
|
* |
1858
|
|
|
* @param string faultcode |
1859
|
|
|
* @param string faultactor |
1860
|
|
|
* @param string faultstring |
1861
|
|
|
* @param string faultdetail |
1862
|
|
|
* @access public |
1863
|
|
|
*/ |
1864
|
|
|
function fault($faultcode,$faultactor,$faultstring='',$faultdetail=''){ |
1865
|
|
|
$this->fault = new soap_fault($faultcode,$faultactor,$faultstring,$faultdetail); |
|
|
|
|
1866
|
|
|
} |
1867
|
|
|
|
1868
|
|
|
/** |
1869
|
|
|
* prints html description of services |
1870
|
|
|
* |
1871
|
|
|
* @access private |
1872
|
|
|
*/ |
1873
|
|
|
function webDescription(){ |
1874
|
|
|
$b .= " |
|
|
|
|
1875
|
|
|
<html><head><title>NuSOAP: ".$this->wsdl->serviceName."</title> |
1876
|
|
|
<style type=\"text/css\"> |
1877
|
|
|
body { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; } |
1878
|
|
|
p { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; } |
1879
|
|
|
pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;} |
1880
|
|
|
ul { margin-top: 10px; margin-left: 20px; } |
1881
|
|
|
li { list-style-type: none; margin-top: 10px; color: #000000; } |
1882
|
|
|
.content{ |
1883
|
|
|
margin-left: 0px; padding-bottom: 2em; } |
1884
|
|
|
.nav { |
1885
|
|
|
padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em; |
1886
|
|
|
margin-top: 10px; margin-left: 0px; color: #000000; |
1887
|
|
|
background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; } |
1888
|
|
|
.title { |
1889
|
|
|
font-family: arial; font-size: 26px; color: #ffffff; |
1890
|
|
|
background-color: #999999; width: 105%; margin-left: 0px; |
1891
|
|
|
padding-top: 10px; padding-bottom: 10px; padding-left: 15px;} |
1892
|
|
|
.hidden { |
1893
|
|
|
position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px; |
1894
|
|
|
font-family: arial; overflow: hidden; width: 600; |
1895
|
|
|
padding: 20px; font-size: 10px; background-color: #999999; |
1896
|
|
|
layer-background-color:#FFFFFF; } |
1897
|
|
|
a,a:active { color: charcoal; font-weight: bold; } |
1898
|
|
|
a:visited { color: #666666; font-weight: bold; } |
1899
|
|
|
a:hover { color: cc3300; font-weight: bold; } |
1900
|
|
|
</style> |
1901
|
|
|
<script language=\"JavaScript\" type=\"text/javascript\"> |
1902
|
|
|
<!-- |
1903
|
|
|
// POP-UP CAPTIONS... |
1904
|
|
|
function lib_bwcheck(){ //Browsercheck (needed) |
1905
|
|
|
this.ver=navigator.appVersion |
1906
|
|
|
this.agent=navigator.userAgent |
1907
|
|
|
this.dom=document.getElementById?1:0 |
1908
|
|
|
this.opera5=this.agent.indexOf(\"Opera 5\")>-1 |
1909
|
|
|
this.ie5=(this.ver.indexOf(\"MSIE 5\")>-1 && this.dom && !this.opera5)?1:0; |
1910
|
|
|
this.ie6=(this.ver.indexOf(\"MSIE 6\")>-1 && this.dom && !this.opera5)?1:0; |
1911
|
|
|
this.ie4=(document.all && !this.dom && !this.opera5)?1:0; |
1912
|
|
|
this.ie=this.ie4||this.ie5||this.ie6 |
1913
|
|
|
this.mac=this.agent.indexOf(\"Mac\")>-1 |
1914
|
|
|
this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0; |
1915
|
|
|
this.ns4=(document.layers && !this.dom)?1:0; |
1916
|
|
|
this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5) |
1917
|
|
|
return this |
1918
|
|
|
} |
1919
|
|
|
var bw = new lib_bwcheck() |
1920
|
|
|
//Makes crossbrowser object. |
1921
|
|
|
function makeObj(obj){ |
1922
|
|
|
this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0; |
1923
|
|
|
if(!this.evnt) return false |
1924
|
|
|
this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0; |
1925
|
|
|
this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0; |
1926
|
|
|
this.writeIt=b_writeIt; |
1927
|
|
|
return this |
1928
|
|
|
} |
1929
|
|
|
// A unit of measure that will be added when setting the position of a layer. |
1930
|
|
|
//var px = bw.ns4||window.opera?\"\":\"px\"; |
1931
|
|
|
function b_writeIt(text){ |
1932
|
|
|
if (bw.ns4){this.wref.write(text);this.wref.close()} |
1933
|
|
|
else this.wref.innerHTML = text |
1934
|
|
|
} |
1935
|
|
|
//Shows the messages |
1936
|
|
|
var oDesc; |
1937
|
|
|
function popup(divid){ |
1938
|
|
|
if(oDesc = new makeObj(divid)){ |
1939
|
|
|
oDesc.css.visibility = \"visible\" |
1940
|
|
|
} |
1941
|
|
|
} |
1942
|
|
|
function popout(){ // Hides message |
1943
|
|
|
if(oDesc) oDesc.css.visibility = \"hidden\" |
1944
|
|
|
} |
1945
|
|
|
//--> |
1946
|
|
|
</script> |
1947
|
|
|
</head> |
1948
|
|
|
<body> |
1949
|
|
|
<div class='content'> |
1950
|
|
|
<br><br> |
1951
|
|
|
<div class='title'>".$this->wsdl->serviceName."</div> |
1952
|
|
|
<div class='nav'> |
1953
|
|
|
<p>View the <a href='".$_SERVER['PHP_SELF']."?wsdl'>WSDL</a> for the service. |
1954
|
|
|
Click on an operation name to view it's details.</p> |
1955
|
|
|
<ul> |
1956
|
|
|
"; |
1957
|
|
|
foreach($this->wsdl->getOperations() as $op => $data){ |
1958
|
|
|
$b .= "<li><a href='#' onclick=\"popup('$op')\">$op</a></li>"; |
1959
|
|
|
// create hidden div |
1960
|
|
|
$b .= "<div id='$op' class='hidden'> |
1961
|
|
|
<a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>"; |
1962
|
|
|
foreach($data as $donnie => $marie){ |
1963
|
|
|
if($donnie == 'input' || $donnie == 'output'){ |
1964
|
|
|
$b .= "<font color='white'>".ucfirst($donnie).":</font><br>"; |
1965
|
|
|
foreach($marie as $captain => $tenille){ |
1966
|
|
|
if($captain == 'parts'){ |
1967
|
|
|
$b .= " $captain:<br>"; |
1968
|
|
|
foreach($tenille as $joanie => $chachi){ |
1969
|
|
|
$b .= " $joanie: $chachi<br>"; |
1970
|
|
|
} |
1971
|
|
|
} else { |
1972
|
|
|
$b .= " $captain: $tenille<br>"; |
1973
|
|
|
} |
1974
|
|
|
} |
1975
|
|
|
} else { |
1976
|
|
|
$b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>"; |
1977
|
|
|
} |
1978
|
|
|
} |
1979
|
|
|
/*$b .= "<pre>".$this->formatDump( |
1980
|
|
|
$this->wsdl->serializeEnvelope( |
1981
|
|
|
$this->wsdl->serializeRPCParameters($op,array())))."</pre>"; |
1982
|
|
|
$b .= "</div>";*/ |
1983
|
|
|
} |
1984
|
|
|
$b .= " |
1985
|
|
|
<ul> |
1986
|
|
|
</div> |
1987
|
|
|
</div> |
1988
|
|
|
</body></html>"; |
1989
|
|
|
return $b; |
1990
|
|
|
} |
1991
|
|
|
|
1992
|
|
|
/** |
1993
|
|
|
* sets up wsdl object |
1994
|
|
|
* this acts as a flag to enable internal WSDL generation |
1995
|
|
|
* NOTE: NOT FUNCTIONAL |
1996
|
|
|
* |
1997
|
|
|
* @param string $serviceName, name of the service |
|
|
|
|
1998
|
|
|
* @param string $namespace, tns namespace |
|
|
|
|
1999
|
|
|
*/ |
2000
|
|
|
function configureWSDL($serviceName,$namespace){ |
2001
|
|
|
$this->wsdl = new wsdl; |
2002
|
|
|
$this->wsdl->serviceName = $serviceName; |
|
|
|
|
2003
|
|
|
$this->wsdl->namespaces['tns'] = $namespace; |
2004
|
|
|
$this->wsdl->namespaces['soap'] = "http://schemas.xmlsoap.org/wsdl/soap/"; |
2005
|
|
|
$this->wsdl->namespaces['wsdl'] = "http://schemas.xmlsoap.org/wsdl/"; |
2006
|
|
|
} |
2007
|
|
|
} |
2008
|
|
|
|
2009
|
|
|
?> |
2010
|
|
|
<?php |
2011
|
|
|
/* |
2012
|
|
|
|
2013
|
|
|
NuSOAP - Web Services Toolkit for PHP |
2014
|
|
|
|
2015
|
|
|
Copyright (c) 2002 NuSphere Corporation |
2016
|
|
|
|
2017
|
|
|
This library is free software; you can redistribute it and/or |
2018
|
|
|
modify it under the terms of the GNU Lesser General Public |
2019
|
|
|
License as published by the Free Software Foundation; either |
2020
|
|
|
version 2.1 of the License, or (at your option) any later version. |
2021
|
|
|
|
2022
|
|
|
This library is distributed in the hope that it will be useful, |
2023
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
2024
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2025
|
|
|
Lesser General Public License for more details. |
2026
|
|
|
|
2027
|
|
|
You should have received a copy of the GNU Lesser General Public |
2028
|
|
|
License along with this library; if not, write to the Free Software |
2029
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2030
|
|
|
|
2031
|
|
|
*/ |
2032
|
|
|
|
2033
|
|
|
/** |
2034
|
|
|
* parses a WSDL file, allows access to it's data, other utility methods |
2035
|
|
|
* |
2036
|
|
|
* @author Dietrich Ayala <[email protected]> |
2037
|
|
|
* @access public |
2038
|
|
|
*/ |
2039
|
|
|
class wsdl extends XMLSchema { |
2040
|
|
|
|
2041
|
|
|
/** |
2042
|
|
|
* constructor |
2043
|
|
|
* |
2044
|
|
|
* @param string $wsdl WSDL document URL |
2045
|
|
|
* @access public |
2046
|
|
|
*/ |
2047
|
|
|
function __construct($wsdl=""){ |
2048
|
|
|
$this->wsdl = $wsdl; |
|
|
|
|
2049
|
|
|
// define internal arrays of bindings, ports, operations, messages, etc. |
2050
|
|
|
//$this->namespaces = array(); |
2051
|
|
|
$this->complexTypes = array(); |
|
|
|
|
2052
|
|
|
$this->messages = array(); |
|
|
|
|
2053
|
|
|
$this->currentMessage; |
|
|
|
|
2054
|
|
|
$this->currentOperation; |
|
|
|
|
2055
|
|
|
$this->portTypes = array(); |
|
|
|
|
2056
|
|
|
$this->currentPortType; |
|
|
|
|
2057
|
|
|
$this->bindings = array(); |
|
|
|
|
2058
|
|
|
$this->currentBinding; |
|
|
|
|
2059
|
|
|
$this->ports = array(); |
|
|
|
|
2060
|
|
|
$this->currentPort; |
|
|
|
|
2061
|
|
|
$this->opData = array(); |
|
|
|
|
2062
|
|
|
$this->status = ""; |
|
|
|
|
2063
|
|
|
$this->documentation = false; |
|
|
|
|
2064
|
|
|
// array of wsdl docs to import |
2065
|
|
|
$this->import = array(); |
|
|
|
|
2066
|
|
|
// parser vars |
2067
|
|
|
$this->parser; |
|
|
|
|
2068
|
|
|
$this->position; |
|
|
|
|
2069
|
|
|
$this->depth; |
|
|
|
|
2070
|
|
|
$this->depth_array = array(); |
|
|
|
|
2071
|
|
|
|
2072
|
|
|
// parse wsdl file |
2073
|
|
|
if($wsdl != ""){ |
2074
|
|
|
$this->debug("initial wsdl file: $wsdl"); |
2075
|
|
|
$this->parseWSDL($wsdl); |
2076
|
|
|
} |
2077
|
|
|
|
2078
|
|
|
// imports |
2079
|
|
|
if(sizeof($this->import) > 0){ |
2080
|
|
|
foreach($this->import as $ns => $url){ |
2081
|
|
|
$this->debug("importing wsdl from $url"); |
2082
|
|
|
$this->parseWSDL($url); |
2083
|
|
|
} |
2084
|
|
|
} |
2085
|
|
|
|
2086
|
|
|
} |
2087
|
|
|
|
2088
|
|
|
/** |
2089
|
|
|
* parses the wsdl document |
2090
|
|
|
* |
2091
|
|
|
* @param string $wsdl path or URL |
2092
|
|
|
* @access private |
2093
|
|
|
*/ |
2094
|
|
|
function parseWSDL($wsdl=""){ |
2095
|
|
|
// parse wsdl file |
2096
|
|
|
if($wsdl != ""){ |
2097
|
|
|
$this->debug("getting $wsdl"); |
2098
|
|
|
if ($fp = @fopen($wsdl,"r")) { |
2099
|
|
|
while($data = fread($fp, 32768)) { |
2100
|
|
|
$wsdl_string .= $data; |
|
|
|
|
2101
|
|
|
} |
2102
|
|
|
fclose($fp); |
2103
|
|
|
} else { |
2104
|
|
|
$this->setError("bad path to WSDL file."); |
2105
|
|
|
return false; |
2106
|
|
|
} |
2107
|
|
|
// Create an XML parser. |
2108
|
|
|
$this->parser = xml_parser_create(); |
2109
|
|
|
// Set the options for parsing the XML data. |
2110
|
|
|
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); |
2111
|
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
2112
|
|
|
// Set the object for the parser. |
2113
|
|
|
xml_set_object($this->parser, $this); |
2114
|
|
|
// Set the element handlers for the parser. |
2115
|
|
|
xml_set_element_handler($this->parser, "start_element","end_element"); |
2116
|
|
|
xml_set_character_data_handler($this->parser,"character_data"); |
2117
|
|
|
//xml_set_default_handler($this->parser, "default_handler"); |
2118
|
|
|
|
2119
|
|
|
// Parse the XML file. |
2120
|
|
View Code Duplication |
if(!xml_parse($this->parser,$wsdl_string,true)){ |
2121
|
|
|
// Display an error message. |
2122
|
|
|
$errstr = sprintf("XML error on line %d: %s", |
2123
|
|
|
xml_get_current_line_number($this->parser), |
2124
|
|
|
xml_error_string(xml_get_error_code($this->parser)) |
2125
|
|
|
); |
2126
|
|
|
$this->debug("XML parse error: $errstr"); |
2127
|
|
|
$this->setError("Parser error: $errstr"); |
2128
|
|
|
return false; |
2129
|
|
|
} |
2130
|
|
|
xml_parser_free($this->parser); |
2131
|
|
|
} else{ |
2132
|
|
|
$this->debug("no wsdl passed to parseWSDL()!!"); |
2133
|
|
|
$this->setError("no wsdl passed to parseWSDL()!!"); |
2134
|
|
|
return false; |
2135
|
|
|
} |
2136
|
|
|
|
2137
|
|
|
// add new data to operation data |
2138
|
|
|
foreach($this->bindings as $binding => $bindingData){ |
2139
|
|
|
if(is_array($bindingData['operations'])){ |
2140
|
|
|
foreach($bindingData['operations'] as $operation => $data){ |
2141
|
|
|
$this->debug("post-parse data gathering for $operation"); |
2142
|
|
|
$this->bindings[$binding]['operations'][$operation]['input'] = array_merge($this->bindings[$binding]['operations'][$operation]['input'],$this->portTypes[ $bindingData['portType'] ][$operation]['input']); |
2143
|
|
|
$this->bindings[$binding]['operations'][$operation]['output'] = array_merge($this->bindings[$binding]['operations'][$operation]['output'],$this->portTypes[ $bindingData['portType'] ][$operation]['output']); |
2144
|
|
|
$this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; |
2145
|
|
|
$this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; |
2146
|
|
|
if($this->bindings[$binding]['operations'][$operation]['style'] == ''){ |
2147
|
|
|
$this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; |
2148
|
|
|
} |
2149
|
|
|
$this->bindings[$binding]['operations'][$operation]['transport'] = $bindingData['transport']; |
2150
|
|
|
$this->bindings[$binding]['operations'][$operation]['documentation'] = $this->portTypes[ $bindingData['portType'] ][$operation]['documentation']; |
2151
|
|
|
$this->bindings[$binding]['operations'][$operation]['endpoint'] = $bindingData['endpoint']; |
2152
|
|
|
} |
2153
|
|
|
} |
2154
|
|
|
} |
2155
|
|
|
return true; |
2156
|
|
|
} |
2157
|
|
|
|
2158
|
|
|
/** |
2159
|
|
|
* start-element handler |
2160
|
|
|
* |
2161
|
|
|
* @param string $parser XML parser object |
2162
|
|
|
* @param string $name element name |
2163
|
|
|
* @param string $attrs associative array of attributes |
2164
|
|
|
* @access private |
2165
|
|
|
*/ |
2166
|
|
|
function start_element($parser, $name, $attrs) { |
2167
|
|
|
|
2168
|
|
|
if($this->status == "schema" || preg_match("/schema$/",$name)){ |
2169
|
|
|
//$this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); |
2170
|
|
|
$this->status = "schema"; |
2171
|
|
|
$this->schemaStartElement($parser,$name,$attrs); |
2172
|
|
|
} else { |
2173
|
|
|
// position in the total number of elements, starting from 0 |
2174
|
|
|
$pos = $this->position++; |
2175
|
|
|
$depth = $this->depth++; |
2176
|
|
|
// set self as current value for this depth |
2177
|
|
|
$this->depth_array[$depth] = $pos; |
2178
|
|
|
|
2179
|
|
|
// get element prefix |
2180
|
|
View Code Duplication |
if(preg_match("/:/",$name)){ |
2181
|
|
|
// get ns prefix |
2182
|
|
|
$prefix = substr($name,0,strpos($name,":")); |
2183
|
|
|
// get unqualified name |
2184
|
|
|
$name = substr(strstr($name,":"),1); |
2185
|
|
|
} |
2186
|
|
|
//$this->debug("name: $name, prefix: $prefix"); |
2187
|
|
|
|
2188
|
|
|
// loop through atts, logging ns declarations |
2189
|
|
View Code Duplication |
foreach($attrs as $key => $value){ |
|
|
|
|
2190
|
|
|
// if ns declarations, add to class level array of valid namespaces |
2191
|
|
|
if(preg_match("/^xmlns/",$key)){ |
2192
|
|
|
if($ns_prefix = substr(strrchr($key,":"),1)){ |
2193
|
|
|
$this->namespaces[$ns_prefix] = $value; |
2194
|
|
|
} else { |
2195
|
|
|
$this->namespaces['ns'.(count($this->namespaces)+1)] = $value; |
2196
|
|
|
} |
2197
|
|
|
if($value == 'http://www.w3.org/2001/XMLSchema'){ |
2198
|
|
|
$this->XMLSchemaVersion = $value; |
|
|
|
|
2199
|
|
|
$this->namespaces['xsi'] = $value.'-instance'; |
2200
|
|
|
} elseif($value == 'http://www.w3.org/1999/XMLSchema'){ |
2201
|
|
|
$this->XMLSchemaVersion = $value; |
|
|
|
|
2202
|
|
|
$this->namespaces['xsi'] = $value.'-instance'; |
2203
|
|
|
} |
2204
|
|
|
} |
2205
|
|
|
} |
2206
|
|
|
|
2207
|
|
|
// find status, register data |
2208
|
|
|
switch($this->status){ |
2209
|
|
|
case 'message': |
2210
|
|
|
if($name == 'part'){ |
2211
|
|
View Code Duplication |
if($attrs['type']){ |
2212
|
|
|
//print "msg ".$this->currentMessage.": found part $attrs[name]: ".implode(',',$attrs)."<br>"; |
2213
|
|
|
$this->messages[$this->currentMessage][$attrs['name']] = $this->expandQname($attrs['type']); |
2214
|
|
|
//print "i've stored it as: ".$this->messages[$this->currentMessage][$attrs['name']]."<br>"; |
2215
|
|
|
} |
2216
|
|
View Code Duplication |
if($attrs['element']){ |
2217
|
|
|
$this->messages[$this->currentMessage][$attrs['name']] = $this->expandQname($attrs['element']); |
2218
|
|
|
} |
2219
|
|
|
} |
2220
|
|
|
break; |
2221
|
|
|
case 'portType': |
2222
|
|
|
switch($name){ |
2223
|
|
|
case 'operation': |
2224
|
|
|
$this->currentPortOperation = $attrs["name"]; |
|
|
|
|
2225
|
|
|
$this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); |
2226
|
|
|
$this->portTypes[$this->currentPortType][$attrs["name"]]["parameterOrder"] = $attrs["parameterOrder"]; |
2227
|
|
|
break; |
2228
|
|
|
case 'documentation': |
2229
|
|
|
$this->documentation = true; |
2230
|
|
|
break; |
2231
|
|
|
// merge input/output data |
2232
|
|
|
default: |
2233
|
|
|
$this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $this->getLocalPart($attrs['message']); |
2234
|
|
|
break; |
2235
|
|
|
} |
2236
|
|
|
break; |
2237
|
|
|
case 'binding': |
2238
|
|
|
switch($name){ |
2239
|
|
|
case 'binding': |
2240
|
|
|
// get ns prefix |
2241
|
|
|
if(isset($attrs['style'])){ |
2242
|
|
|
$this->bindings[$this->currentBinding]['prefix'] = $prefix; |
|
|
|
|
2243
|
|
|
} |
2244
|
|
|
$this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding],$attrs); |
2245
|
|
|
break; |
2246
|
|
|
case 'header': |
2247
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; |
|
|
|
|
2248
|
|
|
break; |
2249
|
|
|
case 'operation': |
2250
|
|
|
if($attrs['soapAction'] || $attrs['style']){ |
2251
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; |
2252
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; |
2253
|
|
|
} elseif($attrs['name']) { |
2254
|
|
|
$this->currentOperation = $attrs['name']; |
2255
|
|
|
$this->debug("current binding operation: $this->currentOperation"); |
2256
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; |
2257
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; |
2258
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = $this->bindings[$this->currentBinding]['endpoint']; |
2259
|
|
|
} |
2260
|
|
|
break; |
2261
|
|
|
case 'input': |
2262
|
|
|
$this->opStatus = 'input'; |
|
|
|
|
2263
|
|
|
break; |
2264
|
|
|
case 'output': |
2265
|
|
|
$this->opStatus = 'output'; |
|
|
|
|
2266
|
|
|
break; |
2267
|
|
|
case 'body': |
2268
|
|
|
$this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus],$attrs); |
|
|
|
|
2269
|
|
|
break; |
2270
|
|
|
} |
2271
|
|
|
break; |
2272
|
|
|
case "service": |
2273
|
|
|
switch($name){ |
2274
|
|
|
case "port": |
2275
|
|
|
$this->currentPort = $attrs['name']; |
|
|
|
|
2276
|
|
|
$this->debug("current port: $this->currentPort"); |
|
|
|
|
2277
|
|
|
$this->ports[$this->currentPort]['binding'] = substr(strstr($attrs['binding'],":"),1); |
|
|
|
|
2278
|
|
|
|
2279
|
|
|
break; |
2280
|
|
|
case "address": |
2281
|
|
|
$this->ports[$this->currentPort]['location'] = $attrs['location']; |
|
|
|
|
2282
|
|
|
$this->ports[$this->currentPort]['bindingType'] = $this->getNamespaceFromPrefix($prefix); |
|
|
|
|
2283
|
|
|
$this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $this->getNamespaceFromPrefix($prefix); |
|
|
|
|
2284
|
|
|
$this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; |
|
|
|
|
2285
|
|
|
//echo "port $this->currentPort, has binding ".$this->ports[$this->currentPort]['binding']." and endpoint ".$attrs['location']."<br>"; |
2286
|
|
|
break; |
2287
|
|
|
} |
2288
|
|
|
break; |
2289
|
|
|
} |
2290
|
|
|
// set status |
2291
|
|
|
switch($name){ |
2292
|
|
|
case "import": |
2293
|
|
|
if(isset($attrs['location'])){ |
2294
|
|
|
$this->import[$attrs['namespace']] = $attrs['location']; |
2295
|
|
|
} |
2296
|
|
|
break; |
2297
|
|
|
case "types": |
2298
|
|
|
$this->status = "schema"; |
2299
|
|
|
break; |
2300
|
|
|
case "message": |
2301
|
|
|
$this->status = "message"; |
2302
|
|
|
$this->messages[$attrs["name"]] = array(); |
2303
|
|
|
$this->currentMessage = $attrs["name"]; |
2304
|
|
|
break; |
2305
|
|
|
case "portType": |
2306
|
|
|
$this->status = "portType"; |
2307
|
|
|
$this->portTypes[$attrs["name"]] = array(); |
2308
|
|
|
$this->currentPortType = $attrs["name"]; |
2309
|
|
|
break; |
2310
|
|
|
case "binding": |
2311
|
|
|
if(isset($attrs['name'])){ |
2312
|
|
|
// get binding name |
2313
|
|
|
if(preg_match("/:/",$attrs['name'])){ |
2314
|
|
|
$this->currentBinding = substr(strstr($attrs['name'],":"),1); |
2315
|
|
|
$prefix = substr($name,0,strpos($attrs['name'],":")); |
|
|
|
|
2316
|
|
|
} else { |
2317
|
|
|
$this->currentBinding = $attrs['name']; |
2318
|
|
|
} |
2319
|
|
|
$this->status = "binding"; |
2320
|
|
|
$this->bindings[$this->currentBinding]['portType'] = substr(strstr($attrs['type'],":"),1); |
2321
|
|
|
$this->debug("current binding: $this->currentBinding of portType: ".$attrs['type']); |
2322
|
|
|
} |
2323
|
|
|
break; |
2324
|
|
|
case "service": |
2325
|
|
|
$this->serviceName = $attrs["name"]; |
|
|
|
|
2326
|
|
|
$this->status = "service"; |
2327
|
|
|
break; |
2328
|
|
|
case "definitions": |
2329
|
|
|
foreach ($attrs as $name=>$value) { |
|
|
|
|
2330
|
|
|
$this->wsdl_info[$name]=$value; |
|
|
|
|
2331
|
|
|
} |
2332
|
|
|
break; |
2333
|
|
|
} |
2334
|
|
|
} |
2335
|
|
|
} |
2336
|
|
|
|
2337
|
|
|
/** |
2338
|
|
|
* end-element handler |
2339
|
|
|
* |
2340
|
|
|
* @param string $parser XML parser object |
2341
|
|
|
* @param string $name element name |
2342
|
|
|
* @access private |
2343
|
|
|
*/ |
2344
|
|
|
function end_element($parser, $name) { |
2345
|
|
|
// unset schema status |
2346
|
|
|
if(preg_match('/types$/',$name) || preg_match('/schema$/',$name)){ |
2347
|
|
|
$this->status = ""; |
2348
|
|
|
} |
2349
|
|
|
if($this->status == 'schema'){ |
2350
|
|
|
$this->schemaEndElement($parser, $name); |
2351
|
|
|
} else { |
2352
|
|
|
// position of current element is equal to the last value left in depth_array for my depth |
2353
|
|
|
$pos = $this->depth_array[$this->depth]; |
|
|
|
|
2354
|
|
|
// bring depth down a notch |
2355
|
|
|
$this->depth--; |
2356
|
|
|
} |
2357
|
|
|
// end documentation |
2358
|
|
|
if($this->documentation){ |
2359
|
|
|
$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; |
2360
|
|
|
$this->documentation = false; |
2361
|
|
|
} |
2362
|
|
|
} |
2363
|
|
|
|
2364
|
|
|
/** |
2365
|
|
|
* element content handler |
2366
|
|
|
* |
2367
|
|
|
* @param string $parser XML parser object |
2368
|
|
|
* @param string $data element content |
2369
|
|
|
* @access private |
2370
|
|
|
*/ |
2371
|
|
|
function character_data($parser, $data){ |
|
|
|
|
2372
|
|
|
$pos = $this->depth_array[$this->depth]; |
2373
|
|
|
$this->message[$pos]["cdata"] .= $data; |
|
|
|
|
2374
|
|
|
if($this->documentation){ |
2375
|
|
|
$this->documentation .= $data; |
2376
|
|
|
} |
2377
|
|
|
} |
2378
|
|
|
|
2379
|
|
|
|
2380
|
|
|
function getBindingData($binding){ |
2381
|
|
|
if(is_array($this->bindings[$binding])){ |
2382
|
|
|
return $this->bindings[$binding]; |
2383
|
|
|
} |
2384
|
|
|
} |
2385
|
|
|
|
2386
|
|
|
function getMessageData($operation,$portType,$msgType){ |
2387
|
|
|
$name = $this->opData[$operation][$msgType]['message']; |
2388
|
|
|
$this->debug( "getting msgData for $name, using $operation,$portType,$msgType<br>" ); |
2389
|
|
|
return $this->messages[$name]; |
2390
|
|
|
} |
2391
|
|
|
|
2392
|
|
|
/** |
2393
|
|
|
* returns an assoc array of operation names => operation data |
2394
|
|
|
* NOTE: currently only supports multiple services of differing binding types |
2395
|
|
|
* This method needs some work |
2396
|
|
|
* |
2397
|
|
|
* @param string $bindingType eg: soap, smtp, dime (only soap is currently supported) |
2398
|
|
|
* @return array |
2399
|
|
|
* @access public |
2400
|
|
|
*/ |
2401
|
|
|
function getOperations($bindingType = "soap"){ |
2402
|
|
|
if($bindingType == "soap"){ |
2403
|
|
|
$bindingType = "http://schemas.xmlsoap.org/wsdl/soap/"; |
2404
|
|
|
} |
2405
|
|
|
// loop thru ports |
2406
|
|
|
foreach($this->ports as $port => $portData){ |
2407
|
|
|
// binding type of port matches parameter |
2408
|
|
|
if($portData['bindingType'] == $bindingType){ |
2409
|
|
|
// get binding |
2410
|
|
|
return $this->bindings[ $portData['binding'] ]['operations']; |
2411
|
|
|
} |
2412
|
|
|
} |
2413
|
|
|
return array(); |
2414
|
|
|
} |
2415
|
|
|
|
2416
|
|
|
/** |
2417
|
|
|
* returns an associative array of data necessary for calling an operation |
2418
|
|
|
* |
2419
|
|
|
* @param string $operation, name of operation |
|
|
|
|
2420
|
|
|
* @param string $bindingType, type of binding eg: soap |
|
|
|
|
2421
|
|
|
* @return array |
2422
|
|
|
* @access public |
2423
|
|
|
*/ |
2424
|
|
|
function getOperationData($operation,$bindingType="soap"){ |
2425
|
|
|
if($bindingType == "soap"){ |
2426
|
|
|
$bindingType = "http://schemas.xmlsoap.org/wsdl/soap/"; |
2427
|
|
|
} |
2428
|
|
|
// loop thru ports |
2429
|
|
|
foreach($this->ports as $port => $portData){ |
2430
|
|
|
// binding type of port matches parameter |
2431
|
|
|
if($portData['bindingType'] == $bindingType){ |
2432
|
|
|
// get binding |
2433
|
|
|
foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData){ |
2434
|
|
|
if($operation == $bOperation){ |
2435
|
|
|
return $opData; |
2436
|
|
|
} |
2437
|
|
|
} |
2438
|
|
|
} |
2439
|
|
|
} |
2440
|
|
|
} |
2441
|
|
|
|
2442
|
|
|
/** |
2443
|
|
|
* serialize the parsed wsdl |
2444
|
|
|
* |
2445
|
|
|
* @return string, serialization of WSDL |
|
|
|
|
2446
|
|
|
* @access public |
2447
|
|
|
*/ |
2448
|
|
|
function serialize(){ |
2449
|
|
|
$xml = "<?xml version=\"1.0\"?><definitions"; |
2450
|
|
|
foreach($this->namespaces as $k => $v){ |
2451
|
|
|
$xml .= " xmlns:$k=\"$v\""; |
2452
|
|
|
} |
2453
|
|
|
$xml .= ">"; |
2454
|
|
|
|
2455
|
|
|
// imports |
2456
|
|
|
if(sizeof($this->import) > 0){ |
2457
|
|
|
foreach($this->import as $ns => $url){ |
2458
|
|
|
$xml .= "<import location=\"$url\" namespace=\"$ns\" />\n"; |
2459
|
|
|
} |
2460
|
|
|
} |
2461
|
|
|
|
2462
|
|
|
// types |
2463
|
|
|
if($this->schema){ |
|
|
|
|
2464
|
|
|
$xml .= "<types>"; |
2465
|
|
|
//$xml .= $this->serializeSchema(); |
2466
|
|
|
$xml .= "</types>"; |
2467
|
|
|
} |
2468
|
|
|
|
2469
|
|
|
// messages |
2470
|
|
|
if(count($this->messages) >= 1){ |
2471
|
|
|
foreach($this->messages as $msgName => $msgParts){ |
2472
|
|
|
$xml .= "<message name=\"$msgName\">"; |
2473
|
|
|
foreach($msgParts as $partName => $partType){ |
2474
|
|
|
$xml .= "<part name=\"$partName\" type=\"$partType\" />"; |
2475
|
|
|
} |
2476
|
|
|
$xml .= "</message>"; |
2477
|
|
|
} |
2478
|
|
|
} |
2479
|
|
|
// portTypes |
2480
|
|
|
if(count($this->portTypes) >= 1){ |
2481
|
|
|
foreach($this->portTypes as $portTypeName => $portOperations){ |
2482
|
|
|
$xml .= "<portType name=\"$portTypeName\">"; |
2483
|
|
|
foreach($portOperations as $portOperation => $parameterOrder){ |
2484
|
|
|
$xml .= "<operation name=\"$portOperation\" parameterOrder=\"$parameterOrder\">"; |
2485
|
|
|
foreach($this->portTypes[$portTypeName][$portOperation] as $name => $attrs){ |
2486
|
|
|
$xml .= "<$name"; |
2487
|
|
|
if(is_array($attrs)){ |
2488
|
|
|
foreach($attrs as $k => $v){ |
2489
|
|
|
$xml .= " $k=\"$v\""; |
2490
|
|
|
} |
2491
|
|
|
} |
2492
|
|
|
$xml .= "/>"; |
2493
|
|
|
} |
2494
|
|
|
$xml .= "</operation>"; |
2495
|
|
|
} |
2496
|
|
|
$xml .= "</portType>"; |
2497
|
|
|
} |
2498
|
|
|
} |
2499
|
|
|
// bindings |
2500
|
|
|
if(count($this->bindings) >= 1){ |
2501
|
|
|
foreach($this->bindings as $bindingName => $attrs){ |
2502
|
|
|
$xml .= "<binding name=\"$msgName\" type=\"".$attrs["type"]."\">"; |
|
|
|
|
2503
|
|
|
$xml .= "<soap:binding style=\"".$attrs["style"]."\" transport=\"".$attrs["transport"]."\"/>"; |
2504
|
|
|
foreach($attrs["operations"] as $opName => $opParts){ |
2505
|
|
|
$xml .= "<operation name=\"$opName\">"; |
2506
|
|
|
$xml .= "<soap:operation soapAction=\"".$opParts["soapAction"]."\"/>"; |
2507
|
|
|
$xml .= "<input>"; |
2508
|
|
|
$xml .= "<soap:body use=\"".$opParts["input"]["use"]."\" namespace=\"".$opParts["input"]["namespace"]."\" encodingStyle=\"".$opParts["input"]["encodingStyle"]."\"/>"; |
2509
|
|
|
$xml .= "</input>"; |
2510
|
|
|
$xml .= "<output>"; |
2511
|
|
|
$xml .= "<soap:body use=\"".$opParts["output"]["use"]."\" namespace=\"".$opParts["output"]["namespace"]."\" encodingStyle=\"".$opParts["output"]["encodingStyle"]."\"/>"; |
2512
|
|
|
$xml .= "</output>"; |
2513
|
|
|
$xml .= "</operation>"; |
2514
|
|
|
} |
2515
|
|
|
$xml .= "</message>"; |
2516
|
|
|
} |
2517
|
|
|
} |
2518
|
|
|
// services |
2519
|
|
|
$xml .= "<service name=\"$this->serviceName\">"; |
2520
|
|
|
if(count($this->ports) >= 1){ |
2521
|
|
|
foreach($this->ports as $pName => $attrs){ |
2522
|
|
|
$xml .= "<port name=\"$pName\" binding=\"".$attrs["binding"]."\">"; |
2523
|
|
|
$xml .= "soap:address location=\"".$attrs["location"]."\"/>"; |
2524
|
|
|
$xml .= "</port>"; |
2525
|
|
|
} |
2526
|
|
|
} |
2527
|
|
|
$xml .= "</service>"; |
2528
|
|
|
return $xml."</definitions>"; |
2529
|
|
|
} |
2530
|
|
|
|
2531
|
|
|
/** |
2532
|
|
|
* serialize a PHP value according to a WSDL message definition |
2533
|
|
|
* |
2534
|
|
|
* TODO |
2535
|
|
|
* - only serialize namespaces used in the message |
2536
|
|
|
* - multi-ref serialization |
2537
|
|
|
* - validate PHP values against type definitions, return errors if invalid |
2538
|
|
|
* - probably more stuff :) |
2539
|
|
|
* - implement 'out' functionality or write new function for 'out' parameters |
2540
|
|
|
* |
2541
|
|
|
* @param string type name |
2542
|
|
|
* @param mixed param value |
2543
|
|
|
* @return mixed new param or false if initial value didn't validate |
2544
|
|
|
*/ |
2545
|
|
|
function serializeRPCParameters($operation,$direction,$parameters){ |
2546
|
|
|
if($direction != 'input' && $direction != 'output'){ |
2547
|
|
|
$this->setError('The value of the \$direction argument needs to be either "input" or "output"'); |
2548
|
|
|
return false; |
2549
|
|
|
} |
2550
|
|
|
if(!$opData = $this->getOperationData($operation)){ |
2551
|
|
|
return false; |
2552
|
|
|
} |
2553
|
|
|
$this->debug( "in serializeRPCParameters with xml schema version $this->XMLSchemaVersion"); |
|
|
|
|
2554
|
|
|
// set input params |
2555
|
|
|
if(sizeof($opData[$direction]['parts']) > 0){ |
2556
|
|
|
foreach($opData[$direction]['parts'] as $name => $type){ |
2557
|
|
|
$xml .= $this->serializeType($name,$type,array_shift($parameters)); |
|
|
|
|
2558
|
|
|
} |
2559
|
|
|
} |
2560
|
|
|
return $xml; |
2561
|
|
|
} |
2562
|
|
|
|
2563
|
|
|
/** |
2564
|
|
|
* serializes a PHP value according a given type definition |
2565
|
|
|
* |
2566
|
|
|
* @param string $name, name of type |
|
|
|
|
2567
|
|
|
* @param string $type, type of type, heh |
|
|
|
|
2568
|
|
|
* @param mixed $value, a native PHP value |
|
|
|
|
2569
|
|
|
* @return string serialization |
2570
|
|
|
* @access public |
2571
|
|
|
*/ |
2572
|
|
|
function serializeType($name,$type,$value){ |
2573
|
|
|
$this->debug("in serializeType: $name, $type, $value"); |
2574
|
|
|
if(strpos($type,':')){ |
2575
|
|
|
$uqType = substr($type,strrpos($type,":")+1); |
2576
|
|
|
$ns = substr($type,0,strrpos($type,":")); |
2577
|
|
|
$this->debug("got a prefixed type: $uqType, $ns"); |
2578
|
|
|
if($ns == $this->XMLSchemaVersion){ |
|
|
|
|
2579
|
|
|
if($uqType == 'boolean' && !$value){ |
2580
|
|
|
$value = 0; |
2581
|
|
|
} elseif($uqType == 'boolean'){ |
2582
|
|
|
$value = 1; |
2583
|
|
|
} |
2584
|
|
|
if($uqType == 'string' && $this->charencoding){ |
2585
|
|
|
$value = htmlspecialchars($value); |
2586
|
|
|
} |
2587
|
|
|
// it's a scalar |
2588
|
|
|
return "<$name xsi:type=\"".$this->getPrefixFromNamespace($this->XMLSchemaVersion).":$uqType\">$value</$name>\n"; |
|
|
|
|
2589
|
|
|
} |
2590
|
|
|
} else { |
2591
|
|
|
$uqType = $type; |
2592
|
|
|
} |
2593
|
|
|
$typeDef = $this->getTypeDef($uqType); |
2594
|
|
|
$phpType = $typeDef['phpType']; |
2595
|
|
|
$this->debug("serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: ".$typeDef['arrayType']); |
|
|
|
|
2596
|
|
|
// if php type == struct, map value to the <all> element names |
2597
|
|
|
if($phpType == "struct"){ |
2598
|
|
|
$xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace($ns).":$uqType\">\n"; |
2599
|
|
|
if(is_array($this->complexTypes[$uqType]["elements"])){ |
2600
|
|
|
foreach($this->complexTypes[$uqType]["elements"] as $eName => $attrs){ |
2601
|
|
|
// get value |
2602
|
|
|
if(isset($value[$eName])){ |
2603
|
|
|
$v = $value[$eName]; |
2604
|
|
|
} elseif(is_array($value)) { |
2605
|
|
|
$v = array_shift($value); |
2606
|
|
|
} |
2607
|
|
|
if(!isset($attrs['type'])){ |
2608
|
|
|
$xml .= $this->serializeType($eName,$attrs['name'],$v); |
|
|
|
|
2609
|
|
|
} else { |
2610
|
|
|
$this->debug("calling serialize_val() for $eName, $v, ".$this->getLocalPart($attrs['type'])); |
2611
|
|
|
$xml .= $this->serialize_val($v,$eName,$this->getLocalPart($attrs['type']),null,$this->getNamespaceFromPrefix($this->getPrefix($attrs['type']))); |
2612
|
|
|
} |
2613
|
|
|
} |
2614
|
|
|
} |
2615
|
|
|
$xml .= "</$name>\n"; |
2616
|
|
|
} elseif($phpType == "array"){ |
2617
|
|
|
$rows = sizeof($value); |
2618
|
|
|
if($typeDef['multidimensional']){ |
2619
|
|
|
$nv = array(); |
2620
|
|
|
foreach($value as $v){ |
2621
|
|
|
$cols = ','.sizeof($v); |
2622
|
|
|
$nv = array_merge($nv,$v); |
2623
|
|
|
} |
2624
|
|
|
$value = $nv; |
2625
|
|
|
} |
2626
|
|
|
if(is_array($value) && sizeof($value) >= 1){ |
2627
|
|
|
foreach($value as $k => $v){ |
2628
|
|
|
if(strpos($typeDef['arrayType'],':')){ |
2629
|
|
|
$contents .= $this->serializeType('item',$typeDef['arrayType'],$v); |
|
|
|
|
2630
|
|
|
} else { |
2631
|
|
|
$contents .= $this->serialize_val($v,'item',$typeDef['arrayType'],null,$this->XMLSchemaVersion); |
|
|
|
|
2632
|
|
|
} |
2633
|
|
|
} |
2634
|
|
|
} |
2635
|
|
|
$xml = "<$name xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').":Array\" ". |
2636
|
|
|
$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') |
2637
|
|
|
.":arrayType=\"" |
2638
|
|
|
.$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) |
2639
|
|
|
.":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">\n" |
|
|
|
|
2640
|
|
|
.$contents |
2641
|
|
|
."</$name>\n"; |
2642
|
|
|
} |
2643
|
|
|
return $xml; |
|
|
|
|
2644
|
|
|
} |
2645
|
|
|
} |
2646
|
|
|
|
2647
|
|
|
?> |
2648
|
|
|
<?php |
2649
|
|
|
/* |
2650
|
|
|
|
2651
|
|
|
NuSOAP - Web Services Toolkit for PHP |
2652
|
|
|
|
2653
|
|
|
Copyright (c) 2002 NuSphere Corporation |
2654
|
|
|
|
2655
|
|
|
This library is free software; you can redistribute it and/or |
2656
|
|
|
modify it under the terms of the GNU Lesser General Public |
2657
|
|
|
License as published by the Free Software Foundation; either |
2658
|
|
|
version 2.1 of the License, or (at your option) any later version. |
2659
|
|
|
|
2660
|
|
|
This library is distributed in the hope that it will be useful, |
2661
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
2662
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2663
|
|
|
Lesser General Public License for more details. |
2664
|
|
|
|
2665
|
|
|
You should have received a copy of the GNU Lesser General Public |
2666
|
|
|
License along with this library; if not, write to the Free Software |
2667
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2668
|
|
|
|
2669
|
|
|
*/ |
2670
|
|
|
|
2671
|
|
|
/** |
2672
|
|
|
* |
2673
|
|
|
* soap_parser class parses SOAP XML messages |
2674
|
|
|
* |
2675
|
|
|
* @author Dietrich Ayala <[email protected]> |
2676
|
|
|
* @version v 0.051 |
2677
|
|
|
* @access public |
2678
|
|
|
*/ |
2679
|
|
|
class soap_parser extends nusoap_base { |
2680
|
|
|
/** |
2681
|
|
|
* constructor |
2682
|
|
|
* |
2683
|
|
|
* @param string $xml SOAP message |
2684
|
|
|
* @param string $encoding character encoding scheme of message |
2685
|
|
|
* @access public |
2686
|
|
|
*/ |
2687
|
|
|
function __construct($xml,$encoding="UTF-8",$method=""){ |
2688
|
|
|
$this->xml = $xml; |
|
|
|
|
2689
|
|
|
$this->xml_encoding = $encoding; |
|
|
|
|
2690
|
|
|
$this->method = $method; |
|
|
|
|
2691
|
|
|
$this->root_struct = ""; |
|
|
|
|
2692
|
|
|
$this->root_struct_name = ""; |
|
|
|
|
2693
|
|
|
$this->root_header = ""; |
|
|
|
|
2694
|
|
|
// determines where in the message we are (envelope,header,body,method) |
2695
|
|
|
$this->status = ""; |
|
|
|
|
2696
|
|
|
$this->position = 0; |
|
|
|
|
2697
|
|
|
$this->depth = 0; |
|
|
|
|
2698
|
|
|
$this->default_namespace = ""; |
|
|
|
|
2699
|
|
|
$this->namespaces = array(); |
|
|
|
|
2700
|
|
|
$this->message = array(); |
|
|
|
|
2701
|
|
|
$this->fault = false; |
|
|
|
|
2702
|
|
|
$this->fault_code = ""; |
|
|
|
|
2703
|
|
|
$this->fault_str = ""; |
|
|
|
|
2704
|
|
|
$this->fault_detail = ""; |
|
|
|
|
2705
|
|
|
$this->errstr = ""; |
|
|
|
|
2706
|
|
|
$this->depth_array = array(); |
|
|
|
|
2707
|
|
|
$this->debug_flag = true; |
|
|
|
|
2708
|
|
|
$this->debug_str = ""; |
|
|
|
|
2709
|
|
|
$this->soapresponse = NULL; |
|
|
|
|
2710
|
|
|
$this->responseHeaders = ""; |
|
|
|
|
2711
|
|
|
// for multiref parsing: |
2712
|
|
|
// array of id => pos |
2713
|
|
|
$this->ids = array(); |
|
|
|
|
2714
|
|
|
// array of id => hrefs => pos |
2715
|
|
|
$this->multirefs = array(); |
|
|
|
|
2716
|
|
|
|
2717
|
|
|
$this->entities = array ( "&" => "&", "<" => "<", ">" => ">", |
|
|
|
|
2718
|
|
|
"'" => "'", '"' => """ ); |
2719
|
|
|
|
2720
|
|
|
// Check whether content has been read. |
2721
|
|
|
if(!empty($xml)){ |
2722
|
|
|
$this->debug("Entering soap_parser()"); |
2723
|
|
|
// Create an XML parser. |
2724
|
|
|
$this->parser = xml_parser_create($this->xml_encoding); |
|
|
|
|
2725
|
|
|
// Set the options for parsing the XML data. |
2726
|
|
|
//xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); |
2727
|
|
|
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); |
2728
|
|
|
// Set the object for the parser. |
2729
|
|
|
xml_set_object($this->parser, $this); |
2730
|
|
|
// Set the element handlers for the parser. |
2731
|
|
|
xml_set_element_handler($this->parser, "start_element","end_element"); |
2732
|
|
|
xml_set_character_data_handler($this->parser,"character_data"); |
2733
|
|
|
//xml_set_default_handler($this->parser, "default_handler"); |
2734
|
|
|
|
2735
|
|
|
// Parse the XML file. |
2736
|
|
|
if(!xml_parse($this->parser,$xml,true)){ |
2737
|
|
|
// Display an error message. |
2738
|
|
|
$err = sprintf("XML error on line %d: %s", |
2739
|
|
|
xml_get_current_line_number($this->parser), |
2740
|
|
|
xml_error_string(xml_get_error_code($this->parser))); |
2741
|
|
|
$this->debug("parse error: $err"); |
2742
|
|
|
$this->errstr = $err; |
2743
|
|
|
} else { |
2744
|
|
|
$this->debug("parsed successfully, found root struct: $this->root_struct of name $this->root_struct_name"); |
|
|
|
|
2745
|
|
|
// get final value |
2746
|
|
|
$this->soapresponse = $this->message[$this->root_struct]['result']; |
2747
|
|
|
// get header value |
2748
|
|
|
if($this->root_header != ""){ |
2749
|
|
|
$this->responseHeaders = $this->message[$this->root_header]['result']; |
2750
|
|
|
} |
2751
|
|
|
} |
2752
|
|
|
xml_parser_free($this->parser); |
2753
|
|
|
} else { |
2754
|
|
|
$this->debug("xml was empty, didn't parse!"); |
2755
|
|
|
$this->errstr = "xml was empty, didn't parse!"; |
2756
|
|
|
} |
2757
|
|
|
} |
2758
|
|
|
|
2759
|
|
|
/** |
2760
|
|
|
* start-element handler |
2761
|
|
|
* |
2762
|
|
|
* @param string $parser XML parser object |
2763
|
|
|
* @param string $name element name |
2764
|
|
|
* @param string $attrs associative array of attributes |
2765
|
|
|
* @access private |
2766
|
|
|
*/ |
2767
|
|
|
function start_element($parser, $name, $attrs) { |
|
|
|
|
2768
|
|
|
// position in a total number of elements, starting from 0 |
2769
|
|
|
// update class level pos |
2770
|
|
|
$pos = $this->position++; |
2771
|
|
|
// and set mine |
2772
|
|
|
$this->message[$pos]["pos"] = $pos; |
2773
|
|
|
// depth = how many levels removed from root? |
2774
|
|
|
// set mine as current global depth and increment global depth value |
2775
|
|
|
$this->message[$pos]["depth"] = $this->depth++; |
2776
|
|
|
|
2777
|
|
|
// else add self as child to whoever the current parent is |
2778
|
|
|
if($pos != 0){ |
2779
|
|
|
$this->message[$this->parent]["children"] .= "|$pos"; |
|
|
|
|
2780
|
|
|
} |
2781
|
|
|
// set my parent |
2782
|
|
|
$this->message[$pos]["parent"] = $this->parent; |
2783
|
|
|
// set self as current parent |
2784
|
|
|
$this->parent = $pos; |
2785
|
|
|
// set self as current value for this depth |
2786
|
|
|
$this->depth_array[$this->depth] = $pos; |
2787
|
|
|
// get element prefix |
2788
|
|
View Code Duplication |
if(strpos($name,":")){ |
2789
|
|
|
// get ns prefix |
2790
|
|
|
$prefix = substr($name,0,strpos($name,":")); |
2791
|
|
|
// get unqualified name |
2792
|
|
|
$name = substr(strstr($name,":"),1); |
2793
|
|
|
} |
2794
|
|
|
// set status |
2795
|
|
|
if($name == "Envelope"){ |
2796
|
|
|
$this->status = "envelope"; |
2797
|
|
|
} elseif($name == "Header"){ |
2798
|
|
|
$this->root_header = $pos; |
2799
|
|
|
$this->status = "header"; |
2800
|
|
|
} elseif($name == "Body"){ |
2801
|
|
|
$this->status = "body"; |
2802
|
|
|
$this->body_position = $pos; |
|
|
|
|
2803
|
|
|
// set method |
2804
|
|
|
} elseif($this->status == "body" && $pos == ($this->body_position+1)){ |
|
|
|
|
2805
|
|
|
//if($name == $this->method."Response" || $name == $this->method || $name == "Fault"){ |
2806
|
|
|
$this->status = "method"; |
2807
|
|
|
$this->root_struct_name = $name; |
|
|
|
|
2808
|
|
|
$this->root_struct = $pos; |
2809
|
|
|
$this->message[$pos]["type"] = "struct"; |
2810
|
|
|
$this->debug("found root struct $this->root_struct_name, pos $pos"); |
|
|
|
|
2811
|
|
|
//} |
2812
|
|
|
} |
2813
|
|
|
// set my status |
2814
|
|
|
$this->message[$pos]["status"] = $this->status; |
2815
|
|
|
// set name |
2816
|
|
|
$this->message[$pos]["name"] = htmlspecialchars($name); |
2817
|
|
|
// set attrs |
2818
|
|
|
$this->message[$pos]["attrs"] = $attrs; |
2819
|
|
|
// get namespace |
2820
|
|
|
if($prefix){ |
2821
|
|
|
$this->message[$pos]["namespace"] = $this->namespaces[$prefix]; |
|
|
|
|
2822
|
|
|
$this->default_namespace = $this->namespaces[$prefix]; |
2823
|
|
|
} else { |
2824
|
|
|
$this->message[$pos]["namespace"] = $this->default_namespace; |
2825
|
|
|
} |
2826
|
|
|
// loop through atts, logging ns and type declarations |
2827
|
|
|
foreach($attrs as $key => $value){ |
|
|
|
|
2828
|
|
|
|
2829
|
|
|
// if ns declarations, add to class level array of valid namespaces |
2830
|
|
|
if(strpos($key,'xmlns:')){ |
2831
|
|
|
$prefix = substr(strrchr($key,":"),1); |
|
|
|
|
2832
|
|
|
if(preg_match('|^http://www.w3.org/[0-9]{4}/XMLSchema$|',$value)){ |
2833
|
|
|
global $XMLSchemaVersion,$namespaces; |
2834
|
|
|
$XMLSchemaVersion = $value; |
2835
|
|
|
$namespaces["xsd"] = $XMLSchemaVersion; |
2836
|
|
|
$namespaces["xsi"] = $XMLSchemaVersion."-instance"; |
2837
|
|
|
} |
2838
|
|
|
$this->namespaces[substr(strrchr($key,":"),1)] = $value; |
2839
|
|
|
// set method namespace |
2840
|
|
|
if($name == $this->root_struct_name){ |
|
|
|
|
2841
|
|
|
$this->methodNamespace = $value; |
|
|
|
|
2842
|
|
|
} |
2843
|
|
|
// if it's a type declaration, set type |
2844
|
|
|
} elseif(strpos($key,":type")){ |
2845
|
|
|
$this->message[$pos]["type"] = substr(strrchr($value,":"),1); |
2846
|
|
|
$this->message[$pos]["typePrefix"] = substr($value,0,strpos($key,":")-1); |
2847
|
|
|
// should do something here with the namespace of specified type? |
2848
|
|
|
} elseif(strpos($key,":arrayType")){ |
2849
|
|
|
$this->message[$pos]['type'] = 'array'; |
2850
|
|
|
/* do arrayType preg here |
2851
|
|
|
[1] arrayTypeValue ::= atype asize |
2852
|
|
|
[2] atype ::= QName rank* |
2853
|
|
|
[3] rank ::= '[' (',')* ']' |
2854
|
|
|
[4] asize ::= '[' length~ ']' |
2855
|
|
|
[5] length ::= nextDimension* Digit+ |
2856
|
|
|
[6] nextDimension ::= Digit+ ',' |
2857
|
|
|
*/ |
2858
|
|
|
$expr = "/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/"; |
2859
|
|
|
if(preg_match($expr,$value,$regs)){ |
2860
|
|
|
$this->message[$pos]['typePrefix'] = $regs[1]; |
2861
|
|
|
$this->message[$pos]['arraySize'] = $regs[3]; |
2862
|
|
|
$this->message[$pos]['arrayCols'] = $regs[4]; |
2863
|
|
|
} |
2864
|
|
|
} |
2865
|
|
|
// log id |
2866
|
|
|
if($key == "id"){ |
2867
|
|
|
$this->ids[$value] = $pos; |
2868
|
|
|
} |
2869
|
|
|
// root |
2870
|
|
|
if(strpos($key,":root") && $value == 1){ |
2871
|
|
|
$this->status = "method"; |
2872
|
|
|
$this->root_struct_name = $name; |
|
|
|
|
2873
|
|
|
$this->root_struct = $pos; |
2874
|
|
|
$this->debug("found root struct $this->root_struct_name, pos $pos"); |
|
|
|
|
2875
|
|
|
} |
2876
|
|
|
} |
2877
|
|
|
} |
2878
|
|
|
|
2879
|
|
|
/** |
2880
|
|
|
* end-element handler |
2881
|
|
|
* |
2882
|
|
|
* @param string $parser XML parser object |
2883
|
|
|
* @param string $name element name |
2884
|
|
|
* @access private |
2885
|
|
|
*/ |
2886
|
|
|
function end_element($parser, $name) { |
|
|
|
|
2887
|
|
|
// position of current element is equal to the last value left in depth_array for my depth |
2888
|
|
|
$pos = $this->depth_array[$this->depth]; |
2889
|
|
|
// bring depth down a notch |
2890
|
|
|
$this->depth--; |
2891
|
|
|
|
2892
|
|
|
// build to native type |
2893
|
|
|
if($pos > $this->body_position){ |
|
|
|
|
2894
|
|
|
// deal w/ multirefs |
2895
|
|
|
if(isset($this->message[$pos]['attrs']['href'])){ |
2896
|
|
|
// get id |
2897
|
|
|
$id = substr($this->message[$pos]['attrs']['href'],1); |
2898
|
|
|
// add placeholder to href array |
2899
|
|
|
$this->multirefs[$id][$pos] = "placeholder"; |
2900
|
|
|
// add set a reference to it as the result value |
2901
|
|
|
$this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; |
2902
|
|
|
} elseif($this->message[$pos]['children'] != ""){ |
2903
|
|
|
$this->message[$pos]['result'] = $this->buildVal($pos); |
2904
|
|
|
} else { |
2905
|
|
|
$this->message[$pos]['result'] = $this->message[$pos]['cdata']; |
2906
|
|
|
} |
2907
|
|
|
} |
2908
|
|
|
|
2909
|
|
|
// switch status |
2910
|
|
|
if($pos == $this->root_struct){ |
2911
|
|
|
$this->status = "body"; |
2912
|
|
|
} elseif(preg_match("/:Body/i",$name)){ |
2913
|
|
|
$this->status = "header"; |
2914
|
|
|
} elseif(preg_match("/:Header/i",$name)){ |
2915
|
|
|
$this->status = "envelope"; |
2916
|
|
|
} elseif(preg_match("/:Envelope/i",$name)){ |
2917
|
|
|
// resolve hrefs/ids |
2918
|
|
|
if(sizeof($this->multirefs) > 0){ |
2919
|
|
|
foreach($this->multirefs as $id => $hrefs){ |
2920
|
|
|
$this->debug("resolving multirefs for id: $id"); |
2921
|
|
|
foreach($hrefs as $refPos => $ref){ |
2922
|
|
|
$this->debug("resolving href at pos $refPos"); |
2923
|
|
|
$this->multirefs[$id][$refPos] = $this->buildval($this->ids[$id]); |
2924
|
|
|
} |
2925
|
|
|
} |
2926
|
|
|
} |
2927
|
|
|
} |
2928
|
|
|
// set parent back to my parent |
2929
|
|
|
$this->parent = $this->message[$pos]["parent"]; |
2930
|
|
|
} |
2931
|
|
|
|
2932
|
|
|
/** |
2933
|
|
|
* element content handler |
2934
|
|
|
* |
2935
|
|
|
* @param string $parser XML parser object |
2936
|
|
|
* @param string $data element content |
2937
|
|
|
* @access private |
2938
|
|
|
*/ |
2939
|
|
|
function character_data($parser, $data){ |
|
|
|
|
2940
|
|
|
$pos = $this->depth_array[$this->depth]; |
2941
|
|
|
$this->message[$pos]["cdata"] .= $data; |
2942
|
|
|
} |
2943
|
|
|
|
2944
|
|
|
/** |
2945
|
|
|
* get the parsed message |
2946
|
|
|
* |
2947
|
|
|
* @return object SOAPx4 soap_val object |
2948
|
|
|
* @access public |
2949
|
|
|
*/ |
2950
|
|
|
function get_response(){ |
2951
|
|
|
return $this->soapresponse; |
2952
|
|
|
} |
2953
|
|
|
|
2954
|
|
|
/** |
2955
|
|
|
* get the parsed headers |
2956
|
|
|
* |
2957
|
|
|
* @return mixed object SOAPx4 soapval object or empty if no headers |
2958
|
|
|
* @access public |
2959
|
|
|
*/ |
2960
|
|
|
function getHeaders(){ |
2961
|
|
|
return $this->responseHeaders; |
2962
|
|
|
} |
2963
|
|
|
|
2964
|
|
|
/** |
2965
|
|
|
* decodes entities |
2966
|
|
|
* |
2967
|
|
|
* @param string $text string to translate |
2968
|
|
|
* @access private |
2969
|
|
|
*/ |
2970
|
|
|
function decode_entities($text){ |
2971
|
|
|
foreach($this->entities as $entity => $encoded){ |
|
|
|
|
2972
|
|
|
$text = str_replace($encoded,$entity,$text); |
2973
|
|
|
} |
2974
|
|
|
return $text; |
2975
|
|
|
} |
2976
|
|
|
|
2977
|
|
|
/** |
2978
|
|
|
* builds response structures for compound values (arrays/structs) |
2979
|
|
|
* |
2980
|
|
|
* @param string $pos position in node tree |
2981
|
|
|
* @access private |
2982
|
|
|
*/ |
2983
|
|
|
function buildVal($pos){ |
2984
|
|
|
// build self |
2985
|
|
|
$this->debug("inside buildVal() for ".$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]["type"]); |
2986
|
|
|
// if there are children... |
2987
|
|
|
if($this->message[$pos]["children"] != ""){ |
2988
|
|
|
$children = explode("|",$this->message[$pos]["children"]); |
2989
|
|
|
array_shift($children); // knock off empty |
2990
|
|
|
// loop thru them, getting params |
2991
|
|
|
foreach($children as $child_pos){ |
2992
|
|
|
// md array |
2993
|
|
|
if($this->message[$pos]['arrayCols']){ |
2994
|
|
|
$this->debug("got an MD array element: $r, $c"); |
|
|
|
|
2995
|
|
|
$params[$r][] = $this->message[$child_pos]['result']; |
|
|
|
|
2996
|
|
|
$c++; |
2997
|
|
|
if($c == $this->message[$pos]['arrayCols']){ |
2998
|
|
|
$c = 0; |
2999
|
|
|
$r++; |
3000
|
|
|
} |
3001
|
|
|
} elseif($this->message[$pos]['type'] == 'array'){ |
3002
|
|
|
$params[] =& $this->message[$child_pos]['result']; |
|
|
|
|
3003
|
|
|
} else { |
3004
|
|
|
$params[$this->message[$child_pos]["name"]] =& $this->message[$child_pos]['result']; |
3005
|
|
|
} |
3006
|
|
|
} |
3007
|
|
|
return is_array($params) ? $params : array(); |
3008
|
|
|
} else { |
3009
|
|
|
//return $this->message[$pos]['cdata']; |
3010
|
|
|
return strtr($this->message[$pos]['cdata'],array_flip($this->entities)); |
|
|
|
|
3011
|
|
|
} |
3012
|
|
|
} |
3013
|
|
|
|
3014
|
|
|
/** |
3015
|
|
|
* for building SOAP header values |
3016
|
|
|
* |
3017
|
|
|
* @param string $pos position in node tree |
3018
|
|
|
* @access private |
3019
|
|
|
*/ |
3020
|
|
|
function buildSoapVal($pos){ |
3021
|
|
|
// if there are children... |
3022
|
|
|
if($this->message[$pos]["children"] != ""){ |
3023
|
|
|
$children = explode("|",$this->message[$pos]["children"]); |
3024
|
|
|
// loop thru them, getting params |
3025
|
|
|
foreach($children as $c => $child_pos){ |
3026
|
|
|
if($this->message[$child_pos]["type"] != NULL) { |
3027
|
|
|
$this->debug("adding ".$this->message[$child_pos]["name"].", pos: $child_pos"); |
3028
|
|
|
$params[] = $this->message[$child_pos]['result']; |
|
|
|
|
3029
|
|
|
} |
3030
|
|
|
} |
3031
|
|
|
} |
3032
|
|
|
// build self |
3033
|
|
|
$this->debug("building ".$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]["type"]); |
3034
|
|
|
if($params){ |
|
|
|
|
3035
|
|
|
return new soapval($this->message[$pos]["name"], $this->message[$pos]["type"] , $params); |
|
|
|
|
3036
|
|
|
} else { |
3037
|
|
|
return new soapval($this->message[$pos]["name"], $this->message[$pos]["type"] , $this->message[$pos]["cdata"]); |
3038
|
|
|
} |
3039
|
|
|
} |
3040
|
|
|
} |
3041
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.