/[drupal]/contributions/sandbox/stevemckenzie/salesforce/includes/nusoap.php
ViewVC logotype

Contents of /contributions/sandbox/stevemckenzie/salesforce/includes/nusoap.php

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Mon Oct 16 20:24:05 2006 UTC (3 years, 1 month ago) by stevemckenzie
Branch: MAIN
CVS Tags: HEAD
File MIME type: text/x-php
checkin of salesforce.module - ahhhh the madness
1 <?php
2
3 /*
4 $Id: nusoap.php,v 1.4 2005/12/07 06:12:25 ryankicks Exp $
5
6 NuSOAP - Web Services Toolkit for PHP
7
8 Copyright (c) 2002 NuSphere Corporation
9
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 2.1 of the License, or (at your option) any later version.
14
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
24 If you have any questions or comments, please email:
25
26 Dietrich Ayala
27 dietrich@ganx4.com
28 http://dietrich.ganx4.com/nusoap
29
30 NuSphere Corporation
31 http://www.nusphere.com
32
33 */
34
35 /* load classes
36
37 // necessary classes
38 require_once('class.nusoapclient.php');
39 require_once('class.soap_val.php');
40 require_once('class.soap_parser.php');
41 require_once('class.soap_fault.php');
42
43 // transport classes
44 require_once('class.soap_transport_http.php');
45
46 // optional add-on classes
47 require_once('class.xmlschema.php');
48 require_once('class.wsdl.php');
49
50 // server class
51 require_once('class.soap_server.php');*/
52
53 // class variable emulation
54 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
55 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = 9;
56
57 /**
58 *
59 * nusoap_base
60 *
61 * @author Dietrich Ayala <dietrich@ganx4.com>
62 * @version $Id: nusoap.php,v 1.4 2005/12/07 06:12:25 ryankicks Exp $
63 * @access public
64 */
65 class nusoap_base {
66 /**
67 * Identification for HTTP headers.
68 *
69 * @var string
70 * @access private
71 */
72 var $title = 'NuSOAP';
73 /**
74 * Version for HTTP headers.
75 *
76 * @var string
77 * @access private
78 */
79 var $version = '0.7.2';
80 /**
81 * CVS revision for HTTP headers.
82 *
83 * @var string
84 * @access private
85 */
86 var $revision = '$Revision: 1.4 $';
87 /**
88 * Current error string (manipulated by getError/setError)
89 *
90 * @var string
91 * @access private
92 */
93 var $error_str = '';
94 /**
95 * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
96 *
97 * @var string
98 * @access private
99 */
100 var $debug_str = '';
101 /**
102 * toggles automatic encoding of special characters as entities
103 * (should always be true, I think)
104 *
105 * @var boolean
106 * @access private
107 */
108 var $charencoding = true;
109 /**
110 * the debug level for this instance
111 *
112 * @var integer
113 * @access private
114 */
115 var $debugLevel;
116
117 /**
118 * set schema version
119 *
120 * @var string
121 * @access public
122 */
123 var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
124
125 /**
126 * charset encoding for outgoing messages
127 *
128 * @var string
129 * @access public
130 */
131 var $soap_defencoding = 'ISO-8859-1';
132 //var $soap_defencoding = 'UTF-8';
133
134 /**
135 * namespaces in an array of prefix => uri
136 *
137 * this is "seeded" by a set of constants, but it may be altered by code
138 *
139 * @var array
140 * @access public
141 */
142 var $namespaces = array(
143 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
144 'xsd' => 'http://www.w3.org/2001/XMLSchema',
145 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
146 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
147 );
148
149 /**
150 * namespaces used in the current context, e.g. during serialization
151 *
152 * @var array
153 * @access private
154 */
155 var $usedNamespaces = array();
156
157 /**
158 * XML Schema types in an array of uri => (array of xml type => php type)
159 * is this legacy yet?
160 * no, this is used by the xmlschema class to verify type => namespace mappings.
161 * @var array
162 * @access public
163 */
164 var $typemap = array(
165 'http://www.w3.org/2001/XMLSchema' => array(
166 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
167 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
168 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
169 // abstract "any" types
170 'anyType'=>'string','anySimpleType'=>'string',
171 // derived datatypes
172 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
173 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
174 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
175 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
176 'http://www.w3.org/2000/10/XMLSchema' => array(
177 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
178 'float'=>'double','dateTime'=>'string',
179 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
180 'http://www.w3.org/1999/XMLSchema' => array(
181 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
182 'float'=>'double','dateTime'=>'string',
183 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
184 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
185 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
186 'http://xml.apache.org/xml-soap' => array('Map')
187 );
188
189 /**
190 * XML entities to convert
191 *
192 * @var array
193 * @access public
194 * @deprecated
195 * @see expandEntities
196 */
197 var $xmlEntities = array('quot' => '"','amp' => '&',
198 'lt' => '<','gt' => '>','apos' => "'");
199
200 /**
201 * constructor
202 *
203 * @access public
204 */
205 function nusoap_base() {
206 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
207 }
208
209 /**
210 * gets the global debug level, which applies to future instances
211 *
212 * @return integer Debug level 0-9, where 0 turns off
213 * @access public
214 */
215 function getGlobalDebugLevel() {
216 return $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel;
217 }
218
219 /**
220 * sets the global debug level, which applies to future instances
221 *
222 * @param int $level Debug level 0-9, where 0 turns off
223 * @access public
224 */
225 function setGlobalDebugLevel($level) {
226 $GLOBALS['_transient']['static']['nusoap_base']->globalDebugLevel = $level;
227 }
228
229 /**
230 * gets the debug level for this instance
231 *
232 * @return int Debug level 0-9, where 0 turns off
233 * @access public
234 */
235 function getDebugLevel() {
236 return $this->debugLevel;
237 }
238
239 /**
240 * sets the debug level for this instance
241 *
242 * @param int $level Debug level 0-9, where 0 turns off
243 * @access public
244 */
245 function setDebugLevel($level) {
246 $this->debugLevel = $level;
247 }
248
249 /**
250 * adds debug data to the instance debug string with formatting
251 *
252 * @param string $string debug data
253 * @access private
254 */
255 function debug($string){
256 if ($this->debugLevel > 0) {
257 $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
258 }
259 }
260
261 /**
262 * adds debug data to the instance debug string without formatting
263 *
264 * @param string $string debug data
265 * @access public
266 */
267 function appendDebug($string){
268 if ($this->debugLevel > 0) {
269 // it would be nice to use a memory stream here to use
270 // memory more efficiently
271 $this->debug_str .= $string;
272 }
273 }
274
275 /**
276 * clears the current debug data for this instance
277 *
278 * @access public
279 */
280 function clearDebug() {
281 // it would be nice to use a memory stream here to use
282 // memory more efficiently
283 $this->debug_str = '';
284 }
285
286 /**
287 * gets the current debug data for this instance
288 *
289 * @return debug data
290 * @access public
291 */
292 function &getDebug() {
293 // it would be nice to use a memory stream here to use
294 // memory more efficiently
295 return $this->debug_str;
296 }
297
298 /**
299 * gets the current debug data for this instance as an XML comment
300 * this may change the contents of the debug data
301 *
302 * @return debug data as an XML comment
303 * @access public
304 */
305 function &getDebugAsXMLComment() {
306 // it would be nice to use a memory stream here to use
307 // memory more efficiently
308 while (strpos($this->debug_str, '--')) {
309 $this->debug_str = str_replace('--', '- -', $this->debug_str);
310 }
311 return "<!--\n" . $this->debug_str . "\n-->";
312 }
313
314 /**
315 * expands entities, e.g. changes '<' to '&lt;'.
316 *
317 * @param string $val The string in which to expand entities.
318 * @access private
319 */
320 function expandEntities($val) {
321 if ($this->charencoding) {
322 $val = str_replace('&', '&amp;', $val);
323 $val = str_replace("'", '&apos;', $val);
324 $val = str_replace('"', '&quot;', $val);
325 $val = str_replace('<', '&lt;', $val);
326 $val = str_replace('>', '&gt;', $val);
327 }
328 return $val;
329 }
330
331 /**
332 * returns error string if present
333 *
334 * @return mixed error string or false
335 * @access public
336 */
337 function getError(){
338 if($this->error_str != ''){
339 return $this->error_str;
340 }
341 return false;
342 }
343
344 /**
345 * sets error string
346 *
347 * @return boolean $string error string
348 * @access private
349 */
350 function setError($str){
351 $this->error_str = $str;
352 }
353
354 /**
355 * detect if array is a simple array or a struct (associative array)
356 *
357 * @param mixed $val The PHP array
358 * @return string (arraySimple|arrayStruct)
359 * @access private
360 */
361 function isArraySimpleOrStruct($val) {
362 $keyList = array_keys($val);
363 foreach ($keyList as $keyListValue) {
364 if (!is_int($keyListValue)) {
365 return 'arrayStruct';
366 }
367 }
368 return 'arraySimple';
369 }
370
371 /**
372 * serializes PHP values in accordance w/ section 5. Type information is
373 * not serialized if $use == 'literal'.
374 *
375 * @param mixed $val The value to serialize
376 * @param string $name The name (local part) of the XML element
377 * @param string $type The XML schema type (local part) for the element
378 * @param string $name_ns The namespace for the name of the XML element
379 * @param string $type_ns The namespace for the type of the element
380 * @param array $attributes The attributes to serialize as name=>value pairs
381 * @param string $use The WSDL "use" (encoded|literal)
382 * @return string The serialized element, possibly with child elements
383 * @access public
384 */
385 function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded'){
386 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use");
387 $this->appendDebug('value=' . $this->varDump($val));
388 $this->appendDebug('attributes=' . $this->varDump($attributes));
389
390 // RCHOI: serialize special array as repeated elements
391 if (is_object($val) && get_class($val) == 'repeatedelementsarray'){
392 return $val->serialize($use);
393 }
394
395 if(is_object($val) && get_class($val) == 'soapval'){
396 return $val->serialize($use);
397 }
398 // force valid name if necessary
399 if (is_numeric($name)) {
400 $name = '__numeric_' . $name;
401 } elseif (! $name) {
402 $name = 'noname';
403 }
404 // if name has ns, add ns prefix to name
405 $xmlns = '';
406 if($name_ns){
407 $prefix = 'nu'.rand(1000,9999);
408 $name = $prefix.':'.$name;
409 $xmlns .= " xmlns:$prefix=\"$name_ns\"";
410 }
411 // if type is prefixed, create type prefix
412 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
413 // need to fix this. shouldn't default to xsd if no ns specified
414 // w/o checking against typemap
415 $type_prefix = 'xsd';
416 } elseif($type_ns){
417 $type_prefix = 'ns'.rand(1000,9999);
418 $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
419 }
420 // serialize attributes if present
421 $atts = '';
422 if($attributes){
423 foreach($attributes as $k => $v){
424 $atts .= " $k=\"".$this->expandEntities($v).'"';
425 }
426 }
427 // serialize null value
428 if (is_null($val)) {
429 if ($use == 'literal') {
430 // TODO: depends on minOccurs
431 return "<$name$xmlns $atts/>";
432 } else {
433 if (isset($type) && isset($type_prefix)) {
434 $type_str = " xsi:type=\"$type_prefix:$type\"";
435 } else {
436 $type_str = '';
437 }
438 return "<$name$xmlns$type_str $atts xsi:nil=\"true\"/>";
439 }
440 }
441 // serialize if an xsd built-in primitive type
442 if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
443 if (is_bool($val)) {
444 if ($type == 'boolean') {
445 $val = $val ? 'true' : 'false';
446 } elseif (! $val) {
447 $val = 0;
448 }
449 } else if (is_string($val)) {
450 $val = $this->expandEntities($val);
451 }
452 if ($use == 'literal') {
453 return "<$name$xmlns $atts>$val</$name>";
454 } else {
455 return "<$name$xmlns $atts xsi:type=\"xsd:$type\">$val</$name>";
456 }
457 }
458 // detect type and serialize
459 $xml = '';
460 switch(true) {
461 case (is_bool($val) || $type == 'boolean'):
462 if ($type == 'boolean') {
463 $val = $val ? 'true' : 'false';
464 } elseif (! $val) {
465 $val = 0;
466 }
467 if ($use == 'literal') {
468 $xml .= "<$name$xmlns $atts>$val</$name>";
469 } else {
470 $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
471 }
472 break;
473 case (is_int($val) || is_long($val) || $type == 'int'):
474 if ($use == 'literal') {
475 $xml .= "<$name$xmlns $atts>$val</$name>";
476 } else {
477 $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
478 }
479 break;
480 case (is_float($val)|| is_double($val) || $type == 'float'):
481 if ($use == 'literal') {
482 $xml .= "<$name$xmlns $atts>$val</$name>";
483 } else {
484 $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
485 }
486 break;
487 case (is_string($val) || $type == 'string'):
488 $val = $this->expandEntities($val);
489 if ($use == 'literal') {
490 $xml .= "<$name$xmlns $atts>$val</$name>";
491 } else {
492 $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
493 }
494 break;
495 case is_object($val):
496 if (! $name) {
497 $name = get_class($val);
498 $this->debug("In serialize_val, used class name $name as element name");
499 } else {
500 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
501 }
502 foreach(get_object_vars($val) as $k => $v){
503 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
504 }
505 $xml .= '<'.$name.'>'.$pXml.'</'.$name.'>';
506 break;
507 break;
508 case (is_array($val) || $type):
509 // detect if struct or array
510 $valueType = $this->isArraySimpleOrStruct($val);
511 if($valueType=='arraySimple' || ereg('^ArrayOf',$type)){
512 $i = 0;
513 if(is_array($val) && count($val)> 0){
514 foreach($val as $v){
515 if(is_object($v) && get_class($v) == 'soapval'){
516 $tt_ns = $v->type_ns;
517 $tt = $v->type;
518 } elseif (is_array($v)) {
519 $tt = $this->isArraySimpleOrStruct($v);
520 } else {
521 $tt = gettype($v);
522 }
523 $array_types[$tt] = 1;
524 // TODO: for literal, the name should be $name
525 $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
526 ++$i;
527 }
528 if(count($array_types) > 1){
529 $array_typename = 'xsd:anyType';
530 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
531 if ($tt == 'integer') {
532 $tt = 'int';
533 }
534 $array_typename = 'xsd:'.$tt;
535 } elseif(isset($tt) && $tt == 'arraySimple'){
536 $array_typename = 'SOAP-ENC:Array';
537 } elseif(isset($tt) && $tt == 'arrayStruct'){
538 $array_typename = 'unnamed_struct_use_soapval';
539 } else {
540 // if type is prefixed, create type prefix
541 if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
542 $array_typename = 'xsd:' . $tt;
543 } elseif ($tt_ns) {
544 $tt_prefix = 'ns' . rand(1000, 9999);
545 $array_typename = "$tt_prefix:$tt";
546 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
547 } else {
548 $array_typename = $tt;
549 }
550 }
551 $array_type = $i;
552 if ($use == 'literal') {
553 $type_str = '';
554 } else if (isset($type) && isset($type_prefix)) {
555 $type_str = " xsi:type=\"$type_prefix:$type\"";
556 } else {
557 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
558 }
559 // empty array
560 } else {
561 if ($use == 'literal') {
562 $type_str = '';
563 } else if (isset($type) && isset($type_prefix)) {
564 $type_str = " xsi:type=\"$type_prefix:$type\"";
565 } else {
566 $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
567 }
568 }
569 // TODO: for array in literal, there is no wrapper here
570 $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
571 } else {
572 // got a struct
573 if(isset($type) && isset($type_prefix)){
574 $type_str = " xsi:type=\"$type_prefix:$type\"";
575 } else {
576 $type_str = '';
577 }
578 if ($use == 'literal') {
579 $xml .= "<$name$xmlns $atts>";
580 } else {
581 $xml .= "<$name$xmlns$type_str$atts>";
582 }
583 foreach($val as $k => $v){
584 // Apache Map
585 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
586 $xml .= '<item>';
587 $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
588 $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
589 $xml .= '</item>';
590 } else {
591 $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
592 }
593 }
594 $xml .= "</$name>";
595 }
596 break;
597 default:
598 $xml .= 'not detected, got '.gettype($val).' for '.$val;
599 break;
600 }
601 return $xml;
602 }
603
604 /**
605 * serializes a message
606 *
607 * @param string $body the XML of the SOAP body
608 * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers
609 * @param array $namespaces optional the namespaces used in generating the body and headers
610 * @param string $style optional (rpc|document)
611 * @param string $use optional (encoded|literal)
612 * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
613 * @return string the message
614 * @access public
615 */
616 function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
617 // TODO: add an option to automatically run utf8_encode on $body and $headers
618 // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
619 // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
620
621 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
622 $this->debug("headers:");
623 $this->appendDebug($this->varDump($headers));
624 $this->debug("namespaces:");
625 $this->appendDebug($this->varDump($namespaces));
626
627 // serialize namespaces
628 $ns_string = '';
629 foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
630 $ns_string .= " xmlns:$k=\"$v\"";
631 }
632 if($encodingStyle) {
633 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
634 }
635
636 // serialize headers
637 if($headers){
638 if (is_array($headers)) {
639 $xml = '';
640 foreach ($headers as $header) {
641 $xml .= $this->serialize_val($header, false, false, false, false, false, $use);
642 }
643 $headers = $xml;
644 $this->debug("In serializeEnvelope, serialzied array of headers to $headers");
645 }
646 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
647 }
648 // serialize envelope
649 return
650 '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
651 '<SOAP-ENV:Envelope'.$ns_string.">".
652 $headers.
653 "<SOAP-ENV:Body>".
654 $body.
655 "</SOAP-ENV:Body>".
656 "</SOAP-ENV:Envelope>";
657 }
658
659 /**
660 * formats a string to be inserted into an HTML stream
661 *
662 * @param string $str The string to format
663 * @return string The formatted string
664 * @access public
665 * @deprecated
666 */
667 function formatDump($str){
668 $str = htmlspecialchars($str);
669 return nl2br($str);
670 }
671
672 /**
673 * contracts (changes namespace to prefix) a qualified name
674 *
675 * @param string $qname qname
676 * @return string contracted qname
677 * @access private
678 */
679 function contractQname($qname){
680 // get element namespace
681 //$this->xdebug("Contract $qname");
682 if (strrpos($qname, ':')) {
683 // get unqualified name
684 $name = substr($qname, strrpos($qname, ':') + 1);
685 // get ns
686 $ns = substr($qname, 0, strrpos($qname, ':'));
687 $p = $this->getPrefixFromNamespace($ns);
688 if ($p) {
689 return $p . ':' . $name;
690 }
691 return $qname;
692 } else {
693 return $qname;
694 }
695 }
696
697 /**
698 * expands (changes prefix to namespace) a qualified name
699 *
700 * @param string $string qname
701 * @return string expanded qname
702 * @access private
703 */
704 function expandQname($qname){
705 // get element prefix
706 if(strpos($qname,':') && !ereg('^http://',$qname)){
707 // get unqualified name
708 $name = substr(strstr($qname,':'),1);
709 // get ns prefix
710 $prefix = substr($qname,0,strpos($qname,':'));
711 if(isset($this->namespaces[$prefix])){
712 return $this->namespaces[$prefix].':'.$name;
713 } else {
714 return $qname;
715 }
716 } else {
717 return $qname;
718 }
719 }
720
721 /**
722 * returns the local part of a prefixed string
723 * returns the original string, if not prefixed
724 *
725 * @param string $str The prefixed string
726 * @return string The local part
727 * @access public
728 */
729 function getLocalPart($str){
730 if($sstr = strrchr($str,':')){
731 // get unqualified name
732 return substr( $sstr, 1 );
733 } else {
734 return $str;
735 }
736 }
737
738 /**
739 * returns the prefix part of a prefixed string
740 * returns false, if not prefixed
741 *
742 * @param string $str The prefixed string
743 * @return mixed The prefix or false if there is no prefix
744 * @access public
745 */
746 function getPrefix($str){
747 if($pos = strrpos($str,':')){
748 // get prefix
749 return substr($str,0,$pos);
750 }
751 return false;
752 }
753
754 /**
755 * pass it a prefix, it returns a namespace
756 *
757 * @param string $prefix The prefix
758 * @return mixed The namespace, false if no namespace has the specified prefix
759 * @access public
760 */
761 function getNamespaceFromPrefix($prefix){
762 if (isset($this->namespaces[$prefix])) {
763 return $this->namespaces[$prefix];
764 }
765 //$this->setError("No namespace registered for prefix '$prefix'");
766 return false;
767 }
768
769 /**
770 * returns the prefix for a given namespace (or prefix)
771 * or false if no prefixes registered for the given namespace
772 *
773 * @param string $ns The namespace
774 * @return mixed The prefix, false if the namespace has no prefixes
775 * @access public
776 */
777 function getPrefixFromNamespace($ns) {
778 foreach ($this->namespaces as $p => $n) {
779 if ($ns == $n || $ns == $p) {
780 $this->usedNamespaces[$p] = $n;
781 return $p;
782 }
783 }
784 return false;
785 }
786
787 /**
788 * returns the time in ODBC canonical form with microseconds
789 *
790 * @return string The time in ODBC canonical form with microseconds
791 * @access public
792 */
793 function getmicrotime() {
794 if (function_exists('gettimeofday')) {
795 $tod = gettimeofday();
796 $sec = $tod['sec'];
797 $usec = $tod['usec'];
798 } else {
799 $sec = time();
800 $usec = 0;
801 }
802 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
803 }
804
805 /**
806 * Returns a string with the output of var_dump
807 *
808 * @param mixed $data The variable to var_dump
809 * @return string The output of var_dump
810 * @access public
811 */
812 function varDump($data) {
813 ob_start();
814 var_dump($data);
815 $ret_val = ob_get_contents();
816 ob_end_clean();
817 return $ret_val;
818 }
819 }
820
821 // XML Schema Datatype Helper Functions
822
823 //xsd:dateTime helpers
824
825 /**
826 * convert unix timestamp to ISO 8601 compliant date string
827 *
828 * @param string $timestamp Unix time stamp
829 * @access public
830 */
831 function timestamp_to_iso8601($timestamp,$utc=true){
832 $datestr = date('Y-m-d\TH:i:sO',$timestamp);
833 if($utc){
834 $eregStr =
835 '([0-9]{4})-'. // centuries & years CCYY-
836 '([0-9]{2})-'. // months MM-
837 '([0-9]{2})'. // days DD
838 'T'. // separator T
839 '([0-9]{2}):'. // hours hh:
840 '([0-9]{2}):'. // minutes mm:
841 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
842 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
843
844 if(ereg($eregStr,$datestr,$regs)){
845 return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
846 }
847 return false;
848 } else {
849 return $datestr;
850 }
851 }
852
853 /**
854 * convert ISO 8601 compliant date string to unix timestamp
855 *
856 * @param string $datestr ISO 8601 compliant date string
857 * @access public
858 */
859 function iso8601_to_timestamp($datestr){
860 $eregStr =
861 '([0-9]{4})-'. // centuries & years CCYY-
862 '([0-9]{2})-'. // months MM-
863 '([0-9]{2})'. // days DD
864 'T'. // separator T
865 '([0-9]{2}):'. // hours hh:
866 '([0-9]{2}):'. // minutes mm:
867 '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
868 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'; // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
869 if(ereg($eregStr,$datestr,$regs)){
870 // not utc
871 if($regs[8] != 'Z'){
872 $op = substr($regs[8],0,1);
873 $h = substr($regs[8],1,2);
874 $m = substr($regs[8],strlen($regs[8])-2,2);
875 if($op == '-'){
876 $regs[4] = $regs[4] + $h;
877 $regs[5] = $regs[5] + $m;
878 } elseif($op == '+'){
879 $regs[4] = $regs[4] - $h;
880 $regs[5] = $regs[5] - $m;
881 }
882 }
883 return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
884 } else {
885 return false;
886 }
887 }
888
889 /**
890 * sleeps some number of microseconds
891 *
892 * @param string $usec the number of microseconds to sleep
893 * @access public
894 * @deprecated
895 */
896 function usleepWindows($usec)
897 {
898 $start = gettimeofday();
899
900 do
901 {
902 $stop = gettimeofday();
903 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
904 + $stop['usec'] - $start['usec'];
905 }
906 while ($timePassed < $usec);
907 }
908
909 ?><?php
910
911
912
913 /**
914 * Contains information for a SOAP fault.
915 * Mainly used for returning faults from deployed functions
916 * in a server instance.
917 * @author Dietrich Ayala <dietrich@ganx4.com>
918 * @version $Id: nusoap.php,v 1.4 2005/12/07 06:12:25 ryankicks Exp $
919 * @access public
920 */
921 class soap_fault extends nusoap_base {
922 /**
923 * The fault code (client|server)
924 * @var string
925 * @access private
926 */
927 var $faultcode;
928 /**
929 * The fault actor
930 * @var string
931 * @access private
932 */
933 var $faultactor;
934 /**
935 * The fault string, a description of the fault
936 * @var string
937 * @access private
938 */
939 var $faultstring;
940 /**
941 * The fault detail, typically a string or array of string
942 * @var mixed
943 * @access private
944 */
945 var $faultdetail;
946
947 /**
948 * constructor
949 *
950 * @param string $faultcode (client | server)
951 * @param string $faultactor only used when msg routed between multiple actors
952 * @param string $faultstring human readable error message
953 * @param mixed $faultdetail detail, typically a string or array of string
954 */
955 function soap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
956 parent::nusoap_base();
957 $this->faultcode = $faultcode;
958 $this->faultactor = $faultactor;
959 $this->faultstring = $faultstring;
960 $this->faultdetail = $faultdetail;
961 }
962
963 /**
964 * serialize a fault
965 *
966 * @return string The serialization of the fault instance.
967 * @access public
968 */
969 function serialize(){
970 $ns_string = '';
971 foreach($this->namespaces as $k => $v){
972 $ns_string .= "\n xmlns:$k=\"$v\"";
973 }
974 $return_msg =
975 '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
976 '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
977 '<SOAP-ENV:Body>'.
978 '<SOAP-ENV:Fault>'.
979 $this->serialize_val($this->faultcode, 'faultcode').
980 $this->serialize_val($this->faultactor, 'faultactor').
981 $this->serialize_val($this->faultstring, 'faultstring').
982 $this->serialize_val($this->faultdetail, 'detail').
983 '</SOAP-ENV:Fault>'.
984 '</SOAP-ENV:Body>'.
985 '</SOAP-ENV:Envelope>';
986 return $return_msg;
987 }
988 }
989
990
991
992 ?><?php
993
994
995
996 /**
997 * parses an XML Schema, allows access to it's data, other utility methods
998 * no validation... yet.
999 * very experimental and limited. As is discussed on XML-DEV, I'm one of the people
1000 * that just doesn't have time to read the spec(s) thoroughly, and just have a couple of trusty
1001 * tutorials I refer to :)
1002 *
1003 * @author Dietrich Ayala <dietrich@ganx4.com>
1004 * @version $Id: nusoap.php,v 1.4 2005/12/07 06:12:25 ryankicks Exp $
1005 * @access public
1006 */
1007 class XMLSchema extends nusoap_base {
1008
1009 // files
1010 var $schema = '';
1011 var $xml = '';
1012 // namespaces
1013 var $enclosingNamespaces;
1014 // schema info
1015 var $schemaInfo = array();
1016 var $schemaTargetNamespace = '';
1017 // types, elements, attributes defined by the schema
1018 var $attributes = array();
1019 var $complexTypes = array();
1020 var $complexTypeStack = array();
1021 var $currentComplexType = null;
1022 var $elements = array();
1023 var $elementStack = array();
1024 var $currentElement = null;
1025 var $simpleTypes = array();
1026 var $simpleTypeStack = array();
1027 var $currentSimpleType = null;
1028 // imports
1029 var $imports = array();
1030 // parser vars
1031 var $parser;
1032 var $position = 0;
1033 var $depth = 0;
1034 var $depth_array = array();
1035 var $message = array();
1036 var $defaultNamespace = array();
1037
1038 /**
1039 * constructor
1040 *
1041 * @param string $schema schema document URI
1042 * @param string $xml xml document URI
1043 * @param string $namespaces namespaces defined in enclosing XML
1044 * @access public
1045 */
1046 function XMLSchema($schema='',$xml='',$namespaces=array()){
1047 parent::nusoap_base();
1048 $this->debug('xmlschema class instantiated, inside constructor');
1049 // files
1050 $this->schema = $schema;
1051 $this->xml = $xml;
1052
1053 // namespaces
1054 $this->enclosingNamespaces = $namespaces;
1055 $this->namespaces = array_merge($this->namespaces, $namespaces);
1056
1057 // parse schema file
1058 if($schema != ''){
1059 $this->debug('initial schema file: '.$schema);
1060 $this->parseFile($schema, 'schema');
1061 }
1062
1063 // parse xml file
1064 if($xml != ''){
1065 $this->debug('initial xml file: '.$xml);
1066 $this->parseFile($xml, 'xml');
1067 }
1068
1069 }
1070
1071 /**
1072 * parse an XML file
1073 *
1074 * @param string $xml, path/URL to XML file
1075 * @param string $type, (schema | xml)
1076 * @return boolean
1077 * @access public
1078 */
1079 function parseFile($xml,$type){
1080 // parse xml file
1081 if($xml != ""){
1082 $xmlStr = @join("",@file($xml));
1083 if($xmlStr == ""){
1084 $msg = 'Error reading XML from '.$xml;
1085 $this->setError($msg);
1086 $this->debug($msg);
1087 return false;
1088 } else {
1089 $this->debug("parsing $xml");
1090 $this->parseString($xmlStr,$type);
1091 $this->debug("done parsing $xml");
1092 return true;
1093 }
1094 }
1095 return false;
1096 }
1097
1098 /**
1099 * parse an XML string
1100 *
1101 * @param string $xml path or URL
1102 * @param string $type, (schema|xml)
1103 * @access private
1104 */
1105 function parseString($xml,$type){
1106 // parse xml string
1107 if($xml != ""){
1108
1109 // Create an XML parser.
1110 $this->parser = xml_parser_create();
1111 // Set the options for parsing the XML data.
1112 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1113
1114 // Set the object for the parser.
1115 xml_set_object($this->parser, $this);
1116
1117 // Set the element handlers for the parser.
1118 if($type == "schema"){
1119 xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1120 xml_set_character_data_handler($this->parser,'schemaCharacterData');
1121 } elseif($type == "xml"){
1122 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1123 xml_set_character_data_handler($this->parser,'xmlCharacterData');
1124 }
1125
1126 // Parse the XML file.
1127 if(!xml_parse($this->parser,$xml,true)){
1128 // Display an error message.
1129 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1130 xml_get_current_line_number($this->parser),
1131 xml_error_string(xml_get_error_code($this->parser))
1132 );
1133 $this->debug($errstr);
1134 $this->debug("XML payload:\n" . $xml);
1135 $this->setError($errstr);
1136 }
1137
1138 xml_parser_free($this->parser);
1139 } else{
1140 $this->debug('no xml passed to parseString()!!');
1141 $this->setError('no xml passed to parseString()!!');
1142 }
1143 }
1144
1145 /**
1146 * start-element handler
1147 *
1148 * @param string $parser XML parser object
1149 * @param string $name element name
1150 * @param string $attrs associative array of attributes
1151 * @access private
1152 */
1153 function schemaStartElement($parser, $name, $attrs) {
1154
1155 // position in the total number of elements, starting from 0
1156 $pos = $this->position++;
1157 $depth = $this->depth++;
1158 // set self as current value for this depth
1159 $this->depth_array[$depth] = $pos;
1160 $this->message[$pos] = array('cdata' => '');
1161 if ($depth > 0) {
1162 $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1163 } else {
1164 $this->defaultNamespace[$pos] = false;
1165 }
1166
1167 // get element prefix
1168 if($prefix = $this->getPrefix($name)){
1169 // get unqualified name
1170 $name = $this->getLocalPart($name);
1171 } else {
1172 $prefix = '';
1173 }
1174
1175 // loop thru attributes, expanding, and registering namespace declarations
1176 if(count($attrs) > 0){
1177 foreach($attrs as $k => $v){
1178 // if ns declarations, add to class level array of valid namespaces
1179 if(ereg("^xmlns",$k)){
1180 //$this->xdebug("$k: $v");
1181 //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1182 if($ns_prefix = substr(strrchr($k,':'),1)){
1183 //$this->xdebug("Add namespace[$ns_prefix] = $v");
1184 $this->namespaces[$ns_prefix] = $v;
1185 } else {
1186 $this->defaultNamespace[$pos] = $v;
1187 if (! $this->getPrefixFromNamespace($v)) {
1188 $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1189 }
1190 }
1191 if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1192 $this->XMLSchemaVersion = $v;
1193 $this->namespaces['xsi'] = $v.'-instance';
1194 }
1195 }
1196 }
1197 foreach($attrs as $k => $v){
1198 // expand each attribute
1199 $k = strpos($k,':') ? $this->expandQname($k) : $k;
1200 $v = strpos($v,':') ? $this->expandQname($v) : $v;
1201 $eAttrs[$k] = $v;
1202 }
1203 $attrs = $eAttrs;
1204 } else {
1205 $attrs = array();
1206 }
1207 // find status, register data
1208 switch($name){
1209 case 'all': // (optional) compositor content for a complexType
1210 case 'choice':
1211 case 'group':
1212 case 'sequence':
1213 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1214 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1215 //if($name == 'all' || $name == 'sequence'){
1216 // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1217 //}
1218 break;
1219 case 'attribute': // complexType attribute
1220 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1221 $this->xdebug("parsing attribute:");
1222 $this->appendDebug($this->varDump($attrs));
1223 if (!isset($attrs['form'])) {
1224 $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1225 }
1226 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1227 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1228 if (!strpos($v, ':')) {
1229 // no namespace in arrayType attribute value...
1230 if ($this->defaultNamespace[$pos]) {
1231 // ...so use the default
1232 $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1233 }
1234 }
1235 }
1236 if(isset($attrs['name'])){
1237 $this->attributes[$attrs['name']] = $attrs;
1238 $aname = $attrs['name'];
1239 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1240 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1241 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1242 } else {
1243 $aname = '';
1244 }
1245 } elseif(isset($attrs['ref'])){
1246 $aname = $attrs['ref'];
1247 $this->attributes[$attrs['ref']] = $attrs;
1248 }
1249
1250 if($this->currentComplexType){ // This should *always* be
1251 $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1252 }
1253 // arrayType attribute
1254 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
1255 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1256 $prefix = $this->getPrefix($aname);
1257 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){