]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/nusoap/nusoap.php
Release 6.2.0
[Github/sugarcrm.git] / include / nusoap / nusoap.php
1 <?php
2
3 /*
4 Modification information for LGPL compliance
5
6 commit af784931b8ab2263776badac5ac3fc4776c9cd61
7 Author: Stanislav Malyshev <smalyshev@gmail.com>
8 Date:   Thu Feb 17 18:09:12 2011 -0800
9
10     bug 34897 - remove characters that aren't valid in XML
11
12 commit 1767411d701b8216cc5e043888fd1337e2eca315
13 Author: Stanislav Malyshev <smalyshev@gmail.com>
14 Date:   Fri Jan 7 12:19:10 2011 -0800
15
16     conserve memory when no debug is enabled
17
18 commit 843510ebf455368865302a05b9d5041815a32c23
19 Author: John Mertic <jmertic@sugarcrm.com>
20 Date:   Wed Nov 17 13:18:09 2010 -0500
21
22     Bug 40716 - Fix WSDL validation problem by removing hardcoded schemaLocation attribute for the <xsd:import> tag.
23
24 commit 2bd12c02078f3e291bd9c1e76179a144c788ce97
25 Author: Collin Lee <clee@Collin-Lee-MacBook-Pro.local>
26 Date:   Fri Oct 22 16:37:42 2010 -0400
27
28     Bug: 39937
29
30     We traced the error to a combination of the new Hoovers' WSDL + the nusoapclient code that winds up improperly encoding the parameter elem
31 ents (this is because the namespace specified for the soap call did not match that declared in the WSDL). Made changes to nusoap.php so that w
32 e may manually set a payload XML portion that will not apply the namespace encoding to the parameters. Fixed unit tests to reflect the changes
33  and also re-enabled those for Hoovers that were marked skipped.
34
35 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
36     bug 40066
37
38 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
39     Merging with maint_6_0_1 (svn merge -r 58250:58342)
40
41 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
42     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
43
44 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
45     fix SOAP calls with no parameters
46
47 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
48
49 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
50
51 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
52
53 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
54
55 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
56
57 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
58
59 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
60
61 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
62 - Changing all ereg function to either preg or simple string based ones
63 - No more references to magic quotes.
64 - Change all the session_unregister() functions to just unset() the correct session variable instead.
65
66 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
67
68 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
69
70 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
71
72 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
73
74 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
75
76 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
77
78 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
79
80 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
81
82 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
83 Touched:
84 - data/SugarBean.php
85 - include/domit/php_http_client_generic.php
86 - include/domit/php_http_connector.php
87 - include/domit/testing_domit.php
88 - include/domit/xml_domit_getelementsbypath.php
89 - include/domit/xml_domit_lite_parser.php
90 - include/domit/xml_domit_nodemaps.php
91 - include/domit/xml_domit_parser.php
92 - include/domit/xml_domit_shared.php
93 - include/generic/SugarWidgets/SugarWidgetField.php
94 - include/generic/SugarWidgets/SugarWidgetReportField.php
95 - include/ListView/ProcessView.php
96 - include/nusoap/class.soapclient.php
97 - include/nusoap/nusoap.php
98 - include/nusoap/nusoapmime.php
99 - include/Pear/HTML_Safe/Safe.php
100 - include/Pear/XML_HTMLSax3/HTMLSax3.php
101 - modules/Administration/RebuildWorkFlow.php
102 - modules/Expressions/RelateSelector.php
103 - modules/Reports/templates/templates_reports.php
104 - modules/WorkFlow/Delete.php
105 - modules/WorkFlow/Save.php
106 - modules/WorkFlow/SaveSequence.php
107 - modules/WorkFlow/WorkFlow.php
108 - modules/WorkFlowActionShells/CreateStep1.php
109 - modules/WorkFlowActionShells/CreateStep2.php
110 - modules/WorkFlowActionShells/Save.php
111 - modules/WorkFlowActionShells/WorkFlowActionShell.php
112 - modules/WorkFlowAlerts/Save.php
113 - modules/WorkFlowAlerts/WorkFlowAlert.php
114 - modules/WorkFlowAlertShells/DetailView.php
115 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
116 - modules/WorkFlowTriggerShells/CreateStep1.php
117 - modules/WorkFlowTriggerShells/CreateStepFilter.php
118 - modules/WorkFlowTriggerShells/SaveFilter.php
119 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
120 - soap/SoapHelperFunctions.php
121 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
122 - test/simpletest/browser.php
123 - test/simpletest/default_reporter.php
124 - test/simpletest/detached.php
125 - test/simpletest/eclipse.php
126 - test/simpletest/expectation.php
127 - test/simpletest/extensions/pear_test_case.php
128 - test/simpletest/form.php
129 - test/simpletest/http.php
130 - test/simpletest/mock_objects.php
131 - test/simpletest/page.php
132 - test/simpletest/parser.php
133 - test/simpletest/remote.php
134 - test/simpletest/shell_tester.php
135 - test/simpletest/simple_test.php
136 - test/simpletest/simpletest.php
137 - test/simpletest/test/acceptance_test.php
138 - test/simpletest/test/adapter_test.php
139 - test/simpletest/test/authentication_test.php
140 - test/simpletest/test/browser_test.php
141 - test/simpletest/test/collector_test.php
142 - test/simpletest/test/compatibility_test.php
143 - test/simpletest/test/detached_test.php
144 - test/simpletest/test/eclipse_test.php
145 - test/simpletest/test/encoding_test.php
146 - test/simpletest/test/errors_test.php
147 - test/simpletest/test/expectation_test.php
148 - test/simpletest/test/form_test.php
149 - test/simpletest/test/frames_test.php
150 - test/simpletest/test/http_test.php
151 - test/simpletest/test/live_test.php
152 - test/simpletest/test/mock_objects_test.php
153 - test/simpletest/test/page_test.php
154 - test/simpletest/test/parse_error_test.php
155 - test/simpletest/test/parser_test.php
156 - test/simpletest/test/remote_test.php
157 - test/simpletest/test/shell_test.php
158 - test/simpletest/test/shell_tester_test.php
159 - test/simpletest/test/simpletest_test.php
160 - test/simpletest/test/site/page_request.php
161 - test/simpletest/test/tag_test.php
162 - test/simpletest/test/unit_tester_test.php
163 - test/simpletest/test/user_agent_test.php
164 - test/simpletest/test/visual_test.php
165 - test/simpletest/test/xml_test.php
166 - test/simpletest/test_case.php
167 - test/simpletest/ui/array_reporter/test.php
168 - test/simpletest/ui/recorder/test.php
169 - test/simpletest/unit_tester.php
170 - test/simpletest/url.php
171 - test/simpletest/user_agent.php
172 - test/simpletest/web_tester.php
173 - test/spikephpcoverage/src/PEAR.php
174 - test/spikephpcoverage/src/util/Utility.php
175 - test/spikephpcoverage/src/XML/Parser.php
176 - test/spikephpcoverage/src/XML/Parser/Simple.php
177 - test/test_utilities/SugarTest_SimpleBrowser.php
178
179 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
180
181 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
182
183 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
184
185 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
186
187 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
188
189 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
190
191 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
192
193 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
194
195 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
196
197 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
198
199 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
200
201 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
202
203 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
204
205 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
206
207 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
208
209 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
210
211 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
212
213 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
214
215 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
216
217 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
218
219 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
220
221 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
222
223 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
224
225 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
226
227
228 */
229
230
231 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
232
233 /*
234 $Id: nusoap.php 58622 2010-10-23 01:18:59Z engsvnbuild $
235
236 NuSOAP - Web Services Toolkit for PHP
237
238 Copyright (c) 2002 NuSphere Corporation
239
240 This library is free software; you can redistribute it and/or
241 modify it under the terms of the GNU Lesser General Public
242 License as published by the Free Software Foundation; either
243 version 2.1 of the License, or (at your option) any later version.
244 n
245 This library is distributed in the hope that it will be useful,
246 but WITHOUT ANY WARRANTY; without even the implied warranty of
247 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
248 Lesser General Public License for more details.
249
250 You should have received a copy of the GNU Lesser General Public
251 License along with this library; if not, write to the Free Software
252 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
253
254 The NuSOAP project home is:
255 http://sourceforge.net/projects/nusoap/
256
257 The primary support for NuSOAP is the Help forum on the project home page.
258
259 If you have any questions or comments, please email:
260
261 Dietrich Ayala
262 dietrich@ganx4.com
263 http://dietrich.ganx4.com/nusoap
264
265 NuSphere Corporation
266 http://www.nusphere.com
267
268 */
269
270 /*
271  *      Some of the standards implmented in whole or part by NuSOAP:
272  *
273  *      SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
274  *      WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
275  *      SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
276  *      XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
277  *      Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
278  *      XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
279  *      RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
280  *      RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
281  *      RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
282  */
283
284 /* load classes
285
286 // necessary classes
287 require_once('class.soapclient.php');
288 require_once('class.soap_val.php');
289 require_once('class.soap_parser.php');
290 require_once('class.soap_fault.php');
291
292 // transport classes
293 require_once('class.soap_transport_http.php');
294
295 // optional add-on classes
296 require_once('class.xmlschema.php');
297 require_once('class.wsdl.php');
298
299 // server class
300 require_once('class.soap_server.php');*/
301
302 // class variable emulation
303 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
304 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 0;
305
306 /**
307 *
308 * nusoap_base
309 *
310 * @author   Dietrich Ayala <dietrich@ganx4.com>
311 * @author   Scott Nichol <snichol@users.sourceforge.net>
312
313 * @access   public
314 */
315 class nusoap_base {
316         /**
317          * Identification for HTTP headers.
318          *
319          * @var string
320          * @access private
321          */
322         var $title = 'NuSOAP';
323         /**
324          * Version for HTTP headers.
325          *
326          * @var string
327          * @access private
328          */
329         var $version = '0.9.5';
330         /**
331          * CVS revision for HTTP headers.
332          *
333          * @var string
334          * @access private
335          */
336         var $revision = '$Revision: 58622 $';
337     /**
338      * Current error string (manipulated by getError/setError)
339          *
340          * @var string
341          * @access private
342          */
343         var $error_str = '';
344     /**
345      * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
346          *
347          * @var string
348          * @access private
349          */
350     var $debug_str = '';
351     /**
352          * toggles automatic encoding of special characters as entities
353          * (should always be true, I think)
354          *
355          * @var boolean
356          * @access private
357          */
358         var $charencoding = true;
359         /**
360          * the debug level for this instance
361          *
362          * @var integer
363          * @access private
364          */
365         var $debugLevel;
366
367     /**
368         * set schema version
369         *
370         * @var      string
371         * @access   public
372         */
373         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
374
375     /**
376         * charset encoding for outgoing messages
377         *
378         * @var      string
379         * @access   public
380         */
381     //var $soap_defencoding = 'ISO-8859-1';
382         var $soap_defencoding = 'UTF-8';
383
384         /**
385         * namespaces in an array of prefix => uri
386         *
387         * this is "seeded" by a set of constants, but it may be altered by code
388         *
389         * @var      array
390         * @access   public
391         */
392         var $namespaces = array(
393                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
394                 'xsd' => 'http://www.w3.org/2001/XMLSchema',
395                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
396                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
397                 );
398
399         /**
400         * namespaces used in the current context, e.g. during serialization
401         *
402         * @var      array
403         * @access   private
404         */
405         var $usedNamespaces = array();
406
407         /**
408         * XML Schema types in an array of uri => (array of xml type => php type)
409         * is this legacy yet?
410         * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
411         * @var      array
412         * @access   public
413         */
414         var $typemap = array(
415         'http://www.w3.org/2001/XMLSchema' => array(
416                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
417                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
418                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
419                 // abstract "any" types
420                 'anyType'=>'string','anySimpleType'=>'string',
421                 // derived datatypes
422                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
423                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
424                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
425                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
426         'http://www.w3.org/2000/10/XMLSchema' => array(
427                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
428                 'float'=>'double','dateTime'=>'string',
429                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
430         'http://www.w3.org/1999/XMLSchema' => array(
431                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
432                 'float'=>'double','dateTime'=>'string',
433                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
434         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
435         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
436     'http://xml.apache.org/xml-soap' => array('Map')
437         );
438
439         /**
440         * XML entities to convert
441         *
442         * @var      array
443         * @access   public
444         * @deprecated
445         * @see  expandEntities
446         */
447         var $xmlEntities = array('quot' => '"','amp' => '&',
448                 'lt' => '<','gt' => '>','apos' => "'");
449
450         /**
451          * Payload override
452          * This is to allows us to override the payload to resolve issues where we need to take
453          * control of the xml content
454          * @var string
455          * @access public
456          *
457          */
458         var $payloadOverride;
459
460         /**
461         * constructor
462         *
463         * @access       public
464         */
465         function nusoap_base() {
466                 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
467         }
468
469         /**
470         * gets the global debug level, which applies to future instances
471         *
472         * @return       integer Debug level 0-9, where 0 turns off
473         * @access       public
474         */
475         function getGlobalDebugLevel() {
476                 return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
477         }
478
479         /**
480         * sets the global debug level, which applies to future instances
481         *
482         * @param        int     $level  Debug level 0-9, where 0 turns off
483         * @access       public
484         */
485         function setGlobalDebugLevel($level) {
486                 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
487         }
488
489         /**
490         * gets the debug level for this instance
491         *
492         * @return       int     Debug level 0-9, where 0 turns off
493         * @access       public
494         */
495         function getDebugLevel() {
496                 return $this->debugLevel;
497         }
498
499         /**
500         * sets the debug level for this instance
501         *
502         * @param        int     $level  Debug level 0-9, where 0 turns off
503         * @access       public
504         */
505         function setDebugLevel($level) {
506                 $this->debugLevel = $level;
507         }
508
509         /**
510         * adds debug data to the instance debug string with formatting
511         *
512         * @param    string $string debug data
513         * @access   private
514         */
515         function debug($string){
516                 if ($this->debugLevel > 0) {
517                         $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
518                 }
519         }
520
521         /**
522         * adds debug data to the instance debug string without formatting
523         *
524         * @param    string $string debug data
525         * @access   public
526         */
527         function appendDebug($string){
528                 if ($this->debugLevel > 0) {
529                         // it would be nice to use a memory stream here to use
530                         // memory more efficiently
531                         $this->debug_str .= $string;
532                 }
533         }
534
535         /**
536         * clears the current debug data for this instance
537         *
538         * @access   public
539         */
540         function clearDebug() {
541                 // it would be nice to use a memory stream here to use
542                 // memory more efficiently
543                 $this->debug_str = '';
544         }
545
546         /**
547         * gets the current debug data for this instance
548         *
549         * @return   debug data
550         * @access   public
551         */
552         function &getDebug() {
553                 // it would be nice to use a memory stream here to use
554                 // memory more efficiently
555                 return $this->debug_str;
556         }
557
558         /**
559         * gets the current debug data for this instance as an XML comment
560         * this may change the contents of the debug data
561         *
562         * @return   debug data as an XML comment
563         * @access   public
564         */
565         function &getDebugAsXMLComment() {
566                 // it would be nice to use a memory stream here to use
567                 // memory more efficiently
568                 while (strpos($this->debug_str, '--')) {
569                         $this->debug_str = str_replace('--', '- -', $this->debug_str);
570                 }
571                 $ret = "<!--\n" . $this->debug_str . "\n-->";
572         return $ret;
573         }
574
575         /**
576         * expands entities, e.g. changes '<' to '&lt;'.
577         *
578         * @param        string  $val    The string in which to expand entities.
579         * @access       private
580         */
581         function expandEntities($val) {
582                 if ($this->charencoding) {
583                 $val = htmlspecialchars($val, ENT_QUOTES, $this->soap_defencoding);
584                 // XML 1.0 doesn't allow those...
585                 $val = preg_replace("/([\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F])/", '', $val);
586             }
587             return $val;
588         }
589
590         /**
591         * returns error string if present
592         *
593         * @return   mixed error string or false
594         * @access   public
595         */
596         function getError(){
597                 if($this->error_str != ''){
598                         return $this->error_str;
599                 }
600                 return false;
601         }
602
603         /**
604         * sets error string
605         *
606         * @return   boolean $string error string
607         * @access   private
608         */
609         function setError($str){
610                 $this->error_str = $str;
611         }
612
613         /**
614         * detect if array is a simple array or a struct (associative array)
615         *
616         * @param        mixed   $val    The PHP array
617         * @return       string  (arraySimple|arrayStruct)
618         * @access       private
619         */
620         function isArraySimpleOrStruct($val) {
621         $keyList = array_keys($val);
622                 foreach ($keyList as $keyListValue) {
623                         if (!is_int($keyListValue)) {
624                                 return 'arrayStruct';
625                         }
626                 }
627                 return 'arraySimple';
628         }
629
630         /**
631         * serializes PHP values in accordance w/ section 5. Type information is
632         * not serialized if $use == 'literal'.
633         *
634         * @param        mixed   $val    The value to serialize
635         * @param        string  $name   The name (local part) of the XML element
636         * @param        string  $type   The XML schema type (local part) for the element
637         * @param        string  $name_ns        The namespace for the name of the XML element
638         * @param        string  $type_ns        The namespace for the type of the element
639         * @param        array   $attributes     The attributes to serialize as name=>value pairs
640         * @param        string  $use    The WSDL "use" (encoded|literal)
641         * @param        boolean $soapval        Whether this is called from soapval.
642         * @return       string  The serialized element, possibly with child elements
643     * @access   public
644         */
645         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
646                 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
647                 $this->appendDebug('value=' . $this->varDump($val));
648                 $this->appendDebug('attributes=' . $this->varDump($attributes));
649
650         if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
651                 $this->debug("serialize_val: serialize soapval");
652                 $xml = $val->serialize($use);
653                         $this->appendDebug($val->getDebug());
654                         $val->clearDebug();
655                         $this->debug("serialize_val of soapval returning $xml");
656                         return $xml;
657         }
658                 // force valid name if necessary
659                 if (is_numeric($name)) {
660                         $name = '__numeric_' . $name;
661                 } elseif (! $name) {
662                         $name = 'noname';
663                 }
664                 // if name has ns, add ns prefix to name
665                 $xmlns = '';
666         if($name_ns){
667                         $prefix = 'nu'.rand(1000,9999);
668                         $name = $prefix.':'.$name;
669                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";
670                 }
671                 // if type is prefixed, create type prefix
672                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
673                         // need to fix this. shouldn't default to xsd if no ns specified
674                     // w/o checking against typemap
675                         $type_prefix = 'xsd';
676                 } elseif($type_ns){
677                         $type_prefix = 'ns'.rand(1000,9999);
678                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
679                 }
680                 // serialize attributes if present
681                 $atts = '';
682                 if($attributes){
683                         foreach($attributes as $k => $v){
684                                 $atts .= " $k=\"".$this->expandEntities($v).'"';
685                         }
686                 }
687                 // serialize null value
688                 if (is_null($val)) {
689                 $this->debug("serialize_val: serialize null");
690                         if ($use == 'literal') {
691                                 // TODO: depends on minOccurs
692                                 $xml = "<$name$xmlns$atts/>";
693                                 $this->debug("serialize_val returning $xml");
694                         return $xml;
695                 } else {
696                                 if (isset($type) && isset($type_prefix)) {
697                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
698                                 } else {
699                                         $type_str = '';
700                                 }
701                                 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
702                                 $this->debug("serialize_val returning $xml");
703                         return $xml;
704                 }
705                 }
706         // serialize if an xsd built-in primitive type
707         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
708                 $this->debug("serialize_val: serialize xsd built-in primitive type");
709                 if (is_bool($val)) {
710                         if ($type == 'boolean') {
711                                 $val = $val ? 'true' : 'false';
712                         } elseif (! $val) {
713                                 $val = 0;
714                         }
715                         } else if (is_string($val)) {
716                                 $val = $this->expandEntities($val);
717                         }
718                         if ($use == 'literal') {
719                                 $xml = "<$name$xmlns$atts>$val</$name>";
720                                 $this->debug("serialize_val returning $xml");
721                         return $xml;
722                 } else {
723                                 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
724                                 $this->debug("serialize_val returning $xml");
725                         return $xml;
726                 }
727         }
728                 // detect type and serialize
729                 $xml = '';
730                 switch(true) {
731                         case (is_bool($val) || $type == 'boolean'):
732                                 $this->debug("serialize_val: serialize boolean");
733                         if ($type == 'boolean') {
734                                 $val = $val ? 'true' : 'false';
735                         } elseif (! $val) {
736                                 $val = 0;
737                         }
738                                 if ($use == 'literal') {
739                                         $xml .= "<$name$xmlns$atts>$val</$name>";
740                                 } else {
741                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
742                                 }
743                                 break;
744                         case (is_int($val) || is_long($val) || $type == 'int'):
745                                 $this->debug("serialize_val: serialize int");
746                                 if ($use == 'literal') {
747                                         $xml .= "<$name$xmlns$atts>$val</$name>";
748                                 } else {
749                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
750                                 }
751                                 break;
752                         case (is_float($val)|| is_double($val) || $type == 'float'):
753                                 $this->debug("serialize_val: serialize float");
754                                 if ($use == 'literal') {
755                                         $xml .= "<$name$xmlns$atts>$val</$name>";
756                                 } else {
757                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
758                                 }
759                                 break;
760                         case (is_string($val) || $type == 'string'):
761                                 $this->debug("serialize_val: serialize string");
762                                 $val = $this->expandEntities($val);
763                                 if ($use == 'literal') {
764                                         $xml .= "<$name$xmlns$atts>$val</$name>";
765                                 } else {
766                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
767                                 }
768                                 break;
769                         case is_object($val):
770                                 $this->debug("serialize_val: serialize object");
771                         if (get_class($val) == 'soapval') {
772                                 $this->debug("serialize_val: serialize soapval object");
773                                 $pXml = $val->serialize($use);
774                                         $this->appendDebug($val->getDebug());
775                                         $val->clearDebug();
776                         } else {
777                                         if (! $name) {
778                                                 $name = get_class($val);
779                                                 $this->debug("In serialize_val, used class name $name as element name");
780                                         } else {
781                                                 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
782                                         }
783                                         foreach(get_object_vars($val) as $k => $v){
784                                                 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
785                                         }
786                                 }
787                                 if(isset($type) && isset($type_prefix)){
788                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
789                                 } else {
790                                         $type_str = '';
791                                 }
792                                 if ($use == 'literal') {
793                                         $xml .= "<$name$xmlns$atts>$pXml</$name>";
794                                 } else {
795                                         $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
796                                 }
797                                 break;
798                         break;
799                         case (is_array($val) || $type):
800                                 // detect if struct or array
801                                 $valueType = $this->isArraySimpleOrStruct($val);
802                 if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){
803                                         $this->debug("serialize_val: serialize array");
804                                         $i = 0;
805                                         if(is_array($val) && count($val)> 0){
806                                                 foreach($val as $v){
807                                 if(is_object($v) && get_class($v) ==  'soapval'){
808                                                                 $tt_ns = $v->type_ns;
809                                                                 $tt = $v->type;
810                                                         } elseif (is_array($v)) {
811                                                                 $tt = $this->isArraySimpleOrStruct($v);
812                                                         } else {
813                                                                 $tt = gettype($v);
814                                 }
815                                                         $array_types[$tt] = 1;
816                                                         // TODO: for literal, the name should be $name
817                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
818                                                         ++$i;
819                                                 }
820                                                 if(count($array_types) > 1){
821                                                         $array_typename = 'xsd:anyType';
822                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
823                                                         if ($tt == 'integer') {
824                                                                 $tt = 'int';
825                                                         }
826                                                         $array_typename = 'xsd:'.$tt;
827                                                 } elseif(isset($tt) && $tt == 'arraySimple'){
828                                                         $array_typename = 'SOAP-ENC:Array';
829                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){
830                                                         $array_typename = 'unnamed_struct_use_soapval';
831                                                 } else {
832                                                         // if type is prefixed, create type prefix
833                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
834                                                                  $array_typename = 'xsd:' . $tt;
835                                                         } elseif ($tt_ns) {
836                                                                 $tt_prefix = 'ns' . rand(1000, 9999);
837                                                                 $array_typename = "$tt_prefix:$tt";
838                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
839                                                         } else {
840                                                                 $array_typename = $tt;
841                                                         }
842                                                 }
843                                                 $array_type = $i;
844                                                 if ($use == 'literal') {
845                                                         $type_str = '';
846                                                 } else if (isset($type) && isset($type_prefix)) {
847                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
848                                                 } else {
849                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
850                                                 }
851                                         // empty array
852                                         } else {
853                                                 if ($use == 'literal') {
854                                                         $type_str = '';
855                                                 } else if (isset($type) && isset($type_prefix)) {
856                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
857                                                 } else {
858                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
859                                                 }
860                                         }
861                                         // TODO: for array in literal, there is no wrapper here
862                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
863                                 } else {
864                                         // got a struct
865                                         $this->debug("serialize_val: serialize struct");
866                                         if(isset($type) && isset($type_prefix)){
867                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";
868                                         } else {
869                                                 $type_str = '';
870                                         }
871                                         if ($use == 'literal') {
872                                                 $xml .= "<$name$xmlns$atts>";
873                                         } else {
874                                                 $xml .= "<$name$xmlns$type_str$atts>";
875                                         }
876                                         foreach($val as $k => $v){
877                                                 // Apache Map
878                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
879                                                         $xml .= '<item>';
880                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
881                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
882                                                         $xml .= '</item>';
883                                                 } else {
884                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
885                                                 }
886                                         }
887                                         $xml .= "</$name>";
888                                 }
889                                 break;
890                         default:
891                                 $this->debug("serialize_val: serialize unknown");
892                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
893                                 break;
894                 }
895                 $this->debug("serialize_val returning $xml");
896                 return $xml;
897         }
898
899     /**
900     * serializes a message
901     *
902     * @param string $body the XML of the SOAP body
903     * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
904     * @param array $namespaces optional the namespaces used in generating the body and headers
905     * @param string $style optional (rpc|document)
906     * @param string $use optional (encoded|literal)
907     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
908     * @return string the message
909     * @access public
910     */
911     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
912     // TODO: add an option to automatically run utf8_encode on $body and $headers
913     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
914     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
915
916         $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
917         $this->debug("headers:");
918         $this->appendDebug($this->varDump($headers));
919         $this->debug("namespaces:");
920         $this->appendDebug($this->varDump($namespaces));
921
922         // serialize namespaces
923     $ns_string = '';
924         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
925                 $ns_string .= " xmlns:$k=\"$v\"";
926         }
927         if($encodingStyle) {
928                 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
929         }
930
931         // serialize headers
932         if($headers){
933                 if (is_array($headers)) {
934                         $xml = '';
935                         foreach ($headers as $k => $v) {
936                                 if (is_object($v) && get_class($v) == 'soapval') {
937                                         $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
938                                 } else {
939                                         $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
940                                 }
941                         }
942                         $headers = $xml;
943                         $this->debug("In serializeEnvelope, serialized array of headers to $headers");
944                 }
945                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
946         }
947         // serialize envelope
948         return
949         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
950         '<SOAP-ENV:Envelope'.$ns_string.">".
951         $headers.
952         "<SOAP-ENV:Body>".
953                 $body.
954         "</SOAP-ENV:Body>".
955         "</SOAP-ENV:Envelope>";
956     }
957
958         /**
959          * formats a string to be inserted into an HTML stream
960          *
961          * @param string $str The string to format
962          * @return string The formatted string
963          * @access public
964          * @deprecated
965          */
966     function formatDump($str){
967                 $str = htmlspecialchars($str);
968                 return nl2br($str);
969     }
970
971         /**
972         * contracts (changes namespace to prefix) a qualified name
973         *
974         * @param    string $qname qname
975         * @return       string contracted qname
976         * @access   private
977         */
978         function contractQname($qname){
979                 // get element namespace
980                 //$this->xdebug("Contract $qname");
981                 if (strrpos($qname, ':')) {
982                         // get unqualified name
983                         $name = substr($qname, strrpos($qname, ':') + 1);
984                         // get ns
985                         $ns = substr($qname, 0, strrpos($qname, ':'));
986                         $p = $this->getPrefixFromNamespace($ns);
987                         if ($p) {
988                                 return $p . ':' . $name;
989                         }
990                         return $qname;
991                 } else {
992                         return $qname;
993                 }
994         }
995
996         /**
997         * expands (changes prefix to namespace) a qualified name
998         *
999         * @param    string $qname qname
1000         * @return       string expanded qname
1001         * @access   private
1002         */
1003         function expandQname($qname){
1004                 // get element prefix
1005                 if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){
1006                         // get unqualified name
1007                         $name = substr(strstr($qname,':'),1);
1008                         // get ns prefix
1009                         $prefix = substr($qname,0,strpos($qname,':'));
1010                         if(isset($this->namespaces[$prefix])){
1011                                 return $this->namespaces[$prefix].':'.$name;
1012                         } else {
1013                                 return $qname;
1014                         }
1015                 } else {
1016                         return $qname;
1017                 }
1018         }
1019
1020     /**
1021     * returns the local part of a prefixed string
1022     * returns the original string, if not prefixed
1023     *
1024     * @param string $str The prefixed string
1025     * @return string The local part
1026     * @access public
1027     */
1028         function getLocalPart($str){
1029                 if($sstr = strrchr($str,':')){
1030                         // get unqualified name
1031                         return substr( $sstr, 1 );
1032                 } else {
1033                         return $str;
1034                 }
1035         }
1036
1037         /**
1038     * returns the prefix part of a prefixed string
1039     * returns false, if not prefixed
1040     *
1041     * @param string $str The prefixed string
1042     * @return mixed The prefix or false if there is no prefix
1043     * @access public
1044     */
1045         function getPrefix($str){
1046                 if($pos = strrpos($str,':')){
1047                         // get prefix
1048                         return substr($str,0,$pos);
1049                 }
1050                 return false;
1051         }
1052
1053         /**
1054     * pass it a prefix, it returns a namespace
1055     *
1056     * @param string $prefix The prefix
1057     * @return mixed The namespace, false if no namespace has the specified prefix
1058     * @access public
1059     */
1060         function getNamespaceFromPrefix($prefix){
1061                 if (isset($this->namespaces[$prefix])) {
1062                         return $this->namespaces[$prefix];
1063                 }
1064                 //$this->setError("No namespace registered for prefix '$prefix'");
1065                 return false;
1066         }
1067
1068         /**
1069     * returns the prefix for a given namespace (or prefix)
1070     * or false if no prefixes registered for the given namespace
1071     *
1072     * @param string $ns The namespace
1073     * @return mixed The prefix, false if the namespace has no prefixes
1074     * @access public
1075     */
1076         function getPrefixFromNamespace($ns) {
1077                 foreach ($this->namespaces as $p => $n) {
1078                         if ($ns == $n || $ns == $p) {
1079                             $this->usedNamespaces[$p] = $n;
1080                                 return $p;
1081                         }
1082                 }
1083                 return false;
1084         }
1085
1086         /**
1087     * returns the time in ODBC canonical form with microseconds
1088     *
1089     * @return string The time in ODBC canonical form with microseconds
1090     * @access public
1091     */
1092         function getmicrotime() {
1093                 if (function_exists('gettimeofday')) {
1094                         $tod = gettimeofday();
1095                         $sec = $tod['sec'];
1096                         $usec = $tod['usec'];
1097                 } else {
1098                         $sec = time();
1099                         $usec = 0;
1100                 }
1101                 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
1102         }
1103
1104         /**
1105          * Returns a string with the output of var_dump
1106          *
1107          * @param mixed $data The variable to var_dump
1108          * @return string The output of var_dump
1109          * @access public
1110          */
1111     function varDump($data) {
1112         if ($this->debugLevel <= 0) {
1113             return '';
1114         }
1115         ob_start();
1116                 var_dump($data);
1117                 $ret_val = ob_get_contents();
1118                 ob_end_clean();
1119                 return $ret_val;
1120         }
1121
1122         /**
1123         * represents the object as a string
1124         *
1125         * @return       string
1126         * @access   public
1127         */
1128         function __toString() {
1129                 return $this->varDump($this);
1130         }
1131 }
1132
1133 // XML Schema Datatype Helper Functions
1134
1135 //xsd:dateTime helpers
1136
1137 /**
1138 * convert unix timestamp to ISO 8601 compliant date string
1139 *
1140 * @param    int $timestamp Unix time stamp
1141 * @param        boolean $utc Whether the time stamp is UTC or local
1142 * @return       mixed ISO 8601 date string or false
1143 * @access   public
1144 */
1145 function timestamp_to_iso8601($timestamp,$utc=true){
1146         $datestr = date('Y-m-d\TH:i:sO',$timestamp);
1147         $pos = strrpos($datestr, "+");
1148         if ($pos === FALSE) {
1149                 $pos = strrpos($datestr, "-");
1150         }
1151         if ($pos !== FALSE) {
1152                 if (strlen($datestr) == $pos + 5) {
1153                         $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
1154                 }
1155         }
1156         if($utc){
1157                 $pattern = '/'.
1158                 '([0-9]{4})-'.  // centuries & years CCYY-
1159                 '([0-9]{2})-'.  // months MM-
1160                 '([0-9]{2})'.   // days DD
1161                 'T'.                    // separator T
1162                 '([0-9]{2}):'.  // hours hh:
1163                 '([0-9]{2}):'.  // minutes mm:
1164                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
1165                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1166                 '/';
1167
1168                 if(preg_match($pattern,$datestr,$regs)){
1169                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
1170                 }
1171                 return false;
1172         } else {
1173                 return $datestr;
1174         }
1175 }
1176
1177 /**
1178 * convert ISO 8601 compliant date string to unix timestamp
1179 *
1180 * @param    string $datestr ISO 8601 compliant date string
1181 * @return       mixed Unix timestamp (int) or false
1182 * @access   public
1183 */
1184 function iso8601_to_timestamp($datestr){
1185         $pattern = '/'.
1186         '([0-9]{4})-'.  // centuries & years CCYY-
1187         '([0-9]{2})-'.  // months MM-
1188         '([0-9]{2})'.   // days DD
1189         'T'.                    // separator T
1190         '([0-9]{2}):'.  // hours hh:
1191         '([0-9]{2}):'.  // minutes mm:
1192         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
1193         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1194         '/';
1195         if(preg_match($pattern,$datestr,$regs)){
1196                 // not utc
1197                 if($regs[8] != 'Z'){
1198                         $op = substr($regs[8],0,1);
1199                         $h = substr($regs[8],1,2);
1200                         $m = substr($regs[8],strlen($regs[8])-2,2);
1201                         if($op == '-'){
1202                                 $regs[4] = $regs[4] + $h;
1203                                 $regs[5] = $regs[5] + $m;
1204                         } elseif($op == '+'){
1205                                 $regs[4] = $regs[4] - $h;
1206                                 $regs[5] = $regs[5] - $m;
1207                         }
1208                 }
1209                 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1210 //              return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
1211         } else {
1212                 return false;
1213         }
1214 }
1215
1216 /**
1217 * sleeps some number of microseconds
1218 *
1219 * @param    string $usec the number of microseconds to sleep
1220 * @access   public
1221 * @deprecated
1222 */
1223 function usleepWindows($usec)
1224 {
1225         $start = gettimeofday();
1226
1227         do
1228         {
1229                 $stop = gettimeofday();
1230                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
1231                 + $stop['usec'] - $start['usec'];
1232         }
1233         while ($timePassed < $usec);
1234 }
1235
1236 ?><?php
1237
1238 /*
1239
1240 Modification information for LGPL compliance
1241
1242 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
1243     bug 40066
1244
1245 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
1246     Merging with maint_6_0_1 (svn merge -r 58250:58342)
1247
1248 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
1249     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
1250
1251 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
1252     fix SOAP calls with no parameters
1253
1254 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
1255
1256 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
1257
1258 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
1259
1260 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
1261
1262 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
1263
1264 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
1265
1266 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
1267
1268 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
1269 - Changing all ereg function to either preg or simple string based ones
1270 - No more references to magic quotes.
1271 - Change all the session_unregister() functions to just unset() the correct session variable instead.
1272
1273 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
1274
1275 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
1276
1277 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
1278
1279 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
1280
1281 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
1282
1283 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
1284
1285 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
1286
1287 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
1288
1289 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
1290 Touched:
1291 - data/SugarBean.php
1292 - include/domit/php_http_client_generic.php
1293 - include/domit/php_http_connector.php
1294 - include/domit/testing_domit.php
1295 - include/domit/xml_domit_getelementsbypath.php
1296 - include/domit/xml_domit_lite_parser.php
1297 - include/domit/xml_domit_nodemaps.php
1298 - include/domit/xml_domit_parser.php
1299 - include/domit/xml_domit_shared.php
1300 - include/generic/SugarWidgets/SugarWidgetField.php
1301 - include/generic/SugarWidgets/SugarWidgetReportField.php
1302 - include/ListView/ProcessView.php
1303 - include/nusoap/class.soapclient.php
1304 - include/nusoap/nusoap.php
1305 - include/nusoap/nusoapmime.php
1306 - include/Pear/HTML_Safe/Safe.php
1307 - include/Pear/XML_HTMLSax3/HTMLSax3.php
1308 - modules/Administration/RebuildWorkFlow.php
1309 - modules/Expressions/RelateSelector.php
1310 - modules/Reports/templates/templates_reports.php
1311 - modules/WorkFlow/Delete.php
1312 - modules/WorkFlow/Save.php
1313 - modules/WorkFlow/SaveSequence.php
1314 - modules/WorkFlow/WorkFlow.php
1315 - modules/WorkFlowActionShells/CreateStep1.php
1316 - modules/WorkFlowActionShells/CreateStep2.php
1317 - modules/WorkFlowActionShells/Save.php
1318 - modules/WorkFlowActionShells/WorkFlowActionShell.php
1319 - modules/WorkFlowAlerts/Save.php
1320 - modules/WorkFlowAlerts/WorkFlowAlert.php
1321 - modules/WorkFlowAlertShells/DetailView.php
1322 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
1323 - modules/WorkFlowTriggerShells/CreateStep1.php
1324 - modules/WorkFlowTriggerShells/CreateStepFilter.php
1325 - modules/WorkFlowTriggerShells/SaveFilter.php
1326 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
1327 - soap/SoapHelperFunctions.php
1328 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
1329 - test/simpletest/browser.php
1330 - test/simpletest/default_reporter.php
1331 - test/simpletest/detached.php
1332 - test/simpletest/eclipse.php
1333 - test/simpletest/expectation.php
1334 - test/simpletest/extensions/pear_test_case.php
1335 - test/simpletest/form.php
1336 - test/simpletest/http.php
1337 - test/simpletest/mock_objects.php
1338 - test/simpletest/page.php
1339 - test/simpletest/parser.php
1340 - test/simpletest/remote.php
1341 - test/simpletest/shell_tester.php
1342 - test/simpletest/simple_test.php
1343 - test/simpletest/simpletest.php
1344 - test/simpletest/test/acceptance_test.php
1345 - test/simpletest/test/adapter_test.php
1346 - test/simpletest/test/authentication_test.php
1347 - test/simpletest/test/browser_test.php
1348 - test/simpletest/test/collector_test.php
1349 - test/simpletest/test/compatibility_test.php
1350 - test/simpletest/test/detached_test.php
1351 - test/simpletest/test/eclipse_test.php
1352 - test/simpletest/test/encoding_test.php
1353 - test/simpletest/test/errors_test.php
1354 - test/simpletest/test/expectation_test.php
1355 - test/simpletest/test/form_test.php
1356 - test/simpletest/test/frames_test.php
1357 - test/simpletest/test/http_test.php
1358 - test/simpletest/test/live_test.php
1359 - test/simpletest/test/mock_objects_test.php
1360 - test/simpletest/test/page_test.php
1361 - test/simpletest/test/parse_error_test.php
1362 - test/simpletest/test/parser_test.php
1363 - test/simpletest/test/remote_test.php
1364 - test/simpletest/test/shell_test.php
1365 - test/simpletest/test/shell_tester_test.php
1366 - test/simpletest/test/simpletest_test.php
1367 - test/simpletest/test/site/page_request.php
1368 - test/simpletest/test/tag_test.php
1369 - test/simpletest/test/unit_tester_test.php
1370 - test/simpletest/test/user_agent_test.php
1371 - test/simpletest/test/visual_test.php
1372 - test/simpletest/test/xml_test.php
1373 - test/simpletest/test_case.php
1374 - test/simpletest/ui/array_reporter/test.php
1375 - test/simpletest/ui/recorder/test.php
1376 - test/simpletest/unit_tester.php
1377 - test/simpletest/url.php
1378 - test/simpletest/user_agent.php
1379 - test/simpletest/web_tester.php
1380 - test/spikephpcoverage/src/PEAR.php
1381 - test/spikephpcoverage/src/util/Utility.php
1382 - test/spikephpcoverage/src/XML/Parser.php
1383 - test/spikephpcoverage/src/XML/Parser/Simple.php
1384 - test/test_utilities/SugarTest_SimpleBrowser.php
1385
1386 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
1387
1388 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
1389
1390 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
1391
1392 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
1393
1394 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
1395
1396 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
1397
1398 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
1399
1400 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
1401
1402 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
1403
1404 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
1405
1406 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
1407
1408 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
1409
1410 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
1411
1412 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
1413
1414 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
1415
1416 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
1417
1418 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
1419
1420 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
1421
1422 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
1423
1424 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
1425
1426 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
1427
1428 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
1429
1430 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
1431
1432 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
1433
1434
1435 */
1436
1437
1438
1439
1440
1441 /**
1442 * Contains information for a SOAP fault.
1443 * Mainly used for returning faults from deployed functions
1444 * in a server instance.
1445 * @author   Dietrich Ayala <dietrich@ganx4.com>
1446
1447 * @access public
1448 */
1449 class nusoap_fault extends nusoap_base {
1450         /**
1451          * The fault code (client|server)
1452          * @var string
1453          * @access private
1454          */
1455         var $faultcode;
1456         /**
1457          * The fault actor
1458          * @var string
1459          * @access private
1460          */
1461         var $faultactor;
1462         /**
1463          * The fault string, a description of the fault
1464          * @var string
1465          * @access private
1466          */
1467         var $faultstring;
1468         /**
1469          * The fault detail, typically a string or array of string
1470          * @var mixed
1471          * @access private
1472          */
1473         var $faultdetail;
1474
1475         /**
1476         * constructor
1477     *
1478     * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
1479     * @param string $faultactor only used when msg routed between multiple actors
1480     * @param string $faultstring human readable error message
1481     * @param mixed $faultdetail detail, typically a string or array of string
1482         */
1483         function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
1484                 parent::nusoap_base();
1485                 $this->faultcode = $faultcode;
1486                 $this->faultactor = $faultactor;
1487                 $this->faultstring = $faultstring;
1488                 $this->faultdetail = $faultdetail;
1489         }
1490
1491         /**
1492         * serialize a fault
1493         *
1494         * @return       string  The serialization of the fault instance.
1495         * @access   public
1496         */
1497         function serialize(){
1498                 $ns_string = '';
1499                 foreach($this->namespaces as $k => $v){
1500                         $ns_string .= "\n  xmlns:$k=\"$v\"";
1501                 }
1502                 $return_msg =
1503                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1504                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1505                                 '<SOAP-ENV:Body>'.
1506                                 '<SOAP-ENV:Fault>'.
1507                                         $this->serialize_val($this->faultcode, 'faultcode').
1508                                         $this->serialize_val($this->faultactor, 'faultactor').
1509                                         $this->serialize_val($this->faultstring, 'faultstring').
1510                                         $this->serialize_val($this->faultdetail, 'detail').
1511                                 '</SOAP-ENV:Fault>'.
1512                                 '</SOAP-ENV:Body>'.
1513                         '</SOAP-ENV:Envelope>';
1514                 return $return_msg;
1515         }
1516 }
1517
1518 /**
1519  * Backward compatibility
1520  */
1521 class soap_fault extends nusoap_fault {
1522 }
1523
1524 ?><?php
1525
1526 /*
1527
1528 Modification information for LGPL compliance
1529
1530 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
1531     bug 40066
1532
1533 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
1534     Merging with maint_6_0_1 (svn merge -r 58250:58342)
1535
1536 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
1537     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
1538
1539 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
1540     fix SOAP calls with no parameters
1541
1542 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
1543
1544 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
1545
1546 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
1547
1548 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
1549
1550 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
1551
1552 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
1553
1554 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
1555
1556 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
1557 - Changing all ereg function to either preg or simple string based ones
1558 - No more references to magic quotes.
1559 - Change all the session_unregister() functions to just unset() the correct session variable instead.
1560
1561 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
1562
1563 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
1564
1565 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
1566
1567 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
1568
1569 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
1570
1571 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
1572
1573 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
1574
1575 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
1576
1577 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
1578 Touched:
1579 - data/SugarBean.php
1580 - include/domit/php_http_client_generic.php
1581 - include/domit/php_http_connector.php
1582 - include/domit/testing_domit.php
1583 - include/domit/xml_domit_getelementsbypath.php
1584 - include/domit/xml_domit_lite_parser.php
1585 - include/domit/xml_domit_nodemaps.php
1586 - include/domit/xml_domit_parser.php
1587 - include/domit/xml_domit_shared.php
1588 - include/generic/SugarWidgets/SugarWidgetField.php
1589 - include/generic/SugarWidgets/SugarWidgetReportField.php
1590 - include/ListView/ProcessView.php
1591 - include/nusoap/class.soapclient.php
1592 - include/nusoap/nusoap.php
1593 - include/nusoap/nusoapmime.php
1594 - include/Pear/HTML_Safe/Safe.php
1595 - include/Pear/XML_HTMLSax3/HTMLSax3.php
1596 - modules/Administration/RebuildWorkFlow.php
1597 - modules/Expressions/RelateSelector.php
1598 - modules/Reports/templates/templates_reports.php
1599 - modules/WorkFlow/Delete.php
1600 - modules/WorkFlow/Save.php
1601 - modules/WorkFlow/SaveSequence.php
1602 - modules/WorkFlow/WorkFlow.php
1603 - modules/WorkFlowActionShells/CreateStep1.php
1604 - modules/WorkFlowActionShells/CreateStep2.php
1605 - modules/WorkFlowActionShells/Save.php
1606 - modules/WorkFlowActionShells/WorkFlowActionShell.php
1607 - modules/WorkFlowAlerts/Save.php
1608 - modules/WorkFlowAlerts/WorkFlowAlert.php
1609 - modules/WorkFlowAlertShells/DetailView.php
1610 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
1611 - modules/WorkFlowTriggerShells/CreateStep1.php
1612 - modules/WorkFlowTriggerShells/CreateStepFilter.php
1613 - modules/WorkFlowTriggerShells/SaveFilter.php
1614 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
1615 - soap/SoapHelperFunctions.php
1616 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
1617 - test/simpletest/browser.php
1618 - test/simpletest/default_reporter.php
1619 - test/simpletest/detached.php
1620 - test/simpletest/eclipse.php
1621 - test/simpletest/expectation.php
1622 - test/simpletest/extensions/pear_test_case.php
1623 - test/simpletest/form.php
1624 - test/simpletest/http.php
1625 - test/simpletest/mock_objects.php
1626 - test/simpletest/page.php
1627 - test/simpletest/parser.php
1628 - test/simpletest/remote.php
1629 - test/simpletest/shell_tester.php
1630 - test/simpletest/simple_test.php
1631 - test/simpletest/simpletest.php
1632 - test/simpletest/test/acceptance_test.php
1633 - test/simpletest/test/adapter_test.php
1634 - test/simpletest/test/authentication_test.php
1635 - test/simpletest/test/browser_test.php
1636 - test/simpletest/test/collector_test.php
1637 - test/simpletest/test/compatibility_test.php
1638 - test/simpletest/test/detached_test.php
1639 - test/simpletest/test/eclipse_test.php
1640 - test/simpletest/test/encoding_test.php
1641 - test/simpletest/test/errors_test.php
1642 - test/simpletest/test/expectation_test.php
1643 - test/simpletest/test/form_test.php
1644 - test/simpletest/test/frames_test.php
1645 - test/simpletest/test/http_test.php
1646 - test/simpletest/test/live_test.php
1647 - test/simpletest/test/mock_objects_test.php
1648 - test/simpletest/test/page_test.php
1649 - test/simpletest/test/parse_error_test.php
1650 - test/simpletest/test/parser_test.php
1651 - test/simpletest/test/remote_test.php
1652 - test/simpletest/test/shell_test.php
1653 - test/simpletest/test/shell_tester_test.php
1654 - test/simpletest/test/simpletest_test.php
1655 - test/simpletest/test/site/page_request.php
1656 - test/simpletest/test/tag_test.php
1657 - test/simpletest/test/unit_tester_test.php
1658 - test/simpletest/test/user_agent_test.php
1659 - test/simpletest/test/visual_test.php
1660 - test/simpletest/test/xml_test.php
1661 - test/simpletest/test_case.php
1662 - test/simpletest/ui/array_reporter/test.php
1663 - test/simpletest/ui/recorder/test.php
1664 - test/simpletest/unit_tester.php
1665 - test/simpletest/url.php
1666 - test/simpletest/user_agent.php
1667 - test/simpletest/web_tester.php
1668 - test/spikephpcoverage/src/PEAR.php
1669 - test/spikephpcoverage/src/util/Utility.php
1670 - test/spikephpcoverage/src/XML/Parser.php
1671 - test/spikephpcoverage/src/XML/Parser/Simple.php
1672 - test/test_utilities/SugarTest_SimpleBrowser.php
1673
1674 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
1675
1676 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
1677
1678 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
1679
1680 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
1681
1682 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
1683
1684 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
1685
1686 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
1687
1688 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
1689
1690 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
1691
1692 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
1693
1694 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
1695
1696 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
1697
1698 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
1699
1700 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
1701
1702 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
1703
1704 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
1705
1706 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
1707
1708 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
1709
1710 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
1711
1712 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
1713
1714 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
1715
1716 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
1717
1718 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
1719
1720 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
1721
1722
1723 */
1724
1725
1726
1727
1728
1729 /**
1730 * parses an XML Schema, allows access to it's data, other utility methods.
1731 * imperfect, no validation... yet, but quite functional.
1732 *
1733 * @author   Dietrich Ayala <dietrich@ganx4.com>
1734 * @author   Scott Nichol <snichol@users.sourceforge.net>
1735
1736 * @access   public
1737 */
1738 class nusoap_xmlschema extends nusoap_base  {
1739
1740         // files
1741         var $schema = '';
1742         var $xml = '';
1743         // namespaces
1744         var $enclosingNamespaces;
1745         // schema info
1746         var $schemaInfo = array();
1747         var $schemaTargetNamespace = '';
1748         // types, elements, attributes defined by the schema
1749         var $attributes = array();
1750         var $complexTypes = array();
1751         var $complexTypeStack = array();
1752         var $currentComplexType = null;
1753         var $elements = array();
1754         var $elementStack = array();
1755         var $currentElement = null;
1756         var $simpleTypes = array();
1757         var $simpleTypeStack = array();
1758         var $currentSimpleType = null;
1759         // imports
1760         var $imports = array();
1761         // parser vars
1762         var $parser;
1763         var $position = 0;
1764         var $depth = 0;
1765         var $depth_array = array();
1766         var $message = array();
1767         var $defaultNamespace = array();
1768
1769         /**
1770         * constructor
1771         *
1772         * @param    string $schema schema document URI
1773         * @param    string $xml xml document URI
1774         * @param        string $namespaces namespaces defined in enclosing XML
1775         * @access   public
1776         */
1777         function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
1778                 parent::nusoap_base();
1779                 $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1780                 // files
1781                 $this->schema = $schema;
1782                 $this->xml = $xml;
1783
1784                 // namespaces
1785                 $this->enclosingNamespaces = $namespaces;
1786                 $this->namespaces = array_merge($this->namespaces, $namespaces);
1787
1788                 // parse schema file
1789                 if($schema != ''){
1790                         $this->debug('initial schema file: '.$schema);
1791                         $this->parseFile($schema, 'schema');
1792                 }
1793
1794                 // parse xml file
1795                 if($xml != ''){
1796                         $this->debug('initial xml file: '.$xml);
1797                         $this->parseFile($xml, 'xml');
1798                 }
1799
1800         }
1801
1802     /**
1803     * parse an XML file
1804     *
1805     * @param string $xml path/URL to XML file
1806     * @param string $type (schema | xml)
1807         * @return boolean
1808     * @access public
1809     */
1810         function parseFile($xml,$type){
1811                 // parse xml file
1812                 if($xml != ""){
1813                         $xmlStr = @join("",@file($xml));
1814                         if($xmlStr == ""){
1815                                 $msg = 'Error reading XML from '.$xml;
1816                                 $this->setError($msg);
1817                                 $this->debug($msg);
1818                         return false;
1819                         } else {
1820                                 $this->debug("parsing $xml");
1821                                 $this->parseString($xmlStr,$type);
1822                                 $this->debug("done parsing $xml");
1823                         return true;
1824                         }
1825                 }
1826                 return false;
1827         }
1828
1829         /**
1830         * parse an XML string
1831         *
1832         * @param    string $xml path or URL
1833     * @param    string $type (schema|xml)
1834         * @access   private
1835         */
1836         function parseString($xml,$type){
1837                 // parse xml string
1838                 if($xml != ""){
1839
1840                 // Create an XML parser.
1841                 $this->parser = xml_parser_create();
1842                 // Set the options for parsing the XML data.
1843                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1844
1845                 // Set the object for the parser.
1846                 xml_set_object($this->parser, $this);
1847
1848                 // Set the element handlers for the parser.
1849                         if($type == "schema"){
1850                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1851                         xml_set_character_data_handler($this->parser,'schemaCharacterData');
1852                         } elseif($type == "xml"){
1853                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1854                         xml_set_character_data_handler($this->parser,'xmlCharacterData');
1855                         }
1856
1857                     // Parse the XML file.
1858                     if(!xml_parse($this->parser,$xml,true)){
1859                         // Display an error message.
1860                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1861                                 xml_get_current_line_number($this->parser),
1862                                 xml_error_string(xml_get_error_code($this->parser))
1863                                 );
1864                                 $this->debug($errstr);
1865                                 $this->debug("XML payload:\n" . $xml);
1866                                 $this->setError($errstr);
1867                 }
1868
1869                         xml_parser_free($this->parser);
1870                 } else{
1871                         $this->debug('no xml passed to parseString()!!');
1872                         $this->setError('no xml passed to parseString()!!');
1873                 }
1874         }
1875
1876         /**
1877          * gets a type name for an unnamed type
1878          *
1879          * @param       string  Element name
1880          * @return      string  A type name for an unnamed type
1881          * @access      private
1882          */
1883         function CreateTypeName($ename) {
1884                 $scope = '';
1885                 for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1886                         $scope .= $this->complexTypeStack[$i] . '_';
1887                 }
1888                 return $scope . $ename . '_ContainedType';
1889         }
1890
1891         /**
1892         * start-element handler
1893         *
1894         * @param    string $parser XML parser object
1895         * @param    string $name element name
1896         * @param    string $attrs associative array of attributes
1897         * @access   private
1898         */
1899         function schemaStartElement($parser, $name, $attrs) {
1900
1901                 // position in the total number of elements, starting from 0
1902                 $pos = $this->position++;
1903                 $depth = $this->depth++;
1904                 // set self as current value for this depth
1905                 $this->depth_array[$depth] = $pos;
1906                 $this->message[$pos] = array('cdata' => '');
1907                 if ($depth > 0) {
1908                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1909                 } else {
1910                         $this->defaultNamespace[$pos] = false;
1911                 }
1912
1913                 // get element prefix
1914                 if($prefix = $this->getPrefix($name)){
1915                         // get unqualified name
1916                         $name = $this->getLocalPart($name);
1917                 } else {
1918                 $prefix = '';
1919         }
1920
1921         // loop thru attributes, expanding, and registering namespace declarations
1922         if(count($attrs) > 0){
1923                 foreach($attrs as $k => $v){
1924                 // if ns declarations, add to class level array of valid namespaces
1925                                 if(preg_match('/^xmlns/',$k)){
1926                         //$this->xdebug("$k: $v");
1927                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1928                         if($ns_prefix = substr(strrchr($k,':'),1)){
1929                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");
1930                                                 $this->namespaces[$ns_prefix] = $v;
1931                                         } else {
1932                                                 $this->defaultNamespace[$pos] = $v;
1933                                                 if (! $this->getPrefixFromNamespace($v)) {
1934                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1935                                                 }
1936                                         }
1937                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1938                                                 $this->XMLSchemaVersion = $v;
1939                                                 $this->namespaces['xsi'] = $v.'-instance';
1940                                         }
1941                                 }
1942                 }
1943                 foreach($attrs as $k => $v){
1944                 // expand each attribute
1945                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
1946                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
1947                         $eAttrs[$k] = $v;
1948                 }
1949                 $attrs = $eAttrs;
1950         } else {
1951                 $attrs = array();
1952         }
1953                 // find status, register data
1954                 switch($name){
1955                         case 'all':                     // (optional) compositor content for a complexType
1956                         case 'choice':
1957                         case 'group':
1958                         case 'sequence':
1959                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1960                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1961                                 //if($name == 'all' || $name == 'sequence'){
1962                                 //      $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1963                                 //}
1964                         break;
1965                         case 'attribute':       // complexType attribute
1966                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1967                 $this->xdebug("parsing attribute:");
1968                 $this->appendDebug($this->varDump($attrs));
1969                                 if (!isset($attrs['form'])) {
1970                                         // TODO: handle globals
1971                                         $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1972                                 }
1973                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1974                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1975                                         if (!strpos($v, ':')) {
1976                                                 // no namespace in arrayType attribute value...
1977                                                 if ($this->defaultNamespace[$pos]) {
1978                                                         // ...so use the default
1979                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1980                                                 }
1981                                         }
1982                 }
1983                 if(isset($attrs['name'])){
1984                                         $this->attributes[$attrs['name']] = $attrs;
1985                                         $aname = $attrs['name'];
1986                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1987                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1988                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1989                         } else {
1990                                 $aname = '';
1991                         }
1992                                 } elseif(isset($attrs['ref'])){
1993                                         $aname = $attrs['ref'];
1994                     $this->attributes[$attrs['ref']] = $attrs;
1995                                 }
1996
1997                                 if($this->currentComplexType){  // This should *always* be
1998                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
1999                                 }
2000                                 // arrayType attribute
2001                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
2002                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2003                         $prefix = $this->getPrefix($aname);
2004                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
2005                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
2006                                         } else {
2007                                                 $v = '';
2008                                         }
2009                     if(strpos($v,'[,]')){
2010                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
2011                     }
2012                     $v = substr($v,0,strpos($v,'[')); // clip the []
2013                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
2014                         $v = $this->XMLSchemaVersion.':'.$v;
2015                     }
2016                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
2017                                 }
2018                         break;
2019                         case 'complexContent':  // (optional) content for a complexType
2020                                 $this->xdebug("do nothing for element $name");
2021                         break;
2022                         case 'complexType':
2023                                 array_push($this->complexTypeStack, $this->currentComplexType);
2024                                 if(isset($attrs['name'])){
2025                                         // TODO: what is the scope of named complexTypes that appear
2026                                         //       nested within other c complexTypes?
2027                                         $this->xdebug('processing named complexType '.$attrs['name']);
2028                                         //$this->currentElement = false;
2029                                         $this->currentComplexType = $attrs['name'];
2030                                         $this->complexTypes[$this->currentComplexType] = $attrs;
2031                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
2032                                         // This is for constructs like
2033                                         //           <complexType name="ListOfString" base="soap:Array">
2034                                         //                <sequence>
2035                                         //                    <element name="string" type="xsd:string"
2036                                         //                        minOccurs="0" maxOccurs="unbounded" />
2037                                         //                </sequence>
2038                                         //            </complexType>
2039                                         if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
2040                                                 $this->xdebug('complexType is unusual array');
2041                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2042                                         } else {
2043                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
2044                                         }
2045                                 } else {
2046                                         $name = $this->CreateTypeName($this->currentElement);
2047                                         $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
2048                                         $this->currentComplexType = $name;
2049                                         //$this->currentElement = false;
2050                                         $this->complexTypes[$this->currentComplexType] = $attrs;
2051                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
2052                                         // This is for constructs like
2053                                         //           <complexType name="ListOfString" base="soap:Array">
2054                                         //                <sequence>
2055                                         //                    <element name="string" type="xsd:string"
2056                                         //                        minOccurs="0" maxOccurs="unbounded" />
2057                                         //                </sequence>
2058                                         //            </complexType>
2059                                         if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
2060                                                 $this->xdebug('complexType is unusual array');
2061                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2062                                         } else {
2063                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
2064                                         }
2065                                 }
2066                                 $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
2067                         break;
2068                         case 'element':
2069                                 array_push($this->elementStack, $this->currentElement);
2070                                 if (!isset($attrs['form'])) {
2071                                         if ($this->currentComplexType) {
2072                                                 $attrs['form'] = $this->schemaInfo['elementFormDefault'];
2073                                         } else {
2074                                                 // global
2075                                                 $attrs['form'] = 'qualified';
2076                                         }
2077                                 }
2078                                 if(isset($attrs['type'])){
2079                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
2080                                         if (! $this->getPrefix($attrs['type'])) {
2081                                                 if ($this->defaultNamespace[$pos]) {
2082                                                         $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
2083                                                         $this->xdebug('used default namespace to make type ' . $attrs['type']);
2084                                                 }
2085                                         }
2086                                         // This is for constructs like
2087                                         //           <complexType name="ListOfString" base="soap:Array">
2088                                         //                <sequence>
2089                                         //                    <element name="string" type="xsd:string"
2090                                         //                        minOccurs="0" maxOccurs="unbounded" />
2091                                         //                </sequence>
2092                                         //            </complexType>
2093                                         if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
2094                                                 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
2095                                                 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
2096                                         }
2097                                         $this->currentElement = $attrs['name'];
2098                                         $ename = $attrs['name'];
2099                                 } elseif(isset($attrs['ref'])){
2100                                         $this->xdebug("processing element as ref to ".$attrs['ref']);
2101                                         $this->currentElement = "ref to ".$attrs['ref'];
2102                                         $ename = $this->getLocalPart($attrs['ref']);
2103                                 } else {
2104                                         $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
2105                                         $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
2106                                         $this->currentElement = $attrs['name'];
2107                                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
2108                                         $ename = $attrs['name'];
2109                                 }
2110                                 if (isset($ename) && $this->currentComplexType) {
2111                                         $this->xdebug("add element $ename to complexType $this->currentComplexType");
2112                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
2113                                 } elseif (!isset($attrs['ref'])) {
2114                                         $this->xdebug("add element $ename to elements array");
2115                                         $this->elements[ $attrs['name'] ] = $attrs;
2116                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2117                                 }
2118                         break;
2119                         case 'enumeration':     //      restriction value list member
2120                                 $this->xdebug('enumeration ' . $attrs['value']);
2121                                 if ($this->currentSimpleType) {
2122                                         $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
2123                                 } elseif ($this->currentComplexType) {
2124                                         $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
2125                                 }
2126                         break;
2127                         case 'extension':       // simpleContent or complexContent type extension
2128                                 $this->xdebug('extension ' . $attrs['base']);
2129                                 if ($this->currentComplexType) {
2130                                         $ns = $this->getPrefix($attrs['base']);
2131                                         if ($ns == '') {
2132                                                 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
2133                                         } else {
2134                                                 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
2135                                         }
2136                                 } else {
2137                                         $this->xdebug('no current complexType to set extensionBase');
2138                                 }
2139                         break;
2140                         case 'import':
2141                             if (isset($attrs['schemaLocation'])) {
2142                                         $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
2143                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
2144                                 } else {
2145                                         $this->xdebug('import namespace ' . $attrs['namespace']);
2146                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
2147                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
2148                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
2149                                         }
2150                                 }
2151                         break;
2152                         case 'include':
2153                             if (isset($attrs['schemaLocation'])) {
2154                                         $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
2155                     $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
2156                                 } else {
2157                                         $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
2158                                 }
2159                         break;
2160                         case 'list':    // simpleType value list
2161                                 $this->xdebug("do nothing for element $name");
2162                         break;
2163                         case 'restriction':     // simpleType, simpleContent or complexContent value restriction
2164                                 $this->xdebug('restriction ' . $attrs['base']);
2165                                 if($this->currentSimpleType){
2166                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
2167                                 } elseif($this->currentComplexType){
2168                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
2169                                         if(strstr($attrs['base'],':') == ':Array'){
2170                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2171                                         }
2172                                 }
2173                         break;
2174                         case 'schema':
2175                                 $this->schemaInfo = $attrs;
2176                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
2177                                 if (isset($attrs['targetNamespace'])) {
2178                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];
2179                                 }
2180                                 if (!isset($attrs['elementFormDefault'])) {
2181                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';
2182                                 }
2183                                 if (!isset($attrs['attributeFormDefault'])) {
2184                                         $this->schemaInfo['attributeFormDefault'] = 'unqualified';
2185                                 }
2186                         break;
2187                         case 'simpleContent':   // (optional) content for a complexType
2188                                 if ($this->currentComplexType) {        // This should *always* be
2189                                         $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
2190                                 } else {
2191                                         $this->xdebug("do nothing for element $name because there is no current complexType");
2192                                 }
2193                         break;
2194                         case 'simpleType':
2195                                 array_push($this->simpleTypeStack, $this->currentSimpleType);
2196                                 if(isset($attrs['name'])){
2197                                         $this->xdebug("processing simpleType for name " . $attrs['name']);
2198                                         $this->currentSimpleType = $attrs['name'];
2199                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;
2200                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
2201                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
2202                                 } else {
2203                                         $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
2204                                         $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
2205                                         $this->currentSimpleType = $name;
2206                                         //$this->currentElement = false;
2207                                         $this->simpleTypes[$this->currentSimpleType] = $attrs;
2208                                         $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
2209                                 }
2210                         break;
2211                         case 'union':   // simpleType type list
2212                                 $this->xdebug("do nothing for element $name");
2213                         break;
2214                         default:
2215                                 $this->xdebug("do not have any logic to process element $name");
2216                 }
2217         }
2218
2219         /**
2220         * end-element handler
2221         *
2222         * @param    string $parser XML parser object
2223         * @param    string $name element name
2224         * @access   private
2225         */
2226         function schemaEndElement($parser, $name) {
2227                 // bring depth down a notch
2228                 $this->depth--;
2229                 // position of current element is equal to the last value left in depth_array for my depth
2230                 if(isset($this->depth_array[$this->depth])){
2231                 $pos = $this->depth_array[$this->depth];
2232         }
2233                 // get element prefix
2234                 if ($prefix = $this->getPrefix($name)){
2235                         // get unqualified name
2236                         $name = $this->getLocalPart($name);
2237                 } else {
2238                 $prefix = '';
2239         }
2240                 // move on...
2241                 if($name == 'complexType'){
2242                         $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
2243                         $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
2244                         $this->currentComplexType = array_pop($this->complexTypeStack);
2245                         //$this->currentElement = false;
2246                 }
2247                 if($name == 'element'){
2248                         $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
2249                         $this->currentElement = array_pop($this->elementStack);
2250                 }
2251                 if($name == 'simpleType'){
2252                         $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
2253                         $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
2254                         $this->currentSimpleType = array_pop($this->simpleTypeStack);
2255                 }
2256         }
2257
2258         /**
2259         * element content handler
2260         *
2261         * @param    string $parser XML parser object
2262         * @param    string $data element content
2263         * @access   private
2264         */
2265         function schemaCharacterData($parser, $data){
2266                 $pos = $this->depth_array[$this->depth - 1];
2267                 $this->message[$pos]['cdata'] .= $data;
2268         }
2269
2270         /**
2271         * serialize the schema
2272         *
2273         * @access   public
2274         */
2275         function serializeSchema(){
2276
2277                 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
2278                 $xml = '';
2279                 // imports
2280                 $schemaLocationCount = 0;
2281                 if (sizeof($this->imports) > 0) {
2282                         foreach($this->imports as $ns => $list) {
2283                                 foreach ($list as $ii) {
2284                                         if ($ii['location'] != '') {
2285                                                 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
2286                                         } else {
2287                                                 if ($schemaLocationCount == 0) {
2288                                                         $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" schemaLocation=\"" . $ns . "\"/>\n";
2289                                                 } else {
2290                                                         $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
2291                                                 }
2292                                         }
2293                                 }
2294                         }
2295                 }
2296                 // complex types
2297                 foreach($this->complexTypes as $typeName => $attrs){
2298                         $contentStr = '';
2299                         // serialize child elements
2300                         if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
2301                                 foreach($attrs['elements'] as $element => $eParts){
2302                                         if(isset($eParts['ref'])){
2303                                                 $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
2304                                         } else {
2305                                                 $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
2306                                                 foreach ($eParts as $aName => $aValue) {
2307                                                         // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
2308                                                         if ($aName != 'name' && $aName != 'type') {
2309                                                                 $contentStr .= " $aName=\"$aValue\"";
2310                                                         }
2311                                                 }
2312                                                 $contentStr .= "/>\n";
2313                                         }
2314                                 }
2315                                 // compositor wraps elements
2316                                 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
2317                                         $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
2318                                 }
2319                         }
2320                         // attributes
2321                         if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
2322                                 foreach($attrs['attrs'] as $attr => $aParts){
2323                                         $contentStr .= "    <$schemaPrefix:attribute";
2324                                         foreach ($aParts as $a => $v) {
2325                                                 if ($a == 'ref' || $a == 'type') {
2326                                                         $contentStr .= " $a=\"".$this->contractQName($v).'"';
2327                                                 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
2328                                                         $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
2329                                                         $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
2330                                                 } else {
2331                                                         $contentStr .= " $a=\"$v\"";
2332                                                 }
2333                                         }
2334                                         $contentStr .= "/>\n";
2335                                 }
2336                         }
2337                         // if restriction
2338                         if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
2339                                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
2340                                 // complex or simple content
2341                                 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
2342                                         $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
2343                                 }
2344                         }
2345                         // finalize complex type
2346                         if($contentStr != ''){
2347                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
2348                         } else {
2349                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
2350                         }
2351                         $xml .= $contentStr;
2352                 }
2353                 // simple types
2354                 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
2355                         foreach($this->simpleTypes as $typeName => $eParts){
2356                                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
2357                                 if (isset($eParts['enumeration'])) {
2358                                         foreach ($eParts['enumeration'] as $e) {
2359                                                 $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
2360                                         }
2361                                 }
2362                                 $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
2363                         }
2364                 }
2365                 // elements
2366                 if(isset($this->elements) && count($this->elements) > 0){
2367                         foreach($this->elements as $element => $eParts){
2368                                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
2369                         }
2370                 }
2371                 // attributes
2372                 if(isset($this->attributes) && count($this->attributes) > 0){
2373                         foreach($this->attributes as $attr => $aParts){
2374                                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
2375                         }
2376                 }
2377                 // finish 'er up
2378                 $attr = '';
2379                 foreach ($this->schemaInfo as $k => $v) {
2380                         if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
2381                                 $attr .= " $k=\"$v\"";
2382                         }
2383                 }
2384                 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
2385                 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
2386                         $el .= " xmlns:$nsp=\"$ns\"";
2387                 }
2388                 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
2389                 return $xml;
2390         }
2391
2392         /**
2393         * adds debug data to the clas level debug string
2394         *
2395         * @param    string $string debug data
2396         * @access   private
2397         */
2398         function xdebug($string){
2399             if($this->debugLevel > 0) {
2400                     $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
2401             }
2402         }
2403
2404     /**
2405     * get the PHP type of a user defined type in the schema
2406     * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
2407     * returns false if no type exists, or not w/ the given namespace
2408     * else returns a string that is either a native php type, or 'struct'
2409     *
2410     * @param string $type name of defined type
2411     * @param string $ns namespace of type
2412     * @return mixed
2413     * @access public
2414     * @deprecated
2415     */
2416         function getPHPType($type,$ns){
2417                 if(isset($this->typemap[$ns][$type])){
2418                         //print "found type '$type' and ns $ns in typemap<br>";
2419                         return $this->typemap[$ns][$type];
2420                 } elseif(isset($this->complexTypes[$type])){
2421                         //print "getting type '$type' and ns $ns from complexTypes array<br>";
2422                         return $this->complexTypes[$type]['phpType'];
2423                 }
2424                 return false;
2425         }
2426
2427         /**
2428     * returns an associative array of information about a given type
2429     * returns false if no type exists by the given name
2430     *
2431         *       For a complexType typeDef = array(
2432         *       'restrictionBase' => '',
2433         *       'phpType' => '',
2434         *       'compositor' => '(sequence|all)',
2435         *       'elements' => array(), // refs to elements array
2436         *       'attrs' => array() // refs to attributes array
2437         *       ... and so on (see addComplexType)
2438         *       )
2439         *
2440         *   For simpleType or element, the array has different keys.
2441     *
2442     * @param string $type
2443     * @return mixed
2444     * @access public
2445     * @see addComplexType
2446     * @see addSimpleType
2447     * @see addElement
2448     */
2449         function getTypeDef($type){
2450                 //$this->debug("in getTypeDef for type $type");
2451                 if (substr($type, -1) == '^') {
2452                         $is_element = 1;
2453                         $type = substr($type, 0, -1);
2454                 } else {
2455                         $is_element = 0;
2456                 }
2457
2458                 if((! $is_element) && isset($this->complexTypes[$type])){
2459                         $this->xdebug("in getTypeDef, found complexType $type");
2460                         return $this->complexTypes[$type];
2461                 } elseif((! $is_element) && isset($this->simpleTypes[$type])){
2462                         $this->xdebug("in getTypeDef, found simpleType $type");
2463                         if (!isset($this->simpleTypes[$type]['phpType'])) {
2464                                 // get info for type to tack onto the simple type
2465                                 // TODO: can this ever really apply (i.e. what is a simpleType really?)
2466                                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
2467                                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
2468                                 $etype = $this->getTypeDef($uqType);
2469                                 if ($etype) {
2470                                         $this->xdebug("in getTypeDef, found type for simpleType $type:");
2471                                         $this->xdebug($this->varDump($etype));
2472                                         if (isset($etype['phpType'])) {
2473                                                 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
2474                                         }
2475                                         if (isset($etype['elements'])) {
2476                                                 $this->simpleTypes[$type]['elements'] = $etype['elements'];
2477                                         }
2478                                 }
2479                         }
2480                         return $this->simpleTypes[$type];
2481                 } elseif(isset($this->elements[$type])){
2482                         $this->xdebug("in getTypeDef, found element $type");
2483                         if (!isset($this->elements[$type]['phpType'])) {
2484                                 // get info for type to tack onto the element
2485                                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
2486                                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
2487                                 $etype = $this->getTypeDef($uqType);
2488                                 if ($etype) {
2489                                         $this->xdebug("in getTypeDef, found type for element $type:");
2490                                         $this->xdebug($this->varDump($etype));
2491                                         if (isset($etype['phpType'])) {
2492                                                 $this->elements[$type]['phpType'] = $etype['phpType'];
2493                                         }
2494                                         if (isset($etype['elements'])) {
2495                                                 $this->elements[$type]['elements'] = $etype['elements'];
2496                                         }
2497                                         if (isset($etype['extensionBase'])) {
2498                                                 $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
2499                                         }
2500                                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
2501                                         $this->xdebug("in getTypeDef, element $type is an XSD type");
2502                                         $this->elements[$type]['phpType'] = 'scalar';
2503                                 }
2504                         }
2505                         return $this->elements[$type];
2506                 } elseif(isset($this->attributes[$type])){
2507                         $this->xdebug("in getTypeDef, found attribute $type");
2508                         return $this->attributes[$type];
2509                 } elseif (preg_match('/_ContainedType$/', $type)) {
2510                         $this->xdebug("in getTypeDef, have an untyped element $type");
2511                         $typeDef['typeClass'] = 'simpleType';
2512                         $typeDef['phpType'] = 'scalar';
2513                         $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
2514                         return $typeDef;
2515                 }
2516                 $this->xdebug("in getTypeDef, did not find $type");
2517                 return false;
2518         }
2519
2520         /**
2521     * returns a sample serialization of a given type, or false if no type by the given name
2522     *
2523     * @param string $type name of type
2524     * @return mixed
2525     * @access public
2526     * @deprecated
2527     */
2528     function serializeTypeDef($type){
2529         //print "in sTD() for type $type<br>";
2530         if($typeDef = $this->getTypeDef($type)){
2531                 $str .= '<'.$type;
2532             if(is_array($typeDef['attrs'])){
2533                 foreach($typeDef['attrs'] as $attName => $data){
2534                     $str .= " $attName=\"{type = ".$data['type']."}\"";
2535                 }
2536             }
2537             $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
2538             if(count($typeDef['elements']) > 0){
2539                 $str .= ">";
2540                 foreach($typeDef['elements'] as $element => $eData){
2541                     $str .= $this->serializeTypeDef($element);
2542                 }
2543                 $str .= "</$type>";
2544             } elseif($typeDef['typeClass'] == 'element') {
2545                 $str .= "></$type>";
2546             } else {
2547                 $str .= "/>";
2548             }
2549                         return $str;
2550         }
2551         return false;
2552     }
2553
2554     /**
2555     * returns HTML form elements that allow a user
2556     * to enter values for creating an instance of the given type.
2557     *
2558     * @param string $name name for type instance
2559     * @param string $type name of type
2560     * @return string
2561     * @access public
2562     * @deprecated
2563         */
2564         function typeToForm($name,$type){
2565                 // get typedef
2566                 if($typeDef = $this->getTypeDef($type)){
2567                         // if struct
2568                         if($typeDef['phpType'] == 'struct'){
2569                                 $buffer .= '<table>';
2570                                 foreach($typeDef['elements'] as $child => $childDef){
2571                                         $buffer .= "
2572                                         <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
2573                                         <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
2574                                 }
2575                                 $buffer .= '</table>';
2576                         // if array
2577                         } elseif($typeDef['phpType'] == 'array'){
2578                                 $buffer .= '<table>';
2579                                 for($i=0;$i < 3; $i++){
2580                                         $buffer .= "
2581                                         <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
2582                                         <td><input type='text' name='parameters[".$name."][]'></td></tr>";
2583                                 }
2584                                 $buffer .= '</table>';
2585                         // if scalar
2586                         } else {
2587                                 $buffer .= "<input type='text' name='parameters[$name]'>";
2588                         }
2589                 } else {
2590                         $buffer .= "<input type='text' name='parameters[$name]'>";
2591                 }
2592                 return $buffer;
2593         }
2594
2595         /**
2596         * adds a complex type to the schema
2597         *
2598         * example: array
2599         *
2600         * addType(
2601         *       'ArrayOfstring',
2602         *       'complexType',
2603         *       'array',
2604         *       '',
2605         *       'SOAP-ENC:Array',
2606         *       array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
2607         *       'xsd:string'
2608         * );
2609         *
2610         * example: PHP associative array ( SOAP Struct )
2611         *
2612         * addType(
2613         *       'SOAPStruct',
2614         *       'complexType',
2615         *       'struct',
2616         *       'all',
2617         *       array('myVar'=> array('name'=>'myVar','type'=>'string')
2618         * );
2619         *
2620         * @param name
2621         * @param typeClass (complexType|simpleType|attribute)
2622         * @param phpType: currently supported are array and struct (php assoc array)
2623         * @param compositor (all|sequence|choice)
2624         * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2625         * @param elements = array ( name = array(name=>'',type=>'') )
2626         * @param attrs = array(
2627         *       array(
2628         *               'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
2629         *               "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
2630         *       )
2631         * )
2632         * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
2633         * @access public
2634         * @see getTypeDef
2635         */
2636         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
2637                 $this->complexTypes[$name] = array(
2638             'name'              => $name,
2639             'typeClass' => $typeClass,
2640             'phpType'   => $phpType,
2641                 'compositor'=> $compositor,
2642             'restrictionBase' => $restrictionBase,
2643                 'elements'      => $elements,
2644             'attrs'             => $attrs,
2645             'arrayType' => $arrayType
2646                 );
2647
2648                 $this->xdebug("addComplexType $name:");
2649                 $this->appendDebug($this->varDump($this->complexTypes[$name]));
2650         }
2651
2652         /**
2653         * adds a simple type to the schema
2654         *
2655         * @param string $name
2656         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2657         * @param string $typeClass (should always be simpleType)
2658         * @param string $phpType (should always be scalar)
2659         * @param array $enumeration array of values
2660         * @access public
2661         * @see nusoap_xmlschema
2662         * @see getTypeDef
2663         */
2664         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
2665                 $this->simpleTypes[$name] = array(
2666             'name'                      => $name,
2667             'typeClass'         => $typeClass,
2668             'phpType'           => $phpType,
2669             'type'                      => $restrictionBase,
2670             'enumeration'       => $enumeration
2671                 );
2672
2673                 $this->xdebug("addSimpleType $name:");
2674                 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2675         }
2676
2677         /**
2678         * adds an element to the schema
2679         *
2680         * @param array $attrs attributes that must include name and type
2681         * @see nusoap_xmlschema
2682         * @access public
2683         */
2684         function addElement($attrs) {
2685                 if (! $this->getPrefix($attrs['type'])) {
2686                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2687                 }
2688                 $this->elements[ $attrs['name'] ] = $attrs;
2689                 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2690
2691                 $this->xdebug("addElement " . $attrs['name']);
2692                 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
2693         }
2694 }
2695
2696 /**
2697  * Backward compatibility
2698  */
2699 class XMLSchema extends nusoap_xmlschema {
2700 }
2701
2702 ?><?php
2703
2704 /*
2705
2706 Modification information for LGPL compliance
2707
2708 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
2709     bug 40066
2710
2711 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
2712     Merging with maint_6_0_1 (svn merge -r 58250:58342)
2713
2714 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
2715     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
2716
2717 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
2718     fix SOAP calls with no parameters
2719
2720 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
2721
2722 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
2723
2724 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
2725
2726 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
2727
2728 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
2729
2730 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
2731
2732 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
2733
2734 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
2735 - Changing all ereg function to either preg or simple string based ones
2736 - No more references to magic quotes.
2737 - Change all the session_unregister() functions to just unset() the correct session variable instead.
2738
2739 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
2740
2741 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
2742
2743 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
2744
2745 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
2746
2747 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
2748
2749 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
2750
2751 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
2752
2753 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
2754
2755 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
2756 Touched:
2757 - data/SugarBean.php
2758 - include/domit/php_http_client_generic.php
2759 - include/domit/php_http_connector.php
2760 - include/domit/testing_domit.php
2761 - include/domit/xml_domit_getelementsbypath.php
2762 - include/domit/xml_domit_lite_parser.php
2763 - include/domit/xml_domit_nodemaps.php
2764 - include/domit/xml_domit_parser.php
2765 - include/domit/xml_domit_shared.php
2766 - include/generic/SugarWidgets/SugarWidgetField.php
2767 - include/generic/SugarWidgets/SugarWidgetReportField.php
2768 - include/ListView/ProcessView.php
2769 - include/nusoap/class.soapclient.php
2770 - include/nusoap/nusoap.php
2771 - include/nusoap/nusoapmime.php
2772 - include/Pear/HTML_Safe/Safe.php
2773 - include/Pear/XML_HTMLSax3/HTMLSax3.php
2774 - modules/Administration/RebuildWorkFlow.php
2775 - modules/Expressions/RelateSelector.php
2776 - modules/Reports/templates/templates_reports.php
2777 - modules/WorkFlow/Delete.php
2778 - modules/WorkFlow/Save.php
2779 - modules/WorkFlow/SaveSequence.php
2780 - modules/WorkFlow/WorkFlow.php
2781 - modules/WorkFlowActionShells/CreateStep1.php
2782 - modules/WorkFlowActionShells/CreateStep2.php
2783 - modules/WorkFlowActionShells/Save.php
2784 - modules/WorkFlowActionShells/WorkFlowActionShell.php
2785 - modules/WorkFlowAlerts/Save.php
2786 - modules/WorkFlowAlerts/WorkFlowAlert.php
2787 - modules/WorkFlowAlertShells/DetailView.php
2788 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
2789 - modules/WorkFlowTriggerShells/CreateStep1.php
2790 - modules/WorkFlowTriggerShells/CreateStepFilter.php
2791 - modules/WorkFlowTriggerShells/SaveFilter.php
2792 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
2793 - soap/SoapHelperFunctions.php
2794 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
2795 - test/simpletest/browser.php
2796 - test/simpletest/default_reporter.php
2797 - test/simpletest/detached.php
2798 - test/simpletest/eclipse.php
2799 - test/simpletest/expectation.php
2800 - test/simpletest/extensions/pear_test_case.php
2801 - test/simpletest/form.php
2802 - test/simpletest/http.php
2803 - test/simpletest/mock_objects.php
2804 - test/simpletest/page.php
2805 - test/simpletest/parser.php
2806 - test/simpletest/remote.php
2807 - test/simpletest/shell_tester.php
2808 - test/simpletest/simple_test.php
2809 - test/simpletest/simpletest.php
2810 - test/simpletest/test/acceptance_test.php
2811 - test/simpletest/test/adapter_test.php
2812 - test/simpletest/test/authentication_test.php
2813 - test/simpletest/test/browser_test.php
2814 - test/simpletest/test/collector_test.php
2815 - test/simpletest/test/compatibility_test.php
2816 - test/simpletest/test/detached_test.php
2817 - test/simpletest/test/eclipse_test.php
2818 - test/simpletest/test/encoding_test.php
2819 - test/simpletest/test/errors_test.php
2820 - test/simpletest/test/expectation_test.php
2821 - test/simpletest/test/form_test.php
2822 - test/simpletest/test/frames_test.php
2823 - test/simpletest/test/http_test.php
2824 - test/simpletest/test/live_test.php
2825 - test/simpletest/test/mock_objects_test.php
2826 - test/simpletest/test/page_test.php
2827 - test/simpletest/test/parse_error_test.php
2828 - test/simpletest/test/parser_test.php
2829 - test/simpletest/test/remote_test.php
2830 - test/simpletest/test/shell_test.php
2831 - test/simpletest/test/shell_tester_test.php
2832 - test/simpletest/test/simpletest_test.php
2833 - test/simpletest/test/site/page_request.php
2834 - test/simpletest/test/tag_test.php
2835 - test/simpletest/test/unit_tester_test.php
2836 - test/simpletest/test/user_agent_test.php
2837 - test/simpletest/test/visual_test.php
2838 - test/simpletest/test/xml_test.php
2839 - test/simpletest/test_case.php
2840 - test/simpletest/ui/array_reporter/test.php
2841 - test/simpletest/ui/recorder/test.php
2842 - test/simpletest/unit_tester.php
2843 - test/simpletest/url.php
2844 - test/simpletest/user_agent.php
2845 - test/simpletest/web_tester.php
2846 - test/spikephpcoverage/src/PEAR.php
2847 - test/spikephpcoverage/src/util/Utility.php
2848 - test/spikephpcoverage/src/XML/Parser.php
2849 - test/spikephpcoverage/src/XML/Parser/Simple.php
2850 - test/test_utilities/SugarTest_SimpleBrowser.php
2851
2852 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
2853
2854 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
2855
2856 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
2857
2858 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
2859
2860 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
2861
2862 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
2863
2864 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
2865
2866 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
2867
2868 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
2869
2870 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
2871
2872 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
2873
2874 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
2875
2876 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
2877
2878 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
2879
2880 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
2881
2882 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
2883
2884 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
2885
2886 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
2887
2888 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
2889
2890 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
2891
2892 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
2893
2894 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
2895
2896 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
2897
2898 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
2899
2900
2901 */
2902
2903
2904
2905
2906
2907 /**
2908 * For creating serializable abstractions of native PHP types.  This class
2909 * allows element name/namespace, XSD type, and XML attributes to be
2910 * associated with a value.  This is extremely useful when WSDL is not
2911 * used, but is also useful when WSDL is used with polymorphic types, including
2912 * xsd:anyType and user-defined types.
2913 *
2914 * @author   Dietrich Ayala <dietrich@ganx4.com>
2915
2916 * @access   public
2917 */
2918 class soapval extends nusoap_base {
2919         /**
2920          * The XML element name
2921          *
2922          * @var string
2923          * @access private
2924          */
2925         var $name;
2926         /**
2927          * The XML type name (string or false)
2928          *
2929          * @var mixed
2930          * @access private
2931          */
2932         var $type;
2933         /**
2934          * The PHP value
2935          *
2936          * @var mixed
2937          * @access private
2938          */
2939         var $value;
2940         /**
2941          * The XML element namespace (string or false)
2942          *
2943          * @var mixed
2944          * @access private
2945          */
2946         var $element_ns;
2947         /**
2948          * The XML type namespace (string or false)
2949          *
2950          * @var mixed
2951          * @access private
2952          */
2953         var $type_ns;
2954         /**
2955          * The XML element attributes (array or false)
2956          *
2957          * @var mixed
2958          * @access private
2959          */
2960         var $attributes;
2961
2962         /**
2963         * constructor
2964         *
2965         * @param    string $name optional name
2966         * @param    mixed $type optional type name
2967         * @param        mixed $value optional value
2968         * @param        mixed $element_ns optional namespace of value
2969         * @param        mixed $type_ns optional namespace of type
2970         * @param        mixed $attributes associative array of attributes to add to element serialization
2971         * @access   public
2972         */
2973         function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
2974                 parent::nusoap_base();
2975                 $this->name = $name;
2976                 $this->type = $type;
2977                 $this->value = $value;
2978                 $this->element_ns = $element_ns;
2979                 $this->type_ns = $type_ns;
2980                 $this->attributes = $attributes;
2981     }
2982
2983         /**
2984         * return serialized value
2985         *
2986         * @param        string $use The WSDL use value (encoded|literal)
2987         * @return       string XML data
2988         * @access   public
2989         */
2990         function serialize($use='encoded') {
2991                 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2992     }
2993
2994         /**
2995         * decodes a soapval object into a PHP native type
2996         *
2997         * @return       mixed
2998         * @access   public
2999         */
3000         function decode(){
3001                 return $this->value;
3002         }
3003 }
3004
3005
3006
3007 ?><?php
3008
3009 /*
3010
3011 Modification information for LGPL compliance
3012
3013 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
3014     bug 40066
3015
3016 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
3017     Merging with maint_6_0_1 (svn merge -r 58250:58342)
3018
3019 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
3020     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
3021
3022 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
3023     fix SOAP calls with no parameters
3024
3025 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
3026
3027 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
3028
3029 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
3030
3031 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
3032
3033 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
3034
3035 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
3036
3037 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
3038
3039 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
3040 - Changing all ereg function to either preg or simple string based ones
3041 - No more references to magic quotes.
3042 - Change all the session_unregister() functions to just unset() the correct session variable instead.
3043
3044 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
3045
3046 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
3047
3048 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
3049
3050 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
3051
3052 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
3053
3054 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
3055
3056 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
3057
3058 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
3059
3060 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
3061 Touched:
3062 - data/SugarBean.php
3063 - include/domit/php_http_client_generic.php
3064 - include/domit/php_http_connector.php
3065 - include/domit/testing_domit.php
3066 - include/domit/xml_domit_getelementsbypath.php
3067 - include/domit/xml_domit_lite_parser.php
3068 - include/domit/xml_domit_nodemaps.php
3069 - include/domit/xml_domit_parser.php
3070 - include/domit/xml_domit_shared.php
3071 - include/generic/SugarWidgets/SugarWidgetField.php
3072 - include/generic/SugarWidgets/SugarWidgetReportField.php
3073 - include/ListView/ProcessView.php
3074 - include/nusoap/class.soapclient.php
3075 - include/nusoap/nusoap.php
3076 - include/nusoap/nusoapmime.php
3077 - include/Pear/HTML_Safe/Safe.php
3078 - include/Pear/XML_HTMLSax3/HTMLSax3.php
3079 - modules/Administration/RebuildWorkFlow.php
3080 - modules/Expressions/RelateSelector.php
3081 - modules/Reports/templates/templates_reports.php
3082 - modules/WorkFlow/Delete.php
3083 - modules/WorkFlow/Save.php
3084 - modules/WorkFlow/SaveSequence.php
3085 - modules/WorkFlow/WorkFlow.php
3086 - modules/WorkFlowActionShells/CreateStep1.php
3087 - modules/WorkFlowActionShells/CreateStep2.php
3088 - modules/WorkFlowActionShells/Save.php
3089 - modules/WorkFlowActionShells/WorkFlowActionShell.php
3090 - modules/WorkFlowAlerts/Save.php
3091 - modules/WorkFlowAlerts/WorkFlowAlert.php
3092 - modules/WorkFlowAlertShells/DetailView.php
3093 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
3094 - modules/WorkFlowTriggerShells/CreateStep1.php
3095 - modules/WorkFlowTriggerShells/CreateStepFilter.php
3096 - modules/WorkFlowTriggerShells/SaveFilter.php
3097 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
3098 - soap/SoapHelperFunctions.php
3099 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
3100 - test/simpletest/browser.php
3101 - test/simpletest/default_reporter.php
3102 - test/simpletest/detached.php
3103 - test/simpletest/eclipse.php
3104 - test/simpletest/expectation.php
3105 - test/simpletest/extensions/pear_test_case.php
3106 - test/simpletest/form.php
3107 - test/simpletest/http.php
3108 - test/simpletest/mock_objects.php
3109 - test/simpletest/page.php
3110 - test/simpletest/parser.php
3111 - test/simpletest/remote.php
3112 - test/simpletest/shell_tester.php
3113 - test/simpletest/simple_test.php
3114 - test/simpletest/simpletest.php
3115 - test/simpletest/test/acceptance_test.php
3116 - test/simpletest/test/adapter_test.php
3117 - test/simpletest/test/authentication_test.php
3118 - test/simpletest/test/browser_test.php
3119 - test/simpletest/test/collector_test.php
3120 - test/simpletest/test/compatibility_test.php
3121 - test/simpletest/test/detached_test.php
3122 - test/simpletest/test/eclipse_test.php
3123 - test/simpletest/test/encoding_test.php
3124 - test/simpletest/test/errors_test.php
3125 - test/simpletest/test/expectation_test.php
3126 - test/simpletest/test/form_test.php
3127 - test/simpletest/test/frames_test.php
3128 - test/simpletest/test/http_test.php
3129 - test/simpletest/test/live_test.php
3130 - test/simpletest/test/mock_objects_test.php
3131 - test/simpletest/test/page_test.php
3132 - test/simpletest/test/parse_error_test.php
3133 - test/simpletest/test/parser_test.php
3134 - test/simpletest/test/remote_test.php
3135 - test/simpletest/test/shell_test.php
3136 - test/simpletest/test/shell_tester_test.php
3137 - test/simpletest/test/simpletest_test.php
3138 - test/simpletest/test/site/page_request.php
3139 - test/simpletest/test/tag_test.php
3140 - test/simpletest/test/unit_tester_test.php
3141 - test/simpletest/test/user_agent_test.php
3142 - test/simpletest/test/visual_test.php
3143 - test/simpletest/test/xml_test.php
3144 - test/simpletest/test_case.php
3145 - test/simpletest/ui/array_reporter/test.php
3146 - test/simpletest/ui/recorder/test.php
3147 - test/simpletest/unit_tester.php
3148 - test/simpletest/url.php
3149 - test/simpletest/user_agent.php
3150 - test/simpletest/web_tester.php
3151 - test/spikephpcoverage/src/PEAR.php
3152 - test/spikephpcoverage/src/util/Utility.php
3153 - test/spikephpcoverage/src/XML/Parser.php
3154 - test/spikephpcoverage/src/XML/Parser/Simple.php
3155 - test/test_utilities/SugarTest_SimpleBrowser.php
3156
3157 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
3158
3159 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
3160
3161 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
3162
3163 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
3164
3165 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
3166
3167 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
3168
3169 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
3170
3171 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
3172
3173 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
3174
3175 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
3176
3177 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
3178
3179 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
3180
3181 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
3182
3183 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
3184
3185 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
3186
3187 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
3188
3189 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
3190
3191 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
3192
3193 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
3194
3195 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
3196
3197 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
3198
3199 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
3200
3201 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
3202
3203 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
3204
3205
3206 */
3207
3208
3209
3210
3211
3212 /**
3213 * transport class for sending/receiving data via HTTP and HTTPS
3214 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
3215 *
3216 * @author   Dietrich Ayala <dietrich@ganx4.com>
3217 * @author   Scott Nichol <snichol@users.sourceforge.net>
3218
3219 * @access public
3220 */
3221 class soap_transport_http extends nusoap_base {
3222
3223         var $url = '';
3224         var $uri = '';
3225         var $digest_uri = '';
3226         var $scheme = '';
3227         var $host = '';
3228         var $port = '';
3229         var $path = '';
3230         var $request_method = 'POST';
3231         var $protocol_version = '1.0';
3232         var $encoding = '';
3233         var $outgoing_headers = array();
3234         var $incoming_headers = array();
3235         var $incoming_cookies = array();
3236         var $outgoing_payload = '';
3237         var $incoming_payload = '';
3238         var $response_status_line;      // HTTP response status line
3239         var $useSOAPAction = true;
3240         var $persistentConnection = false;
3241         var $ch = false;        // cURL handle
3242         var $ch_options = array();      // cURL custom options
3243         var $use_curl = false;          // force cURL use
3244         var $proxy = null;                      // proxy information (associative array)
3245         var $username = '';
3246         var $password = '';
3247         var $authtype = '';
3248         var $digestRequest = array();
3249         var $certRequest = array();     // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
3250                                                                 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
3251                                                                 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
3252                                                                 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
3253                                                                 // passphrase: SSL key password/passphrase
3254                                                                 // certpassword: SSL certificate password
3255                                                                 // verifypeer: default is 1
3256                                                                 // verifyhost: default is 1
3257
3258         /**
3259         * constructor
3260         *
3261         * @param string $url The URL to which to connect
3262         * @param array $curl_options User-specified cURL options
3263         * @param boolean $use_curl Whether to try to force cURL use
3264         * @access public
3265         */
3266         function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
3267                 parent::nusoap_base();
3268                 $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
3269                 $this->appendDebug($this->varDump($curl_options));
3270                 $this->setURL($url);
3271                 if (is_array($curl_options)) {
3272                         $this->ch_options = $curl_options;
3273                 }
3274                 $this->use_curl = $use_curl;
3275                 preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
3276                 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
3277         }
3278
3279         /**
3280         * sets a cURL option
3281         *
3282         * @param        mixed $option The cURL option (always integer?)
3283         * @param        mixed $value The cURL option value
3284         * @access   private
3285         */
3286         function setCurlOption($option, $value) {
3287                 $this->debug("setCurlOption option=$option, value=");
3288                 $this->appendDebug($this->varDump($value));
3289                 curl_setopt($this->ch, $option, $value);
3290         }
3291
3292         /**
3293         * sets an HTTP header
3294         *
3295         * @param string $name The name of the header
3296         * @param string $value The value of the header
3297         * @access private
3298         */
3299         function setHeader($name, $value) {
3300                 $this->outgoing_headers[$name] = $value;
3301                 $this->debug("set header $name: $value");
3302         }
3303
3304         /**
3305         * unsets an HTTP header
3306         *
3307         * @param string $name The name of the header
3308         * @access private
3309         */
3310         function unsetHeader($name) {
3311                 if (isset($this->outgoing_headers[$name])) {
3312                         $this->debug("unset header $name");
3313                         unset($this->outgoing_headers[$name]);
3314                 }
3315         }
3316
3317         /**
3318         * sets the URL to which to connect
3319         *
3320         * @param string $url The URL to which to connect
3321         * @access private
3322         */
3323         function setURL($url) {
3324                 $this->url = $url;
3325
3326                 $u = parse_url($url);
3327                 foreach($u as $k => $v){
3328                         $this->debug("parsed URL $k = $v");
3329                         $this->$k = $v;
3330                 }
3331
3332                 // add any GET params to path
3333                 if(isset($u['query']) && $u['query'] != ''){
3334             $this->path .= '?' . $u['query'];
3335                 }
3336
3337                 // set default port
3338                 if(!isset($u['port'])){
3339                         if($u['scheme'] == 'https'){
3340                                 $this->port = 443;
3341                         } else {
3342                                 $this->port = 80;
3343                         }
3344                 }
3345
3346                 $this->uri = $this->path;
3347                 $this->digest_uri = $this->uri;
3348
3349                 // build headers
3350                 if (!isset($u['port'])) {
3351                         $this->setHeader('Host', $this->host);
3352                 } else {
3353                         $this->setHeader('Host', $this->host.':'.$this->port);
3354                 }
3355
3356                 if (isset($u['user']) && $u['user'] != '') {
3357                         $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
3358                 }
3359         }
3360
3361         /**
3362         * gets the I/O method to use
3363         *
3364         * @return       string  I/O method to use (socket|curl|unknown)
3365         * @access       private
3366         */
3367         function io_method() {
3368                 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
3369                         return 'curl';
3370                 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
3371                         return 'socket';
3372                 return 'unknown';
3373         }
3374
3375         /**
3376         * establish an HTTP connection
3377         *
3378         * @param    integer $timeout set connection timeout in seconds
3379         * @param        integer $response_timeout set response timeout in seconds
3380         * @return       boolean true if connected, false if not
3381         * @access   private
3382         */
3383         function connect($connection_timeout=0,$response_timeout=30){
3384                 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
3385                 // "regular" socket.
3386                 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
3387                 //       loaded), and until PHP5 stream_get_wrappers is not available.
3388 //              if ($this->scheme == 'https') {
3389 //                      if (version_compare(phpversion(), '4.3.0') >= 0) {
3390 //                              if (extension_loaded('openssl')) {
3391 //                                      $this->scheme = 'ssl';
3392 //                                      $this->debug('Using SSL over OpenSSL');
3393 //                              }
3394 //                      }
3395 //              }
3396                 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
3397           if ($this->io_method() == 'socket') {
3398                 if (!is_array($this->proxy)) {
3399                         $host = $this->host;
3400                         $port = $this->port;
3401                 } else {
3402                         $host = $this->proxy['host'];
3403                         $port = $this->proxy['port'];
3404                 }
3405
3406                 // use persistent connection
3407                 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
3408                         if (!feof($this->fp)) {
3409                                 $this->debug('Re-use persistent connection');
3410                                 return true;
3411                         }
3412                         fclose($this->fp);
3413                         $this->debug('Closed persistent connection at EOF');
3414                 }
3415
3416                 // munge host if using OpenSSL
3417                 if ($this->scheme == 'ssl') {
3418                         $host = 'ssl://' . $host;
3419                 }
3420                 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
3421
3422                 // open socket
3423                 if($connection_timeout > 0){
3424                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout);
3425                 } else {
3426                         $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str);
3427                 }
3428
3429                 // test pointer
3430                 if(!$this->fp) {
3431                         $msg = 'Couldn\'t open socket connection to server ' . $this->url;
3432                         if ($this->errno) {
3433                                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
3434                         } else {
3435                                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';
3436                         }
3437                         $this->debug($msg);
3438                         $this->setError($msg);
3439                         return false;
3440                 }
3441
3442                 // set response timeout
3443                 $this->debug('set response timeout to ' . $response_timeout);
3444                 socket_set_timeout( $this->fp, $response_timeout);
3445
3446                 $this->debug('socket connected');
3447                 return true;
3448           } else if ($this->io_method() == 'curl') {
3449                 if (!extension_loaded('curl')) {
3450 //                      $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
3451                         $this->setError('The PHP cURL Extension is required for HTTPS or NLTM.  You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.');
3452                         return false;
3453                 }
3454                 // Avoid warnings when PHP does not have these options
3455                 if (defined('CURLOPT_CONNECTIONTIMEOUT'))
3456                         $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
3457                 else
3458                         $CURLOPT_CONNECTIONTIMEOUT = 78;
3459                 if (defined('CURLOPT_HTTPAUTH'))
3460                         $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
3461                 else
3462                         $CURLOPT_HTTPAUTH = 107;
3463                 if (defined('CURLOPT_PROXYAUTH'))
3464                         $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
3465                 else
3466                         $CURLOPT_PROXYAUTH = 111;
3467                 if (defined('CURLAUTH_BASIC'))
3468                         $CURLAUTH_BASIC = CURLAUTH_BASIC;
3469                 else
3470                         $CURLAUTH_BASIC = 1;
3471                 if (defined('CURLAUTH_DIGEST'))
3472                         $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
3473                 else
3474                         $CURLAUTH_DIGEST = 2;
3475                 if (defined('CURLAUTH_NTLM'))
3476                         $CURLAUTH_NTLM = CURLAUTH_NTLM;
3477                 else
3478                         $CURLAUTH_NTLM = 8;
3479
3480                 $this->debug('connect using cURL');
3481                 // init CURL
3482                 $this->ch = curl_init();
3483                 // set url
3484                 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
3485                 // add path
3486                 $hostURL .= $this->path;
3487                 $this->setCurlOption(CURLOPT_URL, $hostURL);
3488                 // follow location headers (re-directs)
3489                 if (ini_get('safe_mode') || ini_get('open_basedir')) {
3490                         $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
3491                         $this->debug('safe_mode = ');
3492                         $this->appendDebug($this->varDump(ini_get('safe_mode')));
3493                         $this->debug('open_basedir = ');
3494                         $this->appendDebug($this->varDump(ini_get('open_basedir')));
3495                 } else {
3496                         $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
3497                 }
3498                 // ask for headers in the response output
3499                 $this->setCurlOption(CURLOPT_HEADER, 1);
3500                 // ask for the response output as the return value
3501                 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
3502                 // encode
3503                 // We manage this ourselves through headers and encoding
3504 //              if(function_exists('gzuncompress')){
3505 //                      $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
3506 //              }
3507                 // persistent connection
3508                 if ($this->persistentConnection) {
3509                         // I believe the following comment is now bogus, having applied to
3510                         // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
3511                         // The way we send data, we cannot use persistent connections, since
3512                         // there will be some "junk" at the end of our request.
3513                         //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
3514                         $this->persistentConnection = false;
3515                         $this->setHeader('Connection', 'close');
3516                 }
3517                 // set timeouts
3518                 if ($connection_timeout != 0) {
3519                         $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
3520                 }
3521                 if ($response_timeout != 0) {
3522                         $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
3523                 }
3524
3525                 if ($this->scheme == 'https') {
3526                         $this->debug('set cURL SSL verify options');
3527                         // recent versions of cURL turn on peer/host checking by default,
3528                         // while PHP binaries are not compiled with a default location for the
3529                         // CA cert bundle, so disable peer/host checking.
3530                         //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
3531                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
3532                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
3533
3534                         // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
3535                         if ($this->authtype == 'certificate') {
3536                                 $this->debug('set cURL certificate options');
3537                                 if (isset($this->certRequest['cainfofile'])) {
3538                                         $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
3539                                 }
3540                                 if (isset($this->certRequest['verifypeer'])) {
3541                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
3542                                 } else {
3543                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
3544                                 }
3545                                 if (isset($this->certRequest['verifyhost'])) {
3546                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
3547                                 } else {
3548                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
3549                                 }
3550                                 if (isset($this->certRequest['sslcertfile'])) {
3551                                         $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
3552                                 }
3553                                 if (isset($this->certRequest['sslkeyfile'])) {
3554                                         $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
3555                                 }
3556                                 if (isset($this->certRequest['passphrase'])) {
3557                                         $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
3558                                 }
3559                                 if (isset($this->certRequest['certpassword'])) {
3560                                         $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
3561                                 }
3562                         }
3563                 }
3564                 if ($this->authtype && ($this->authtype != 'certificate')) {
3565                         if ($this->username) {
3566                                 $this->debug('set cURL username/password');
3567                                 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
3568                         }
3569                         if ($this->authtype == 'basic') {
3570                                 $this->debug('set cURL for Basic authentication');
3571                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
3572                         }
3573                         if ($this->authtype == 'digest') {
3574                                 $this->debug('set cURL for digest authentication');
3575                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
3576                         }
3577                         if ($this->authtype == 'ntlm') {
3578                                 $this->debug('set cURL for NTLM authentication');
3579                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
3580                         }
3581                 }
3582                 if (is_array($this->proxy)) {
3583                         $this->debug('set cURL proxy options');
3584                         if ($this->proxy['port'] != '') {
3585                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
3586                         } else {
3587                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
3588                         }
3589                         if ($this->proxy['username'] || $this->proxy['password']) {
3590                                 $this->debug('set cURL proxy authentication options');
3591                                 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
3592                                 if ($this->proxy['authtype'] == 'basic') {
3593                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
3594                                 }
3595                                 if ($this->proxy['authtype'] == 'ntlm') {
3596                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
3597                                 }
3598                         }
3599                 }
3600                 $this->debug('cURL connection set up');
3601                 return true;
3602           } else {
3603                 $this->setError('Unknown scheme ' . $this->scheme);
3604                 $this->debug('Unknown scheme ' . $this->scheme);
3605                 return false;
3606           }
3607         }
3608
3609         /**
3610         * sends the SOAP request and gets the SOAP response via HTTP[S]
3611         *
3612         * @param    string $data message data
3613         * @param    integer $timeout set connection timeout in seconds
3614         * @param        integer $response_timeout set response timeout in seconds
3615         * @param        array $cookies cookies to send
3616         * @return       string data
3617         * @access   public
3618         */
3619         function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
3620
3621                 $this->debug('entered send() with data of length: '.strlen($data));
3622
3623                 $this->tryagain = true;
3624                 $tries = 0;
3625                 while ($this->tryagain) {
3626                         $this->tryagain = false;
3627                         if ($tries++ < 2) {
3628                                 // make connnection
3629                                 if (!$this->connect($timeout, $response_timeout)){
3630                                         return false;
3631                                 }
3632
3633                                 // send request
3634                                 if (!$this->sendRequest($data, $cookies)){
3635                                         return false;
3636                                 }
3637
3638                                 // get response
3639                                 $respdata = $this->getResponse();
3640                         } else {
3641                                 $this->setError("Too many tries to get an OK response ($this->response_status_line)");
3642                         }
3643                 }
3644                 $this->debug('end of send()');
3645                 return $respdata;
3646         }
3647
3648
3649         /**
3650         * sends the SOAP request and gets the SOAP response via HTTPS using CURL
3651         *
3652         * @param    string $data message data
3653         * @param    integer $timeout set connection timeout in seconds
3654         * @param        integer $response_timeout set response timeout in seconds
3655         * @param        array $cookies cookies to send
3656         * @return       string data
3657         * @access   public
3658         * @deprecated
3659         */
3660         function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
3661                 return $this->send($data, $timeout, $response_timeout, $cookies);
3662         }
3663
3664         /**
3665         * if authenticating, set user credentials here
3666         *
3667         * @param    string $username
3668         * @param    string $password
3669         * @param        string $authtype (basic|digest|certificate|ntlm)
3670         * @param        array $digestRequest (keys must be nonce, nc, realm, qop)
3671         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
3672         * @access   public
3673         */
3674         function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
3675                 $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
3676                 $this->appendDebug($this->varDump($digestRequest));
3677                 $this->debug("certRequest=");
3678                 $this->appendDebug($this->varDump($certRequest));
3679                 // cf. RFC 2617
3680                 if ($authtype == 'basic') {
3681                         $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
3682                 } elseif ($authtype == 'digest') {
3683                         if (isset($digestRequest['nonce'])) {
3684                                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
3685
3686                                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
3687
3688                                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
3689                                 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
3690
3691                                 // H(A1) = MD5(A1)
3692                                 $HA1 = md5($A1);
3693
3694                                 // A2 = Method ":" digest-uri-value
3695                                 $A2 = $this->request_method . ':' . $this->digest_uri;
3696
3697                                 // H(A2)
3698                                 $HA2 =  md5($A2);
3699
3700                                 // KD(secret, data) = H(concat(secret, ":", data))
3701                                 // if qop == auth:
3702                                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
3703                                 //                              ":" nc-value
3704                                 //                              ":" unq(cnonce-value)
3705                                 //                              ":" unq(qop-value)
3706                                 //                              ":" H(A2)
3707                                 //                            ) <">
3708                                 // if qop is missing,
3709                                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
3710
3711                                 $unhashedDigest = '';
3712                                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
3713                                 $cnonce = $nonce;
3714                                 if ($digestRequest['qop'] != '') {
3715                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
3716                                 } else {
3717                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
3718                                 }
3719
3720                                 $hashedDigest = md5($unhashedDigest);
3721
3722                                 $opaque = '';
3723                                 if (isset($digestRequest['opaque'])) {
3724                                         $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
3725                                 }
3726
3727                                 $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
3728                         }
3729                 } elseif ($authtype == 'certificate') {
3730                         $this->certRequest = $certRequest;
3731                         $this->debug('Authorization header not set for certificate');
3732                 } elseif ($authtype == 'ntlm') {
3733                         // do nothing
3734                         $this->debug('Authorization header not set for ntlm');
3735                 }
3736                 $this->username = $username;
3737                 $this->password = $password;
3738                 $this->authtype = $authtype;
3739                 $this->digestRequest = $digestRequest;
3740         }
3741
3742         /**
3743         * set the soapaction value
3744         *
3745         * @param    string $soapaction
3746         * @access   public
3747         */
3748         function setSOAPAction($soapaction) {
3749                 $this->setHeader('SOAPAction', '"' . $soapaction . '"');
3750         }
3751
3752         /**
3753         * use http encoding
3754         *
3755         * @param    string $enc encoding style. supported values: gzip, deflate, or both
3756         * @access   public
3757         */
3758         function setEncoding($enc='gzip, deflate') {
3759                 if (function_exists('gzdeflate')) {
3760                         $this->protocol_version = '1.1';
3761                         $this->setHeader('Accept-Encoding', $enc);
3762                         if (!isset($this->outgoing_headers['Connection'])) {
3763                                 $this->setHeader('Connection', 'close');
3764                                 $this->persistentConnection = false;
3765                         }
3766                         // deprecated as of PHP 5.3.0
3767                         //set_magic_quotes_runtime(0);
3768                         $this->encoding = $enc;
3769                 }
3770         }
3771
3772         /**
3773         * set proxy info here
3774         *
3775         * @param    string $proxyhost use an empty string to remove proxy
3776         * @param    string $proxyport
3777         * @param        string $proxyusername
3778         * @param        string $proxypassword
3779         * @param        string $proxyauthtype (basic|ntlm)
3780         * @access   public
3781         */
3782         function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
3783                 if ($proxyhost) {
3784                         $this->proxy = array(
3785                                 'host' => $proxyhost,
3786                                 'port' => $proxyport,
3787                                 'username' => $proxyusername,
3788                                 'password' => $proxypassword,
3789                                 'authtype' => $proxyauthtype
3790                         );
3791                         if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
3792                                 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
3793                         }
3794                 } else {
3795                         $this->debug('remove proxy');
3796                         $proxy = null;
3797                         unsetHeader('Proxy-Authorization');
3798                 }
3799         }
3800
3801
3802         /**
3803          * Test if the given string starts with a header that is to be skipped.
3804          * Skippable headers result from chunked transfer and proxy requests.
3805          *
3806          * @param       string $data The string to check.
3807          * @returns     boolean Whether a skippable header was found.
3808          * @access      private
3809          */
3810         function isSkippableCurlHeader(&$data) {
3811                 $skipHeaders = array(   'HTTP/1.1 100',
3812                                                                 'HTTP/1.0 301',
3813                                                                 'HTTP/1.1 301',
3814                                                                 'HTTP/1.0 302',
3815                                                                 'HTTP/1.1 302',
3816                                                                 'HTTP/1.0 401',
3817                                                                 'HTTP/1.1 401',
3818                                                                 'HTTP/1.0 200 Connection established');
3819                 foreach ($skipHeaders as $hd) {
3820                         $prefix = substr($data, 0, strlen($hd));
3821                         if ($prefix == $hd) return true;
3822                 }
3823
3824                 return false;
3825         }
3826
3827         /**
3828         * decode a string that is encoded w/ "chunked' transfer encoding
3829         * as defined in RFC2068 19.4.6
3830         *
3831         * @param    string $buffer
3832         * @param    string $lb
3833         * @returns      string
3834         * @access   public
3835         * @deprecated
3836         */
3837         function decodeChunked($buffer, $lb){
3838                 // length := 0
3839                 $length = 0;
3840                 $new = '';
3841
3842                 // read chunk-size, chunk-extension (if any) and CRLF
3843                 // get the position of the linebreak
3844                 $chunkend = strpos($buffer, $lb);
3845                 if ($chunkend == FALSE) {
3846                         $this->debug('no linebreak found in decodeChunked');
3847                         return $new;
3848                 }
3849                 $temp = substr($buffer,0,$chunkend);
3850                 $chunk_size = hexdec( trim($temp) );
3851                 $chunkstart = $chunkend + strlen($lb);
3852                 // while (chunk-size > 0) {
3853                 while ($chunk_size > 0) {
3854                         $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
3855                         $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
3856
3857                         // Just in case we got a broken connection
3858                         if ($chunkend == FALSE) {
3859                             $chunk = substr($buffer,$chunkstart);
3860                                 // append chunk-data to entity-body
3861                         $new .= $chunk;
3862                             $length += strlen($chunk);
3863                             break;
3864                         }
3865
3866                         // read chunk-data and CRLF
3867                         $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
3868                         // append chunk-data to entity-body
3869                         $new .= $chunk;
3870                         // length := length + chunk-size
3871                         $length += strlen($chunk);
3872                         // read chunk-size and CRLF
3873                         $chunkstart = $chunkend + strlen($lb);
3874
3875                         $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
3876                         if ($chunkend == FALSE) {
3877                                 break; //Just in case we got a broken connection
3878                         }
3879                         $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
3880                         $chunk_size = hexdec( trim($temp) );
3881                         $chunkstart = $chunkend;
3882                 }
3883                 return $new;
3884         }
3885
3886         /**
3887          * Writes the payload, including HTTP headers, to $this->outgoing_payload.
3888          *
3889          * @param       string $data HTTP body
3890          * @param       string $cookie_str data for HTTP Cookie header
3891          * @return      void
3892          * @access      private
3893          */
3894         function buildPayload($data, $cookie_str = '') {
3895                 // Note: for cURL connections, $this->outgoing_payload is ignored,
3896                 // as is the Content-Length header, but these are still created as
3897                 // debugging guides.
3898
3899                 // add content-length header
3900                 if ($this->request_method != 'GET') {
3901                         $this->setHeader('Content-Length', strlen($data));
3902                 }
3903
3904                 // start building outgoing payload:
3905                 if ($this->proxy) {
3906                         $uri = $this->url;
3907                 } else {
3908                         $uri = $this->uri;
3909                 }
3910                 $req = "$this->request_method $uri HTTP/$this->protocol_version";
3911                 $this->debug("HTTP request: $req");
3912                 $this->outgoing_payload = "$req\r\n";
3913
3914                 // loop thru headers, serializing
3915                 foreach($this->outgoing_headers as $k => $v){
3916                         $hdr = $k.': '.$v;
3917                         $this->debug("HTTP header: $hdr");
3918                         $this->outgoing_payload .= "$hdr\r\n";
3919                 }
3920
3921                 // add any cookies
3922                 if ($cookie_str != '') {
3923                         $hdr = 'Cookie: '.$cookie_str;
3924                         $this->debug("HTTP header: $hdr");
3925                         $this->outgoing_payload .= "$hdr\r\n";
3926                 }
3927
3928                 // header/body separator
3929                 $this->outgoing_payload .= "\r\n";
3930
3931                 // add data
3932                 $this->outgoing_payload .= $data;
3933         }
3934
3935         /**
3936         * sends the SOAP request via HTTP[S]
3937         *
3938         * @param    string $data message data
3939         * @param        array $cookies cookies to send
3940         * @return       boolean true if OK, false if problem
3941         * @access   private
3942         */
3943         function sendRequest($data, $cookies = NULL) {
3944                 // build cookie string
3945                 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
3946
3947                 // build payload
3948                 $this->buildPayload($data, $cookie_str);
3949
3950           if ($this->io_method() == 'socket') {
3951                 // send payload
3952                 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
3953                         $this->setError('couldn\'t write message data to socket');
3954                         $this->debug('couldn\'t write message data to socket');
3955                         return false;
3956                 }
3957                 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
3958                 return true;
3959           } else if ($this->io_method() == 'curl') {
3960                 // set payload
3961                 // cURL does say this should only be the verb, and in fact it
3962                 // turns out that the URI and HTTP version are appended to this, which
3963                 // some servers refuse to work with (so we no longer use this method!)
3964                 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
3965                 $curl_headers = array();
3966                 foreach($this->outgoing_headers as $k => $v){
3967                         if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
3968                                 $this->debug("Skip cURL header $k: $v");
3969                         } else {
3970                                 $curl_headers[] = "$k: $v";
3971                         }
3972                 }
3973                 if ($cookie_str != '') {
3974                         $curl_headers[] = 'Cookie: ' . $cookie_str;
3975                 }
3976                 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
3977                 $this->debug('set cURL HTTP headers');
3978                 if ($this->request_method == "POST") {
3979                         $this->setCurlOption(CURLOPT_POST, 1);
3980                         $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
3981                         $this->debug('set cURL POST data');
3982                 } else {
3983                 }
3984                 // insert custom user-set cURL options
3985                 foreach ($this->ch_options as $key => $val) {
3986                         $this->setCurlOption($key, $val);
3987                 }
3988
3989                 $this->debug('set cURL payload');
3990                 return true;
3991           }
3992         }
3993
3994         /**
3995         * gets the SOAP response via HTTP[S]
3996         *
3997         * @return       string the response (also sets member variables like incoming_payload)
3998         * @access   private
3999         */
4000         function getResponse(){
4001                 $this->incoming_payload = '';
4002
4003           if ($this->io_method() == 'socket') {
4004             // loop until headers have been retrieved
4005             $data = '';
4006             while (!isset($lb)){
4007
4008                         // We might EOF during header read.
4009                         if(feof($this->fp)) {
4010                                 $this->incoming_payload = $data;
4011                                 $this->debug('found no headers before EOF after length ' . strlen($data));
4012                                 $this->debug("received before EOF:\n" . $data);
4013                                 $this->setError('server failed to send headers');
4014                                 return false;
4015                         }
4016
4017                         $tmp = fgets($this->fp, 256);
4018                         $tmplen = strlen($tmp);
4019                         $this->debug("read line of $tmplen bytes: " . trim($tmp));
4020
4021                         if ($tmplen == 0) {
4022                                 $this->incoming_payload = $data;
4023                                 $this->debug('socket read of headers timed out after length ' . strlen($data));
4024                                 $this->debug("read before timeout: " . $data);
4025                                 $this->setError('socket read of headers timed out');
4026                                 return false;
4027                         }
4028
4029                         $data .= $tmp;
4030                         $pos = strpos($data,"\r\n\r\n");
4031                         if($pos > 1){
4032                                 $lb = "\r\n";
4033                         } else {
4034                                 $pos = strpos($data,"\n\n");
4035                                 if($pos > 1){
4036                                         $lb = "\n";
4037                                 }
4038                         }
4039                         // remove 100 headers
4040                         if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) {
4041                                 unset($lb);
4042                                 $data = '';
4043                         }//
4044                 }
4045                 // store header data
4046                 $this->incoming_payload .= $data;
4047                 $this->debug('found end of headers after length ' . strlen($data));
4048                 // process headers
4049                 $header_data = trim(substr($data,0,$pos));
4050                 $header_array = explode($lb,$header_data);
4051                 $this->incoming_headers = array();
4052                 $this->incoming_cookies = array();
4053                 foreach($header_array as $header_line){
4054                         $arr = explode(':',$header_line, 2);
4055                         if(count($arr) > 1){
4056                                 $header_name = strtolower(trim($arr[0]));
4057                                 $this->incoming_headers[$header_name] = trim($arr[1]);
4058                                 if ($header_name == 'set-cookie') {
4059                                         // TODO: allow multiple cookies from parseCookie
4060                                         $cookie = $this->parseCookie(trim($arr[1]));
4061                                         if ($cookie) {
4062                                                 $this->incoming_cookies[] = $cookie;
4063                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
4064                                         } else {
4065                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
4066                                         }
4067                         }
4068                         } else if (isset($header_name)) {
4069                                 // append continuation line to previous header
4070                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
4071                         }
4072                 }
4073
4074                 // loop until msg has been received
4075                 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
4076                         $content_length =  2147483647;  // ignore any content-length header
4077                         $chunked = true;
4078                         $this->debug("want to read chunked content");
4079                 } elseif (isset($this->incoming_headers['content-length'])) {
4080                         $content_length = $this->incoming_headers['content-length'];
4081                         $chunked = false;
4082                         $this->debug("want to read content of length $content_length");
4083                 } else {
4084                         $content_length =  2147483647;
4085                         $chunked = false;
4086                         $this->debug("want to read content to EOF");
4087                 }
4088                 $data = '';
4089                 do {
4090                         if ($chunked) {
4091                                 $tmp = fgets($this->fp, 256);
4092                                 $tmplen = strlen($tmp);
4093                                 $this->debug("read chunk line of $tmplen bytes");
4094                                 if ($tmplen == 0) {
4095                                         $this->incoming_payload = $data;
4096                                         $this->debug('socket read of chunk length timed out after length ' . strlen($data));
4097                                         $this->debug("read before timeout:\n" . $data);
4098                                         $this->setError('socket read of chunk length timed out');
4099                                         return false;
4100                                 }
4101                                 $content_length = hexdec(trim($tmp));
4102                                 $this->debug("chunk length $content_length");
4103                         }
4104                         $strlen = 0;
4105                     while (($strlen < $content_length) && (!feof($this->fp))) {
4106                         $readlen = min(8192, $content_length - $strlen);
4107                                 $tmp = fread($this->fp, $readlen);
4108                                 $tmplen = strlen($tmp);
4109                                 $this->debug("read buffer of $tmplen bytes");
4110                                 if (($tmplen == 0) && (!feof($this->fp))) {
4111                                         $this->incoming_payload = $data;
4112                                         $this->debug('socket read of body timed out after length ' . strlen($data));
4113                                         $this->debug("read before timeout:\n" . $data);
4114                                         $this->setError('socket read of body timed out');
4115                                         return false;
4116                                 }
4117                                 $strlen += $tmplen;
4118                                 $data .= $tmp;
4119                         }
4120                         if ($chunked && ($content_length > 0)) {
4121                                 $tmp = fgets($this->fp, 256);
4122                                 $tmplen = strlen($tmp);
4123                                 $this->debug("read chunk terminator of $tmplen bytes");
4124                                 if ($tmplen == 0) {
4125                                         $this->incoming_payload = $data;
4126                                         $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
4127                                         $this->debug("read before timeout:\n" . $data);
4128                                         $this->setError('socket read of chunk terminator timed out');
4129                                         return false;
4130                                 }
4131                         }
4132                 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
4133                 if (feof($this->fp)) {
4134                         $this->debug('read to EOF');
4135                 }
4136                 $this->debug('read body of length ' . strlen($data));
4137                 $this->incoming_payload .= $data;
4138                 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
4139
4140                 // close filepointer
4141                 if(
4142                         (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
4143                         (! $this->persistentConnection) || feof($this->fp)){
4144                         fclose($this->fp);
4145                         $this->fp = false;
4146                         $this->debug('closed socket');
4147                 }
4148
4149                 // connection was closed unexpectedly
4150                 if($this->incoming_payload == ''){
4151                         $this->setError('no response from server');
4152                         return false;
4153                 }
4154
4155                 // decode transfer-encoding
4156 //              if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
4157 //                      if(!$data = $this->decodeChunked($data, $lb)){
4158 //                              $this->setError('Decoding of chunked data failed');
4159 //                              return false;
4160 //                      }
4161                         //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
4162                         // set decoded payload
4163 //                      $this->incoming_payload = $header_data.$lb.$lb.$data;
4164 //              }
4165
4166           } else if ($this->io_method() == 'curl') {
4167                 // send and receive
4168                 $this->debug('send and receive with cURL');
4169                 $this->incoming_payload = curl_exec($this->ch);
4170                 $data = $this->incoming_payload;
4171
4172         $cErr = curl_error($this->ch);
4173                 if ($cErr != '') {
4174                 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
4175                 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
4176                         foreach(curl_getinfo($this->ch) as $k => $v){
4177                                 $err .= "$k: $v<br>";
4178                         }
4179                         $this->debug($err);
4180                         $this->setError($err);
4181                         curl_close($this->ch);
4182                 return false;
4183                 } else {
4184                         //echo '<pre>';
4185                         //var_dump(curl_getinfo($this->ch));
4186                         //echo '</pre>';
4187                 }
4188                 // close curl
4189                 $this->debug('No cURL error, closing cURL');
4190                 curl_close($this->ch);
4191
4192                 // try removing skippable headers
4193                 $savedata = $data;
4194                 while ($this->isSkippableCurlHeader($data)) {
4195                         $this->debug("Found HTTP header to skip");
4196                         if ($pos = strpos($data,"\r\n\r\n")) {
4197                                 $data = ltrim(substr($data,$pos));
4198                         } elseif($pos = strpos($data,"\n\n") ) {
4199                                 $data = ltrim(substr($data,$pos));
4200                         }
4201                 }
4202
4203                 if ($data == '') {
4204                         // have nothing left; just remove 100 header(s)
4205                         $data = $savedata;
4206                         while (preg_match('/^HTTP\/1.1 100/',$data)) {
4207                                 if ($pos = strpos($data,"\r\n\r\n")) {
4208                                         $data = ltrim(substr($data,$pos));
4209                                 } elseif($pos = strpos($data,"\n\n") ) {
4210                                         $data = ltrim(substr($data,$pos));
4211                                 }
4212                         }
4213                 }
4214
4215                 // separate content from HTTP headers
4216                 if ($pos = strpos($data,"\r\n\r\n")) {
4217                         $lb = "\r\n";
4218                 } elseif( $pos = strpos($data,"\n\n")) {
4219                         $lb = "\n";
4220                 } else {
4221                         $this->debug('no proper separation of headers and document');
4222                         $this->setError('no proper separation of headers and document');
4223                         return false;
4224                 }
4225                 $header_data = trim(substr($data,0,$pos));
4226                 $header_array = explode($lb,$header_data);
4227                 $data = ltrim(substr($data,$pos));
4228                 $this->debug('found proper separation of headers and document');
4229                 $this->debug('cleaned data, stringlen: '.strlen($data));
4230                 // clean headers
4231                 foreach ($header_array as $header_line) {
4232                         $arr = explode(':',$header_line,2);
4233                         if(count($arr) > 1){
4234                                 $header_name = strtolower(trim($arr[0]));
4235                                 $this->incoming_headers[$header_name] = trim($arr[1]);
4236                                 if ($header_name == 'set-cookie') {
4237                                         // TODO: allow multiple cookies from parseCookie
4238                                         $cookie = $this->parseCookie(trim($arr[1]));
4239                                         if ($cookie) {
4240                                                 $this->incoming_cookies[] = $cookie;
4241                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
4242                                         } else {
4243                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
4244                                         }
4245                         }
4246                         } else if (isset($header_name)) {
4247                                 // append continuation line to previous header
4248                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
4249                         }
4250                 }
4251           }
4252
4253                 $this->response_status_line = $header_array[0];
4254                 $arr = explode(' ', $this->response_status_line, 3);
4255                 $http_version = $arr[0];
4256                 $http_status = intval($arr[1]);
4257                 $http_reason = count($arr) > 2 ? $arr[2] : '';
4258
4259                 // see if we need to resend the request with http digest authentication
4260                 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
4261                         $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
4262                         $this->setURL($this->incoming_headers['location']);
4263                         $this->tryagain = true;
4264                         return false;
4265                 }
4266
4267                 // see if we need to resend the request with http digest authentication
4268                 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
4269                         $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
4270                         if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
4271                                 $this->debug('Server wants digest authentication');
4272                                 // remove "Digest " from our elements
4273                                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
4274
4275                                 // parse elements into array
4276                                 $digestElements = explode(',', $digestString);
4277                                 foreach ($digestElements as $val) {
4278                                         $tempElement = explode('=', trim($val), 2);
4279                                         $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
4280                                 }
4281
4282                                 // should have (at least) qop, realm, nonce
4283                                 if (isset($digestRequest['nonce'])) {
4284                                         $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
4285                                         $this->tryagain = true;
4286                                         return false;
4287                                 }
4288                         }
4289                         $this->debug('HTTP authentication failed');
4290                         $this->setError('HTTP authentication failed');
4291                         return false;
4292                 }
4293
4294                 if (
4295                         ($http_status >= 300 && $http_status <= 307) ||
4296                         ($http_status >= 400 && $http_status <= 417) ||
4297                         ($http_status >= 501 && $http_status <= 505)
4298                    ) {
4299                         $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
4300                         return false;
4301                 }
4302
4303                 // decode content-encoding
4304                 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
4305                         if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
4306                         // if decoding works, use it. else assume data wasn't gzencoded
4307                         if(function_exists('gzinflate')){
4308                                         //$timer->setMarker('starting decoding of gzip/deflated content');
4309                                         // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
4310                                         // this means there are no Zlib headers, although there should be
4311                                         $this->debug('The gzinflate function exists');
4312                                         $datalen = strlen($data);
4313                                         if ($this->incoming_headers['content-encoding'] == 'deflate') {
4314                                                 if ($degzdata = @gzinflate($data)) {
4315                                                 $data = $degzdata;
4316                                                 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
4317                                                 if (strlen($data) < $datalen) {
4318                                                         // test for the case that the payload has been compressed twice
4319                                                         $this->debug('The inflated payload is smaller than the gzipped one; try again');
4320                                                                 if ($degzdata = @gzinflate($data)) {
4321                                                                 $data = $degzdata;
4322                                                                 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
4323                                                                 }
4324                                                 }
4325                                         } else {
4326                                                 $this->debug('Error using gzinflate to inflate the payload');
4327                                                 $this->setError('Error using gzinflate to inflate the payload');
4328                                         }
4329                                         } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
4330                                                 if ($degzdata = @gzinflate(substr($data, 10))) {        // do our best
4331                                                         $data = $degzdata;
4332                                                 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
4333                                                 if (strlen($data) < $datalen) {
4334                                                         // test for the case that the payload has been compressed twice
4335                                                         $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
4336                                                                 if ($degzdata = @gzinflate(substr($data, 10))) {
4337                                                                 $data = $degzdata;
4338                                                                 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
4339                                                                 }
4340                                                 }
4341                                         } else {
4342                                                 $this->debug('Error using gzinflate to un-gzip the payload');
4343                                                         $this->setError('Error using gzinflate to un-gzip the payload');
4344                                         }
4345                                         }
4346                                         //$timer->setMarker('finished decoding of gzip/deflated content');
4347                                         //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
4348                                         // set decoded payload
4349                                         $this->incoming_payload = $header_data.$lb.$lb.$data;
4350                         } else {
4351                                         $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
4352                                         $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
4353                                 }
4354                         } else {
4355                                 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
4356                                 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
4357                         }
4358                 } else {
4359                         $this->debug('No Content-Encoding header');
4360                 }
4361
4362                 if(strlen($data) == 0){
4363                         $this->debug('no data after headers!');
4364                         $this->setError('no data present after HTTP headers');
4365                         return false;
4366                 }
4367
4368                 return $data;
4369         }
4370
4371         /**
4372          * sets the content-type for the SOAP message to be sent
4373          *
4374          * @param       string $type the content type, MIME style
4375          * @param       mixed $charset character set used for encoding (or false)
4376          * @access      public
4377          */
4378         function setContentType($type, $charset = false) {
4379                 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
4380         }
4381
4382         /**
4383          * specifies that an HTTP persistent connection should be used
4384          *
4385          * @return      boolean whether the request was honored by this method.
4386          * @access      public
4387          */
4388         function usePersistentConnection(){
4389                 if (isset($this->outgoing_headers['Accept-Encoding'])) {
4390                         return false;
4391                 }
4392                 $this->protocol_version = '1.1';
4393                 $this->persistentConnection = true;
4394                 $this->setHeader('Connection', 'Keep-Alive');
4395                 return true;
4396         }
4397
4398         /**
4399          * parse an incoming Cookie into it's parts
4400          *
4401          * @param       string $cookie_str content of cookie
4402          * @return      array with data of that cookie
4403          * @access      private
4404          */
4405         /*
4406          * TODO: allow a Set-Cookie string to be parsed into multiple cookies
4407          */
4408         function parseCookie($cookie_str) {
4409                 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
4410                 $data = preg_split('/;/', $cookie_str);
4411                 $value_str = $data[0];
4412
4413                 $cookie_param = 'domain=';
4414                 $start = strpos($cookie_str, $cookie_param);
4415                 if ($start > 0) {
4416                         $domain = substr($cookie_str, $start + strlen($cookie_param));
4417                         $domain = substr($domain, 0, strpos($domain, ';'));
4418                 } else {
4419                         $domain = '';
4420                 }
4421
4422                 $cookie_param = 'expires=';
4423                 $start = strpos($cookie_str, $cookie_param);
4424                 if ($start > 0) {
4425                         $expires = substr($cookie_str, $start + strlen($cookie_param));
4426                         $expires = substr($expires, 0, strpos($expires, ';'));
4427                 } else {
4428                         $expires = '';
4429                 }
4430
4431                 $cookie_param = 'path=';
4432                 $start = strpos($cookie_str, $cookie_param);
4433                 if ( $start > 0 ) {
4434                         $path = substr($cookie_str, $start + strlen($cookie_param));
4435                         $path = substr($path, 0, strpos($path, ';'));
4436                 } else {
4437                         $path = '/';
4438                 }
4439
4440                 $cookie_param = ';secure;';
4441                 if (strpos($cookie_str, $cookie_param) !== FALSE) {
4442                         $secure = true;
4443                 } else {
4444                         $secure = false;
4445                 }
4446
4447                 $sep_pos = strpos($value_str, '=');
4448
4449                 if ($sep_pos) {
4450                         $name = substr($value_str, 0, $sep_pos);
4451                         $value = substr($value_str, $sep_pos + 1);
4452                         $cookie= array( 'name' => $name,
4453                                         'value' => $value,
4454                                                         'domain' => $domain,
4455                                                         'path' => $path,
4456                                                         'expires' => $expires,
4457                                                         'secure' => $secure
4458                                                         );
4459                         return $cookie;
4460                 }
4461                 return false;
4462         }
4463
4464         /**
4465          * sort out cookies for the current request
4466          *
4467          * @param       array $cookies array with all cookies
4468          * @param       boolean $secure is the send-content secure or not?
4469          * @return      string for Cookie-HTTP-Header
4470          * @access      private
4471          */
4472         function getCookiesForRequest($cookies, $secure=false) {
4473                 $cookie_str = '';
4474                 if ((! is_null($cookies)) && (is_array($cookies))) {
4475                         foreach ($cookies as $cookie) {
4476                                 if (! is_array($cookie)) {
4477                                         continue;
4478                                 }
4479                         $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
4480                                 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
4481                                         if (strtotime($cookie['expires']) <= time()) {
4482                                                 $this->debug('cookie has expired');
4483                                                 continue;
4484                                         }
4485                                 }
4486                                 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
4487                                         $domain = preg_quote($cookie['domain']);
4488                                         if (! preg_match("'.*$domain$'i", $this->host)) {
4489                                                 $this->debug('cookie has different domain');
4490                                                 continue;
4491                                         }
4492                                 }
4493                                 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
4494                                         $path = preg_quote($cookie['path']);
4495                                         if (! preg_match("'^$path.*'i", $this->path)) {
4496                                                 $this->debug('cookie is for a different path');
4497                                                 continue;
4498                                         }
4499                                 }
4500                                 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
4501                                         $this->debug('cookie is secure, transport is not');
4502                                         continue;
4503                                 }
4504                                 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
4505                         $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
4506                         }
4507                 }
4508                 return $cookie_str;
4509   }
4510 }
4511
4512 ?><?php
4513
4514 /*
4515
4516 Modification information for LGPL compliance
4517
4518 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
4519     bug 40066
4520
4521 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
4522     Merging with maint_6_0_1 (svn merge -r 58250:58342)
4523
4524 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
4525     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
4526
4527 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
4528     fix SOAP calls with no parameters
4529
4530 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
4531
4532 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
4533
4534 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
4535
4536 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
4537
4538 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
4539
4540 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
4541
4542 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
4543
4544 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
4545 - Changing all ereg function to either preg or simple string based ones
4546 - No more references to magic quotes.
4547 - Change all the session_unregister() functions to just unset() the correct session variable instead.
4548
4549 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
4550
4551 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
4552
4553 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
4554
4555 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
4556
4557 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
4558
4559 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
4560
4561 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
4562
4563 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
4564
4565 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
4566 Touched:
4567 - data/SugarBean.php
4568 - include/domit/php_http_client_generic.php
4569 - include/domit/php_http_connector.php
4570 - include/domit/testing_domit.php
4571 - include/domit/xml_domit_getelementsbypath.php
4572 - include/domit/xml_domit_lite_parser.php
4573 - include/domit/xml_domit_nodemaps.php
4574 - include/domit/xml_domit_parser.php
4575 - include/domit/xml_domit_shared.php
4576 - include/generic/SugarWidgets/SugarWidgetField.php
4577 - include/generic/SugarWidgets/SugarWidgetReportField.php
4578 - include/ListView/ProcessView.php
4579 - include/nusoap/class.soapclient.php
4580 - include/nusoap/nusoap.php
4581 - include/nusoap/nusoapmime.php
4582 - include/Pear/HTML_Safe/Safe.php
4583 - include/Pear/XML_HTMLSax3/HTMLSax3.php
4584 - modules/Administration/RebuildWorkFlow.php
4585 - modules/Expressions/RelateSelector.php
4586 - modules/Reports/templates/templates_reports.php
4587 - modules/WorkFlow/Delete.php
4588 - modules/WorkFlow/Save.php
4589 - modules/WorkFlow/SaveSequence.php
4590 - modules/WorkFlow/WorkFlow.php
4591 - modules/WorkFlowActionShells/CreateStep1.php
4592 - modules/WorkFlowActionShells/CreateStep2.php
4593 - modules/WorkFlowActionShells/Save.php
4594 - modules/WorkFlowActionShells/WorkFlowActionShell.php
4595 - modules/WorkFlowAlerts/Save.php
4596 - modules/WorkFlowAlerts/WorkFlowAlert.php
4597 - modules/WorkFlowAlertShells/DetailView.php
4598 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
4599 - modules/WorkFlowTriggerShells/CreateStep1.php
4600 - modules/WorkFlowTriggerShells/CreateStepFilter.php
4601 - modules/WorkFlowTriggerShells/SaveFilter.php
4602 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
4603 - soap/SoapHelperFunctions.php
4604 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
4605 - test/simpletest/browser.php
4606 - test/simpletest/default_reporter.php
4607 - test/simpletest/detached.php
4608 - test/simpletest/eclipse.php
4609 - test/simpletest/expectation.php
4610 - test/simpletest/extensions/pear_test_case.php
4611 - test/simpletest/form.php
4612 - test/simpletest/http.php
4613 - test/simpletest/mock_objects.php
4614 - test/simpletest/page.php
4615 - test/simpletest/parser.php
4616 - test/simpletest/remote.php
4617 - test/simpletest/shell_tester.php
4618 - test/simpletest/simple_test.php
4619 - test/simpletest/simpletest.php
4620 - test/simpletest/test/acceptance_test.php
4621 - test/simpletest/test/adapter_test.php
4622 - test/simpletest/test/authentication_test.php
4623 - test/simpletest/test/browser_test.php
4624 - test/simpletest/test/collector_test.php
4625 - test/simpletest/test/compatibility_test.php
4626 - test/simpletest/test/detached_test.php
4627 - test/simpletest/test/eclipse_test.php
4628 - test/simpletest/test/encoding_test.php
4629 - test/simpletest/test/errors_test.php
4630 - test/simpletest/test/expectation_test.php
4631 - test/simpletest/test/form_test.php
4632 - test/simpletest/test/frames_test.php
4633 - test/simpletest/test/http_test.php
4634 - test/simpletest/test/live_test.php
4635 - test/simpletest/test/mock_objects_test.php
4636 - test/simpletest/test/page_test.php
4637 - test/simpletest/test/parse_error_test.php
4638 - test/simpletest/test/parser_test.php
4639 - test/simpletest/test/remote_test.php
4640 - test/simpletest/test/shell_test.php
4641 - test/simpletest/test/shell_tester_test.php
4642 - test/simpletest/test/simpletest_test.php
4643 - test/simpletest/test/site/page_request.php
4644 - test/simpletest/test/tag_test.php
4645 - test/simpletest/test/unit_tester_test.php
4646 - test/simpletest/test/user_agent_test.php
4647 - test/simpletest/test/visual_test.php
4648 - test/simpletest/test/xml_test.php
4649 - test/simpletest/test_case.php
4650 - test/simpletest/ui/array_reporter/test.php
4651 - test/simpletest/ui/recorder/test.php
4652 - test/simpletest/unit_tester.php
4653 - test/simpletest/url.php
4654 - test/simpletest/user_agent.php
4655 - test/simpletest/web_tester.php
4656 - test/spikephpcoverage/src/PEAR.php
4657 - test/spikephpcoverage/src/util/Utility.php
4658 - test/spikephpcoverage/src/XML/Parser.php
4659 - test/spikephpcoverage/src/XML/Parser/Simple.php
4660 - test/test_utilities/SugarTest_SimpleBrowser.php
4661
4662 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
4663
4664 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
4665
4666 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
4667
4668 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
4669
4670 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
4671
4672 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
4673
4674 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
4675
4676 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
4677
4678 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
4679
4680 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
4681
4682 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
4683
4684 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
4685
4686 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
4687
4688 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
4689
4690 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
4691
4692 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
4693
4694 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
4695
4696 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
4697
4698 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
4699
4700 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
4701
4702 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
4703
4704 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
4705
4706 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
4707
4708 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
4709
4710
4711 */
4712
4713
4714
4715
4716
4717 /**
4718 *
4719 * nusoap_server allows the user to create a SOAP server
4720 * that is capable of receiving messages and returning responses
4721 *
4722 * @author   Dietrich Ayala <dietrich@ganx4.com>
4723 * @author   Scott Nichol <snichol@users.sourceforge.net>
4724
4725 * @access   public
4726 */
4727 class nusoap_server extends nusoap_base {
4728         /**
4729          * HTTP headers of request
4730          * @var array
4731          * @access private
4732          */
4733         var $headers = array();
4734         /**
4735          * HTTP request
4736          * @var string
4737          * @access private
4738          */
4739         var $request = '';
4740         /**
4741          * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
4742          * @var string
4743          * @access public
4744          */
4745         var $requestHeaders = '';
4746         /**
4747          * SOAP Headers from request (parsed)
4748          * @var mixed
4749          * @access public
4750          */
4751         var $requestHeader = NULL;
4752         /**
4753          * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
4754          * @var string
4755          * @access public
4756          */
4757         var $document = '';
4758         /**
4759          * SOAP payload for request (text)
4760          * @var string
4761          * @access public
4762          */
4763         var $requestSOAP = '';
4764         /**
4765          * requested method namespace URI
4766          * @var string
4767          * @access private
4768          */
4769         var $methodURI = '';
4770         /**
4771          * name of method requested
4772          * @var string
4773          * @access private
4774          */
4775         var $methodname = '';
4776         /**
4777          * method parameters from request
4778          * @var array
4779          * @access private
4780          */
4781         var $methodparams = array();
4782         /**
4783          * SOAP Action from request
4784          * @var string
4785          * @access private
4786          */
4787         var $SOAPAction = '';
4788         /**
4789          * character set encoding of incoming (request) messages
4790          * @var string
4791          * @access public
4792          */
4793         var $xml_encoding = '';
4794         /**
4795          * toggles whether the parser decodes element content w/ utf8_decode()
4796          * @var boolean
4797          * @access public
4798          */
4799     var $decode_utf8 = false;
4800
4801         /**
4802          * HTTP headers of response
4803          * @var array
4804          * @access public
4805          */
4806         var $outgoing_headers = array();
4807         /**
4808          * HTTP response
4809          * @var string
4810          * @access private
4811          */
4812         var $response = '';
4813         /**
4814          * SOAP headers for response (text or array of soapval or associative array)
4815          * @var mixed
4816          * @access public
4817          */
4818         var $responseHeaders = '';
4819         /**
4820          * SOAP payload for response (text)
4821          * @var string
4822          * @access private
4823          */
4824         var $responseSOAP = '';
4825         /**
4826          * method return value to place in response
4827          * @var mixed
4828          * @access private
4829          */
4830         var $methodreturn = false;
4831         /**
4832          * whether $methodreturn is a string of literal XML
4833          * @var boolean
4834          * @access public
4835          */
4836         var $methodreturnisliteralxml = false;
4837         /**
4838          * SOAP fault for response (or false)
4839          * @var mixed
4840          * @access private
4841          */
4842         var $fault = false;
4843         /**
4844          * text indication of result (for debugging)
4845          * @var string
4846          * @access private
4847          */
4848         var $result = 'successful';
4849
4850         /**
4851          * assoc array of operations => opData; operations are added by the register()
4852          * method or by parsing an external WSDL definition
4853          * @var array
4854          * @access private
4855          */
4856         var $operations = array();
4857         /**
4858          * wsdl instance (if one)
4859          * @var mixed
4860          * @access private
4861          */
4862         var $wsdl = false;
4863         /**
4864          * URL for WSDL (if one)
4865          * @var mixed
4866          * @access private
4867          */
4868         var $externalWSDLURL = false;
4869         /**
4870          * whether to append debug to response as XML comment
4871          * @var boolean
4872          * @access public
4873          */
4874         var $debug_flag = false;
4875
4876
4877         /**
4878         * constructor
4879     * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
4880         *
4881     * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
4882         * @access   public
4883         */
4884         function nusoap_server($wsdl=false){
4885                 parent::nusoap_base();
4886                 // turn on debugging?
4887                 global $debug;
4888                 global $HTTP_SERVER_VARS;
4889
4890                 if (isset($_SERVER)) {
4891                         $this->debug("_SERVER is defined:");
4892                         $this->appendDebug($this->varDump($_SERVER));
4893                 } elseif (isset($HTTP_SERVER_VARS)) {
4894                         $this->debug("HTTP_SERVER_VARS is defined:");
4895                         $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
4896                 } else {
4897                         $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
4898                 }
4899
4900                 if (isset($debug)) {
4901                         $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
4902                         $this->debug_flag = $debug;
4903                 } elseif (isset($_SERVER['QUERY_STRING'])) {
4904                         $qs = explode('&', $_SERVER['QUERY_STRING']);
4905                         foreach ($qs as $v) {
4906                                 if (substr($v, 0, 6) == 'debug=') {
4907                                         $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
4908                                         $this->debug_flag = substr($v, 6);
4909                                 }
4910                         }
4911                 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
4912                         $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
4913                         foreach ($qs as $v) {
4914                                 if (substr($v, 0, 6) == 'debug=') {
4915                                         $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
4916                                         $this->debug_flag = substr($v, 6);
4917                                 }
4918                         }
4919                 }
4920
4921                 // wsdl
4922                 if($wsdl){
4923                         $this->debug("In nusoap_server, WSDL is specified");
4924                         if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
4925                                 $this->wsdl = $wsdl;
4926                                 $this->externalWSDLURL = $this->wsdl->wsdl;
4927                                 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
4928                         } else {
4929                                 $this->debug('Create wsdl from ' . $wsdl);
4930                                 $this->wsdl = new wsdl($wsdl);
4931                                 $this->externalWSDLURL = $wsdl;
4932                         }
4933                         $this->appendDebug($this->wsdl->getDebug());
4934                         $this->wsdl->clearDebug();
4935                         if($err = $this->wsdl->getError()){
4936                                 die('WSDL ERROR: '.$err);
4937                         }
4938                 }
4939         }
4940
4941         /**
4942         * processes request and returns response
4943         *
4944         * @param    string $data usually is the value of $HTTP_RAW_POST_DATA
4945         * @access   public
4946         */
4947         function service($data){
4948                 global $HTTP_SERVER_VARS;
4949
4950                 if (isset($_SERVER['REQUEST_METHOD'])) {
4951                         $rm = $_SERVER['REQUEST_METHOD'];
4952                 } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
4953                         $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
4954                 } else {
4955                         $rm = '';
4956                 }
4957
4958                 if (isset($_SERVER['QUERY_STRING'])) {
4959                         $qs = $_SERVER['QUERY_STRING'];
4960                 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
4961                         $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
4962                 } else {
4963                         $qs = '';
4964                 }
4965                 $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
4966
4967                 if ($rm == 'POST') {
4968                         $this->debug("In service, invoke the request");
4969                         $this->parse_request($data);
4970                         if (! $this->fault) {
4971                                 $this->invoke_method();
4972                         }
4973                         if (! $this->fault) {
4974                                 $this->serialize_return();
4975                         }
4976                         $this->send_response();
4977                 } elseif (preg_match('/wsdl/', $qs) ){
4978                         $this->debug("In service, this is a request for WSDL");
4979                         if ($this->externalWSDLURL){
4980               if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
4981                                 $this->debug("In service, re-direct for WSDL");
4982                                 header('Location: '.$this->externalWSDLURL);
4983               } else { // assume file
4984                                 $this->debug("In service, use file passthru for WSDL");
4985                 header("Content-Type: text/xml\r\n");
4986                                 $pos = strpos($this->externalWSDLURL, "file://");
4987                                 if ($pos === false) {
4988                                         $filename = $this->externalWSDLURL;
4989                                 } else {
4990                                         $filename = substr($this->externalWSDLURL, $pos + 7);
4991                                 }
4992                 $fp = fopen($this->externalWSDLURL, 'r');
4993                 fpassthru($fp);
4994               }
4995                         } elseif ($this->wsdl) {
4996                                 $this->debug("In service, serialize WSDL");
4997                                 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
4998                                 print $this->wsdl->serialize($this->debug_flag);
4999                                 if ($this->debug_flag) {
5000                                         $this->debug('wsdl:');
5001                                         $this->appendDebug($this->varDump($this->wsdl));
5002                                         print $this->getDebugAsXMLComment();
5003                                 }
5004                         } else {
5005                                 $this->debug("In service, there is no WSDL");
5006                                 header("Content-Type: text/html; charset=ISO-8859-1\r\n");
5007                                 print "This service does not provide WSDL";
5008                         }
5009                 } elseif ($this->wsdl) {
5010                         $this->debug("In service, return Web description");
5011                         print $this->wsdl->webDescription();
5012                 } else {
5013                         $this->debug("In service, no Web description");
5014                         header("Content-Type: text/html; charset=ISO-8859-1\r\n");
5015                         print "This service does not provide a Web description";
5016                 }
5017         }
5018
5019         /**
5020         * parses HTTP request headers.
5021         *
5022         * The following fields are set by this function (when successful)
5023         *
5024         * headers
5025         * request
5026         * xml_encoding
5027         * SOAPAction
5028         *
5029         * @access   private
5030         */
5031         function parse_http_headers() {
5032                 global $HTTP_SERVER_VARS;
5033
5034                 $this->request = '';
5035                 $this->SOAPAction = '';
5036                 if(function_exists('getallheaders')){
5037                         $this->debug("In parse_http_headers, use getallheaders");
5038                         $headers = getallheaders();
5039                         foreach($headers as $k=>$v){
5040                                 $k = strtolower($k);
5041                                 $this->headers[$k] = $v;
5042                                 $this->request .= "$k: $v\r\n";
5043                                 $this->debug("$k: $v");
5044                         }
5045                         // get SOAPAction header
5046                         if(isset($this->headers['soapaction'])){
5047                                 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
5048                         }
5049                         // get the character encoding of the incoming request
5050                         if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
5051                                 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
5052                                 if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
5053                                         $this->xml_encoding = strtoupper($enc);
5054                                 } else {
5055                                         $this->xml_encoding = 'US-ASCII';
5056                                 }
5057                         } else {
5058                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5059                                 $this->xml_encoding = 'ISO-8859-1';
5060                         }
5061                 } elseif(isset($_SERVER) && is_array($_SERVER)){
5062                         $this->debug("In parse_http_headers, use _SERVER");
5063                         foreach ($_SERVER as $k => $v) {
5064                                 if (substr($k, 0, 5) == 'HTTP_') {
5065                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
5066                                 } else {
5067                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
5068                                 }
5069                                 if ($k == 'soapaction') {
5070                                         // get SOAPAction header
5071                                         $k = 'SOAPAction';
5072                                         $v = str_replace('"', '', $v);
5073                                         $v = str_replace('\\', '', $v);
5074                                         $this->SOAPAction = $v;
5075                                 } else if ($k == 'content-type') {
5076                                         // get the character encoding of the incoming request
5077                                         if (strpos($v, '=')) {
5078                                                 $enc = substr(strstr($v, '='), 1);
5079                                                 $enc = str_replace('"', '', $enc);
5080                                                 $enc = str_replace('\\', '', $enc);
5081                                                 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
5082                                                         $this->xml_encoding = strtoupper($enc);
5083                                                 } else {
5084                                                         $this->xml_encoding = 'US-ASCII';
5085                                                 }
5086                                         } else {
5087                                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5088                                                 $this->xml_encoding = 'ISO-8859-1';
5089                                         }
5090                                 }
5091                                 $this->headers[$k] = $v;
5092                                 $this->request .= "$k: $v\r\n";
5093                                 $this->debug("$k: $v");
5094                         }
5095                 } elseif (is_array($HTTP_SERVER_VARS)) {
5096                         $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
5097                         foreach ($HTTP_SERVER_VARS as $k => $v) {
5098                                 if (substr($k, 0, 5) == 'HTTP_') {
5099                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                            $k = strtolower(substr($k, 5));
5100                                 } else {
5101                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                               $k = strtolower($k);
5102                                 }
5103                                 if ($k == 'soapaction') {
5104                                         // get SOAPAction header
5105                                         $k = 'SOAPAction';
5106                                         $v = str_replace('"', '', $v);
5107                                         $v = str_replace('\\', '', $v);
5108                                         $this->SOAPAction = $v;
5109                                 } else if ($k == 'content-type') {
5110                                         // get the character encoding of the incoming request
5111                                         if (strpos($v, '=')) {
5112                                                 $enc = substr(strstr($v, '='), 1);
5113                                                 $enc = str_replace('"', '', $enc);
5114                                                 $enc = str_replace('\\', '', $enc);
5115                                                 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
5116                                                         $this->xml_encoding = strtoupper($enc);
5117                                                 } else {
5118                                                         $this->xml_encoding = 'US-ASCII';
5119                                                 }
5120                                         } else {
5121                                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5122                                                 $this->xml_encoding = 'ISO-8859-1';
5123                                         }
5124                                 }
5125                                 $this->headers[$k] = $v;
5126                                 $this->request .= "$k: $v\r\n";
5127                                 $this->debug("$k: $v");
5128                         }
5129                 } else {
5130                         $this->debug("In parse_http_headers, HTTP headers not accessible");
5131                         $this->setError("HTTP headers not accessible");
5132                 }
5133         }
5134
5135         /**
5136         * parses a request
5137         *
5138         * The following fields are set by this function (when successful)
5139         *
5140         * headers
5141         * request
5142         * xml_encoding
5143         * SOAPAction
5144         * request
5145         * requestSOAP
5146         * methodURI
5147         * methodname
5148         * methodparams
5149         * requestHeaders
5150         * document
5151         *
5152         * This sets the fault field on error
5153         *
5154         * @param    string $data XML string
5155         * @access   private
5156         */
5157         function parse_request($data='') {
5158                 $this->debug('entering parse_request()');
5159                 $this->parse_http_headers();
5160                 $this->debug('got character encoding: '.$this->xml_encoding);
5161                 // uncompress if necessary
5162                 if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
5163                         $this->debug('got content encoding: ' . $this->headers['content-encoding']);
5164                         if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
5165                         // if decoding works, use it. else assume data wasn't gzencoded
5166                                 if (function_exists('gzuncompress')) {
5167                                         if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
5168                                                 $data = $degzdata;
5169                                         } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
5170                                                 $data = $degzdata;
5171                                         } else {
5172                                                 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
5173                                                 return;
5174                                         }
5175                                 } else {
5176                                         $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
5177                                         return;
5178                                 }
5179                         }
5180                 }
5181                 $this->request .= "\r\n".$data;
5182                 $data = $this->parseRequest($this->headers, $data);
5183                 $this->requestSOAP = $data;
5184                 $this->debug('leaving parse_request');
5185         }
5186
5187         function register_class($classname){
5188                 $this->registeredClass = $classname;
5189         }
5190         /**
5191         * invokes a PHP function for the requested SOAP method
5192         *
5193         * The following fields are set by this function (when successful)
5194         *
5195         * methodreturn
5196         *
5197         * Note that the PHP function that is called may also set the following
5198         * fields to affect the response sent to the client
5199         *
5200         * responseHeaders
5201         * outgoing_headers
5202         *
5203         * This sets the fault field on error
5204         *
5205         * @access   private
5206         */
5207         function invoke_method() {
5208                 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
5209
5210                 //
5211                 // if you are debugging in this area of the code, your service uses a class to implement methods,
5212                 // you use SOAP RPC, and the client is .NET, please be aware of the following...
5213                 // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
5214                 // method name.  that is fine for naming the .NET methods.  it is not fine for properly constructing
5215                 // the XML request and reading the XML response.  you need to add the RequestElementName and
5216                 // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
5217                 // generates for the method.  these parameters are used to specify the correct XML element names
5218                 // for .NET to use, i.e. the names with the '.' in them.
5219                 //
5220                 $orig_methodname = $this->methodname;
5221                 if ($this->wsdl) {
5222                         if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
5223                                 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
5224                                 $this->appendDebug('opData=' . $this->varDump($this->opData));
5225                         } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
5226                                 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
5227                                 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
5228                                 $this->appendDebug('opData=' . $this->varDump($this->opData));
5229                                 $this->methodname = $this->opData['name'];
5230                         } else {
5231                                 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
5232                                 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
5233                                 return;
5234                         }
5235                 } else {
5236                         $this->debug('in invoke_method, no WSDL to validate method');
5237                 }
5238
5239                 // if a . is present in $this->methodname, we see if there is a class in scope,
5240                 // which could be referred to. We will also distinguish between two deliminators,
5241                 // to allow methods to be called a the class or an instance
5242                 if (strpos($this->methodname, '..') > 0) {
5243                         $delim = '..';
5244                 } else if (strpos($this->methodname, '.') > 0) {
5245                         $delim = '.';
5246                 } else {
5247                         $delim = '';
5248                 }
5249                 $this->debug("in invoke_method, delim=$delim");
5250
5251                 $class = '';
5252                 $method = '';
5253                 if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
5254                         $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
5255                         if (class_exists($try_class)) {
5256                                 // get the class and method name
5257                                 $class = $try_class;
5258                                 $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
5259                                 $this->debug("in invoke_method, class=$class method=$method delim=$delim");
5260                         } else {
5261                                 $this->debug("in invoke_method, class=$try_class not found");
5262                         }
5263                 } else {
5264                         $try_class = '';
5265                         $this->debug("in invoke_method, no class to try");
5266                 }
5267                 if(empty($delim) && isset($this->registeredClass)){
5268                         $class  = $this->registeredClass;
5269                         $delim = '..';
5270                         $method = $this->methodname;
5271                 }
5272
5273                 // does method exist?
5274                 if ($class == '') {
5275                         if (!function_exists($this->methodname)) {
5276                                 $this->debug("in invoke_method, function '$this->methodname' not found!");
5277                                 $this->result = 'fault: method not found';
5278                                 $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
5279                                 return;
5280                         }
5281                 } else {
5282                         $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
5283                         if (!in_array($method_to_compare, get_class_methods($class))) {
5284                                 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
5285                                 $this->result = 'fault: method not found';
5286                                 $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
5287                                 return;
5288                         }
5289                 }
5290
5291                 // evaluate message, getting back parameters
5292                 // verify that request parameters match the method's signature
5293                 if(! $this->verify_method($this->methodname,$this->methodparams)){
5294                         // debug
5295                         $this->debug('ERROR: request not verified against method signature');
5296                         $this->result = 'fault: request failed validation against method signature';
5297                         // return fault
5298                         $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
5299                         return;
5300                 }
5301
5302                 // if there are parameters to pass
5303                 $this->debug('in invoke_method, params:');
5304                 $this->appendDebug($this->varDump($this->methodparams));
5305                 $this->debug("in invoke_method, calling '$this->methodname'");
5306                 if (!function_exists('call_user_func_array')) {
5307                         if ($class == '') {
5308                                 $this->debug('in invoke_method, calling function using eval()');
5309                                 $funcCall = "\$this->methodreturn = $this->methodname(";
5310                         } else {
5311                                 if ($delim == '..') {
5312                                         $this->debug('in invoke_method, calling class method using eval()');
5313                                         $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
5314                                 } else {
5315                                         $this->debug('in invoke_method, calling instance method using eval()');
5316                                         // generate unique instance name
5317                                         $instname = "\$inst_".time();
5318                                         $funcCall = $instname." = new ".$class."(); ";
5319                                         $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
5320                                 }
5321                         }
5322                         if ($this->methodparams) {
5323                                 foreach ($this->methodparams as $param) {
5324                                         if (is_array($param) || is_object($param)) {
5325                                                 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
5326                                                 return;
5327                                         }
5328                                         $funcCall .= "\"$param\",";
5329                                 }
5330                                 $funcCall = substr($funcCall, 0, -1);
5331                         }
5332                         $funcCall .= ');';
5333                         $this->debug('in invoke_method, function call: '.$funcCall);
5334                         @eval($funcCall);
5335                 } else {
5336                         if ($class == '') {
5337                                 $this->debug('in invoke_method, calling function using call_user_func_array()');
5338                                 $call_arg = "$this->methodname";        // straight assignment changes $this->methodname to lower case after call_user_func_array()
5339                         } elseif ($delim == '..') {
5340                                 $this->debug('in invoke_method, calling class method using call_user_func_array()');
5341                                 $call_arg = array ($class, $method);
5342                         } else {
5343                                 $this->debug('in invoke_method, calling instance method using call_user_func_array()');
5344                                 $instance = new $class ();
5345                                 $call_arg = array(&$instance, $method);
5346                         }
5347                         if (is_array($this->methodparams)) {
5348                                 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
5349                         } else {
5350                                 $this->methodreturn = call_user_func_array($call_arg, array());
5351                         }
5352                 }
5353         $this->debug('in invoke_method, methodreturn:');
5354         $this->appendDebug($this->varDump($this->methodreturn));
5355                 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
5356         }
5357
5358         /**
5359         * serializes the return value from a PHP function into a full SOAP Envelope
5360         *
5361         * The following fields are set by this function (when successful)
5362         *
5363         * responseSOAP
5364         *
5365         * This sets the fault field on error
5366         *
5367         * @access   private
5368         */
5369         function serialize_return() {
5370                 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
5371                 // if fault
5372                 if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
5373                         $this->debug('got a fault object from method');
5374                         $this->fault = $this->methodreturn;
5375                         return;
5376                 } elseif ($this->methodreturnisliteralxml) {
5377                         $return_val = $this->methodreturn;
5378                 // returned value(s)
5379                 } else {
5380                         $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
5381                         $this->debug('serializing return value');
5382                         if($this->wsdl){
5383                                 if (sizeof($this->opData['output']['parts']) > 1) {
5384                                         $this->debug('more than one output part, so use the method return unchanged');
5385                                 $opParams = $this->methodreturn;
5386                             } elseif (sizeof($this->opData['output']['parts']) == 1) {
5387                                         $this->debug('exactly one output part, so wrap the method return in a simple array');
5388                                         // TODO: verify that it is not already wrapped!
5389                                 //foreach ($this->opData['output']['parts'] as $name => $type) {
5390                                         //      $this->debug('wrap in element named ' . $name);
5391                                 //}
5392                                 $opParams = array($this->methodreturn);
5393                             }
5394                             $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
5395                             $this->appendDebug($this->wsdl->getDebug());
5396                             $this->wsdl->clearDebug();
5397                                 if($errstr = $this->wsdl->getError()){
5398                                         $this->debug('got wsdl error: '.$errstr);
5399                                         $this->fault('SOAP-ENV:Server', 'unable to serialize result');
5400                                         return;
5401                                 }
5402                         } else {
5403                                 if (isset($this->methodreturn)) {
5404                                         $return_val = $this->serialize_val($this->methodreturn, 'return');
5405                                 } else {
5406                                         $return_val = '';
5407                                         $this->debug('in absence of WSDL, assume void return for backward compatibility');
5408                                 }
5409                         }
5410                 }
5411                 $this->debug('return value:');
5412                 $this->appendDebug($this->varDump($return_val));
5413
5414                 $this->debug('serializing response');
5415                 if ($this->wsdl) {
5416                         $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
5417                         if ($this->opData['style'] == 'rpc') {
5418                                 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
5419                                 if ($this->opData['output']['use'] == 'literal') {
5420                                         // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
5421                                         if ($this->methodURI) {
5422                                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
5423                                         } else {
5424                                                 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
5425                                         }
5426                                 } else {
5427                                         if ($this->methodURI) {
5428                                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
5429                                         } else {
5430                                                 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
5431                                         }
5432                                 }
5433                         } else {
5434                                 $this->debug('style is not rpc for serialization: assume document');
5435                                 $payload = $return_val;
5436                         }
5437                 } else {
5438                         $this->debug('do not have WSDL for serialization: assume rpc/encoded');
5439                         $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
5440                 }
5441                 $this->result = 'successful';
5442                 if($this->wsdl){
5443                         //if($this->debug_flag){
5444                 $this->appendDebug($this->wsdl->getDebug());
5445             //  }
5446                         if (isset($this->opData['output']['encodingStyle'])) {
5447                                 $encodingStyle = $this->opData['output']['encodingStyle'];
5448                         } else {
5449                                 $encodingStyle = '';
5450                         }
5451                         // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
5452                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
5453                 } else {
5454                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
5455                 }
5456                 $this->debug("Leaving serialize_return");
5457         }
5458
5459         /**
5460         * sends an HTTP response
5461         *
5462         * The following fields are set by this function (when successful)
5463         *
5464         * outgoing_headers
5465         * response
5466         *
5467         * @access   private
5468         */
5469         function send_response() {
5470                 $this->debug('Enter send_response');
5471                 if ($this->fault) {
5472                         $payload = $this->fault->serialize();
5473                         $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
5474                         $this->outgoing_headers[] = "Status: 500 Internal Server Error";
5475                 } else {
5476                         $payload = $this->responseSOAP;
5477                         // Some combinations of PHP+Web server allow the Status
5478                         // to come through as a header.  Since OK is the default
5479                         // just do nothing.
5480                         // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
5481                         // $this->outgoing_headers[] = "Status: 200 OK";
5482                 }
5483         // add debug data if in debug mode
5484                 if(isset($this->debug_flag) && $this->debug_flag){
5485                 $payload .= $this->getDebugAsXMLComment();
5486         }
5487                 $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
5488                 preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
5489                 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
5490                 // Let the Web server decide about this
5491                 //$this->outgoing_headers[] = "Connection: Close\r\n";
5492                 $payload = $this->getHTTPBody($payload);
5493                 $type = $this->getHTTPContentType();
5494                 $charset = $this->getHTTPContentTypeCharset();
5495                 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
5496                 //begin code to compress payload - by John
5497                 // NOTE: there is no way to know whether the Web server will also compress
5498                 // this data.
5499                 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
5500                         if (strstr($this->headers['accept-encoding'], 'gzip')) {
5501                                 if (function_exists('gzencode')) {
5502                                         if (isset($this->debug_flag) && $this->debug_flag) {
5503                                                 $payload .= "<!-- Content being gzipped -->";
5504                                         }
5505                                         $this->outgoing_headers[] = "Content-Encoding: gzip";
5506                                         $payload = gzencode($payload);
5507                                 } else {
5508                                         if (isset($this->debug_flag) && $this->debug_flag) {
5509                                                 $payload .= "<!-- Content will not be gzipped: no gzencode -->";
5510                                         }
5511                                 }
5512                         } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
5513                                 // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
5514                                 // instead of gzcompress output,
5515                                 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
5516                                 if (function_exists('gzdeflate')) {
5517                                         if (isset($this->debug_flag) && $this->debug_flag) {
5518                                                 $payload .= "<!-- Content being deflated -->";
5519                                         }
5520                                         $this->outgoing_headers[] = "Content-Encoding: deflate";
5521                                         $payload = gzdeflate($payload);
5522                                 } else {
5523                                         if (isset($this->debug_flag) && $this->debug_flag) {
5524                                                 $payload .= "<!-- Content will not be deflated: no gzcompress -->";
5525                                         }
5526                                 }
5527                         }
5528                 }
5529                 //end code
5530                 ob_end_clean();
5531                 ob_start();
5532                 $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
5533                 reset($this->outgoing_headers);
5534                 foreach($this->outgoing_headers as $hdr){
5535                         header($hdr, false);
5536                 }
5537                 print $payload;
5538                 ob_flush();
5539
5540                 $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
5541         }
5542
5543         /**
5544         * takes the value that was created by parsing the request
5545         * and compares to the method's signature, if available.
5546         *
5547         * @param        string  $operation      The operation to be invoked
5548         * @param        array   $request        The array of parameter values
5549         * @return       boolean Whether the operation was found
5550         * @access   private
5551         */
5552         function verify_method($operation,$request){
5553                 if(isset($this->wsdl) && is_object($this->wsdl)){
5554                         if($this->wsdl->getOperationData($operation)){
5555                                 return true;
5556                         }
5557             } elseif(isset($this->operations[$operation])){
5558                         return true;
5559                 }
5560                 return false;
5561         }
5562
5563         /**
5564         * processes SOAP message received from client
5565         *
5566         * @param        array   $headers        The HTTP headers
5567         * @param        string  $data           unprocessed request data from client
5568         * @return       mixed   value of the message, decoded into a PHP type
5569         * @access   private
5570         */
5571     function parseRequest($headers, $data) {
5572                 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
5573                 $this->appendDebug($this->varDump($headers));
5574         if (!isset($headers['content-type'])) {
5575                         $this->setError('Request not of type text/xml (no content-type header)');
5576                         return false;
5577         }
5578                 if (!strstr($headers['content-type'], 'text/xml')) {
5579                         $this->setError('Request not of type text/xml');
5580                         return false;
5581                 }
5582                 if (strpos($headers['content-type'], '=')) {
5583                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
5584                         $this->debug('Got response encoding: ' . $enc);
5585                         if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
5586                                 $this->xml_encoding = strtoupper($enc);
5587                         } else {
5588                                 $this->xml_encoding = 'US-ASCII';
5589                         }
5590                 } else {
5591                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5592                         $this->xml_encoding = 'ISO-8859-1';
5593                 }
5594                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
5595                 // parse response, get soap parser obj
5596                 $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
5597                 // parser debug
5598                 $this->debug("parser debug: \n".$parser->getDebug());
5599                 // if fault occurred during message parsing
5600                 if($err = $parser->getError()){
5601                         $this->result = 'fault: error in msg parsing: '.$err;
5602                         $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
5603                 // else successfully parsed request into soapval object
5604                 } else {
5605                         // get/set methodname
5606                         $this->methodURI = $parser->root_struct_namespace;
5607                         $this->methodname = $parser->root_struct_name;
5608                         $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
5609                         $this->debug('calling parser->get_soapbody()');
5610                         $this->methodparams = $parser->get_soapbody();
5611                         // get SOAP headers
5612                         $this->requestHeaders = $parser->getHeaders();
5613                         // get SOAP Header
5614                         $this->requestHeader = $parser->get_soapheader();
5615             // add document for doclit support
5616             $this->document = $parser->document;
5617                 }
5618          }
5619
5620         /**
5621         * gets the HTTP body for the current response.
5622         *
5623         * @param string $soapmsg The SOAP payload
5624         * @return string The HTTP body, which includes the SOAP payload
5625         * @access private
5626         */
5627         function getHTTPBody($soapmsg) {
5628                 return $soapmsg;
5629         }
5630
5631         /**
5632         * gets the HTTP content type for the current response.
5633         *
5634         * Note: getHTTPBody must be called before this.
5635         *
5636         * @return string the HTTP content type for the current response.
5637         * @access private
5638         */
5639         function getHTTPContentType() {
5640                 return 'text/xml';
5641         }
5642
5643         /**
5644         * gets the HTTP content type charset for the current response.
5645         * returns false for non-text content types.
5646         *
5647         * Note: getHTTPBody must be called before this.
5648         *
5649         * @return string the HTTP content type charset for the current response.
5650         * @access private
5651         */
5652         function getHTTPContentTypeCharset() {
5653                 return $this->soap_defencoding;
5654         }
5655
5656         /**
5657         * add a method to the dispatch map (this has been replaced by the register method)
5658         *
5659         * @param    string $methodname
5660         * @param    string $in array of input values
5661         * @param    string $out array of output values
5662         * @access   public
5663         * @deprecated
5664         */
5665         function add_to_map($methodname,$in,$out){
5666                         $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
5667         }
5668
5669         /**
5670         * register a service function with the server
5671         *
5672         * @param    string $name the name of the PHP function, class.method or class..method
5673         * @param    array $in assoc array of input values: key = param name, value = param type
5674         * @param    array $out assoc array of output values: key = param name, value = param type
5675         * @param        mixed $namespace the element namespace for the method or false
5676         * @param        mixed $soapaction the soapaction for the method or false
5677         * @param        mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
5678         * @param        mixed $use optional (encoded|literal) or false
5679         * @param        string $documentation optional Description to include in WSDL
5680         * @param        string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
5681         * @access   public
5682         */
5683         function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
5684                 global $HTTP_SERVER_VARS;
5685
5686                 if($this->externalWSDLURL){
5687                         die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
5688                 }
5689                 if (! $name) {
5690                         die('You must specify a name when you register an operation');
5691                 }
5692                 if (!is_array($in)) {
5693                         die('You must provide an array for operation inputs');
5694                 }
5695                 if (!is_array($out)) {
5696                         die('You must provide an array for operation outputs');
5697                 }
5698                 if(false == $namespace) {
5699                 }
5700                 if(false == $soapaction) {
5701                         if (isset($_SERVER)) {
5702                                 $SERVER_NAME = $_SERVER['SERVER_NAME'];
5703                                 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
5704                                 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
5705                         } elseif (isset($HTTP_SERVER_VARS)) {
5706                                 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
5707                                 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
5708                                 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
5709                         } else {
5710                                 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5711                         }
5712                 if ($HTTPS == '1' || $HTTPS == 'on') {
5713                         $SCHEME = 'https';
5714                 } else {
5715                         $SCHEME = 'http';
5716                 }
5717                         $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
5718                 }
5719                 if(false == $style) {
5720                         $style = "rpc";
5721                 }
5722                 if(false == $use) {
5723                         $use = "encoded";
5724                 }
5725                 if ($use == 'encoded' && $encodingStyle == '') {
5726                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5727                 }
5728
5729                 $this->operations[$name] = array(
5730             'name' => $name,
5731             'in' => $in,
5732             'out' => $out,
5733             'namespace' => $namespace,
5734             'soapaction' => $soapaction,
5735             'style' => $style);
5736         if($this->wsdl){
5737                 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
5738             }
5739                 return true;
5740         }
5741
5742         /**
5743         * Specify a fault to be returned to the client.
5744         * This also acts as a flag to the server that a fault has occured.
5745         *
5746         * @param        string $faultcode
5747         * @param        string $faultstring
5748         * @param        string $faultactor
5749         * @param        string $faultdetail
5750         * @access   public
5751         */
5752         function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
5753                 if ($faultdetail == '' && $this->debug_flag) {
5754                         $faultdetail = $this->getDebug();
5755                 }
5756                 $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
5757                 $this->fault->soap_defencoding = $this->soap_defencoding;
5758         }
5759
5760     /**
5761     * Sets up wsdl object.
5762     * Acts as a flag to enable internal WSDL generation
5763     *
5764     * @param string $serviceName, name of the service
5765     * @param mixed $namespace optional 'tns' service namespace or false
5766     * @param mixed $endpoint optional URL of service endpoint or false
5767     * @param string $style optional (rpc|document) WSDL style (also specified by operation)
5768     * @param string $transport optional SOAP transport
5769     * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
5770     */
5771     function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
5772     {
5773         global $HTTP_SERVER_VARS;
5774
5775                 if (isset($_SERVER)) {
5776                         $SERVER_NAME = $_SERVER['SERVER_NAME'];
5777                         $SERVER_PORT = $_SERVER['SERVER_PORT'];
5778                         $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
5779                         $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
5780                 } elseif (isset($HTTP_SERVER_VARS)) {
5781                         $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
5782                         $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
5783                         $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
5784                         $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
5785                 } else {
5786                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5787                 }
5788                 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
5789                 $colon = strpos($SERVER_NAME,":");
5790                 if ($colon) {
5791                     $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
5792                 }
5793                 if ($SERVER_PORT == 80) {
5794                         $SERVER_PORT = '';
5795                 } else {
5796                         $SERVER_PORT = ':' . $SERVER_PORT;
5797                 }
5798         if(false == $namespace) {
5799             $namespace = "http://$SERVER_NAME/soap/$serviceName";
5800         }
5801
5802         if(false == $endpoint) {
5803                 if ($HTTPS == '1' || $HTTPS == 'on') {
5804                         $SCHEME = 'https';
5805                 } else {
5806                         $SCHEME = 'http';
5807                 }
5808             $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
5809         }
5810
5811         if(false == $schemaTargetNamespace) {
5812             $schemaTargetNamespace = $namespace;
5813         }
5814
5815                 $this->wsdl = new wsdl;
5816                 $this->wsdl->serviceName = $serviceName;
5817         $this->wsdl->endpoint = $endpoint;
5818                 $this->wsdl->namespaces['tns'] = $namespace;
5819                 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
5820                 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
5821                 if ($schemaTargetNamespace != $namespace) {
5822                         $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
5823                 }
5824         $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
5825         if ($style == 'document') {
5826                 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
5827         }
5828         $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
5829         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
5830         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
5831         $this->wsdl->bindings[$serviceName.'Binding'] = array(
5832                 'name'=>$serviceName.'Binding',
5833             'style'=>$style,
5834             'transport'=>$transport,
5835             'portType'=>$serviceName.'PortType');
5836         $this->wsdl->ports[$serviceName.'Port'] = array(
5837                 'binding'=>$serviceName.'Binding',
5838             'location'=>$endpoint,
5839             'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
5840     }
5841 }
5842
5843 /**
5844  * Backward compatibility
5845  */
5846 class soap_server extends nusoap_server {
5847 }
5848
5849 ?><?php
5850
5851 /*
5852
5853 Modification information for LGPL compliance
5854
5855 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
5856     bug 40066
5857
5858 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
5859     Merging with maint_6_0_1 (svn merge -r 58250:58342)
5860
5861 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
5862     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
5863
5864 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
5865     fix SOAP calls with no parameters
5866
5867 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
5868
5869 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
5870
5871 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
5872
5873 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
5874
5875 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
5876
5877 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
5878
5879 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
5880
5881 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
5882 - Changing all ereg function to either preg or simple string based ones
5883 - No more references to magic quotes.
5884 - Change all the session_unregister() functions to just unset() the correct session variable instead.
5885
5886 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
5887
5888 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
5889
5890 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
5891
5892 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
5893
5894 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
5895
5896 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
5897
5898 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
5899
5900 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
5901
5902 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
5903 Touched:
5904 - data/SugarBean.php
5905 - include/domit/php_http_client_generic.php
5906 - include/domit/php_http_connector.php
5907 - include/domit/testing_domit.php
5908 - include/domit/xml_domit_getelementsbypath.php
5909 - include/domit/xml_domit_lite_parser.php
5910 - include/domit/xml_domit_nodemaps.php
5911 - include/domit/xml_domit_parser.php
5912 - include/domit/xml_domit_shared.php
5913 - include/generic/SugarWidgets/SugarWidgetField.php
5914 - include/generic/SugarWidgets/SugarWidgetReportField.php
5915 - include/ListView/ProcessView.php
5916 - include/nusoap/class.soapclient.php
5917 - include/nusoap/nusoap.php
5918 - include/nusoap/nusoapmime.php
5919 - include/Pear/HTML_Safe/Safe.php
5920 - include/Pear/XML_HTMLSax3/HTMLSax3.php
5921 - modules/Administration/RebuildWorkFlow.php
5922 - modules/Expressions/RelateSelector.php
5923 - modules/Reports/templates/templates_reports.php
5924 - modules/WorkFlow/Delete.php
5925 - modules/WorkFlow/Save.php
5926 - modules/WorkFlow/SaveSequence.php
5927 - modules/WorkFlow/WorkFlow.php
5928 - modules/WorkFlowActionShells/CreateStep1.php
5929 - modules/WorkFlowActionShells/CreateStep2.php
5930 - modules/WorkFlowActionShells/Save.php
5931 - modules/WorkFlowActionShells/WorkFlowActionShell.php
5932 - modules/WorkFlowAlerts/Save.php
5933 - modules/WorkFlowAlerts/WorkFlowAlert.php
5934 - modules/WorkFlowAlertShells/DetailView.php
5935 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
5936 - modules/WorkFlowTriggerShells/CreateStep1.php
5937 - modules/WorkFlowTriggerShells/CreateStepFilter.php
5938 - modules/WorkFlowTriggerShells/SaveFilter.php
5939 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
5940 - soap/SoapHelperFunctions.php
5941 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
5942 - test/simpletest/browser.php
5943 - test/simpletest/default_reporter.php
5944 - test/simpletest/detached.php
5945 - test/simpletest/eclipse.php
5946 - test/simpletest/expectation.php
5947 - test/simpletest/extensions/pear_test_case.php
5948 - test/simpletest/form.php
5949 - test/simpletest/http.php
5950 - test/simpletest/mock_objects.php
5951 - test/simpletest/page.php
5952 - test/simpletest/parser.php
5953 - test/simpletest/remote.php
5954 - test/simpletest/shell_tester.php
5955 - test/simpletest/simple_test.php
5956 - test/simpletest/simpletest.php
5957 - test/simpletest/test/acceptance_test.php
5958 - test/simpletest/test/adapter_test.php
5959 - test/simpletest/test/authentication_test.php
5960 - test/simpletest/test/browser_test.php
5961 - test/simpletest/test/collector_test.php
5962 - test/simpletest/test/compatibility_test.php
5963 - test/simpletest/test/detached_test.php
5964 - test/simpletest/test/eclipse_test.php
5965 - test/simpletest/test/encoding_test.php
5966 - test/simpletest/test/errors_test.php
5967 - test/simpletest/test/expectation_test.php
5968 - test/simpletest/test/form_test.php
5969 - test/simpletest/test/frames_test.php
5970 - test/simpletest/test/http_test.php
5971 - test/simpletest/test/live_test.php
5972 - test/simpletest/test/mock_objects_test.php
5973 - test/simpletest/test/page_test.php
5974 - test/simpletest/test/parse_error_test.php
5975 - test/simpletest/test/parser_test.php
5976 - test/simpletest/test/remote_test.php
5977 - test/simpletest/test/shell_test.php
5978 - test/simpletest/test/shell_tester_test.php
5979 - test/simpletest/test/simpletest_test.php
5980 - test/simpletest/test/site/page_request.php
5981 - test/simpletest/test/tag_test.php
5982 - test/simpletest/test/unit_tester_test.php
5983 - test/simpletest/test/user_agent_test.php
5984 - test/simpletest/test/visual_test.php
5985 - test/simpletest/test/xml_test.php
5986 - test/simpletest/test_case.php
5987 - test/simpletest/ui/array_reporter/test.php
5988 - test/simpletest/ui/recorder/test.php
5989 - test/simpletest/unit_tester.php
5990 - test/simpletest/url.php
5991 - test/simpletest/user_agent.php
5992 - test/simpletest/web_tester.php
5993 - test/spikephpcoverage/src/PEAR.php
5994 - test/spikephpcoverage/src/util/Utility.php
5995 - test/spikephpcoverage/src/XML/Parser.php
5996 - test/spikephpcoverage/src/XML/Parser/Simple.php
5997 - test/test_utilities/SugarTest_SimpleBrowser.php
5998
5999 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
6000
6001 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
6002
6003 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
6004
6005 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
6006
6007 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
6008
6009 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
6010
6011 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
6012
6013 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
6014
6015 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
6016
6017 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
6018
6019 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
6020
6021 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
6022
6023 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
6024
6025 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
6026
6027 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
6028
6029 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
6030
6031 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
6032
6033 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
6034
6035 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
6036
6037 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
6038
6039 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
6040
6041 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
6042
6043 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
6044
6045 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
6046
6047
6048 */
6049
6050
6051
6052
6053
6054 /**
6055 * parses a WSDL file, allows access to it's data, other utility methods.
6056 * also builds WSDL structures programmatically.
6057 *
6058 * @author   Dietrich Ayala <dietrich@ganx4.com>
6059 * @author   Scott Nichol <snichol@users.sourceforge.net>
6060
6061 * @access public
6062 */
6063 class wsdl extends nusoap_base {
6064         // URL or filename of the root of this WSDL
6065     var $wsdl;
6066     // define internal arrays of bindings, ports, operations, messages, etc.
6067     var $schemas = array();
6068     var $currentSchema;
6069     var $message = array();
6070     var $complexTypes = array();
6071     var $messages = array();
6072     var $currentMessage;
6073     var $currentOperation;
6074     var $portTypes = array();
6075     var $currentPortType;
6076     var $bindings = array();
6077     var $currentBinding;
6078     var $ports = array();
6079     var $currentPort;
6080     var $opData = array();
6081     var $status = '';
6082     var $documentation = false;
6083     var $endpoint = '';
6084     // array of wsdl docs to import
6085     var $import = array();
6086     // parser vars
6087     var $parser;
6088     var $position = 0;
6089     var $depth = 0;
6090     var $depth_array = array();
6091         // for getting wsdl
6092         var $proxyhost = '';
6093     var $proxyport = '';
6094         var $proxyusername = '';
6095         var $proxypassword = '';
6096         var $timeout = 0;
6097         var $response_timeout = 30;
6098         var $curl_options = array();    // User-specified cURL options
6099         var $use_curl = false;                  // whether to always try to use cURL
6100         // for HTTP authentication
6101         var $username = '';                             // Username for HTTP authentication
6102         var $password = '';                             // Password for HTTP authentication
6103         var $authtype = '';                             // Type of HTTP authentication
6104         var $certRequest = array();             // Certificate for HTTP SSL authentication
6105
6106     /**
6107      * constructor
6108      *
6109      * @param string $wsdl WSDL document URL
6110          * @param string $proxyhost
6111          * @param string $proxyport
6112          * @param string $proxyusername
6113          * @param string $proxypassword
6114          * @param integer $timeout set the connection timeout
6115          * @param integer $response_timeout set the response timeout
6116          * @param array $curl_options user-specified cURL options
6117          * @param boolean $use_curl try to use cURL
6118      * @access public
6119      */
6120     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
6121                 parent::nusoap_base();
6122                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
6123         $this->proxyhost = $proxyhost;
6124         $this->proxyport = $proxyport;
6125                 $this->proxyusername = $proxyusername;
6126                 $this->proxypassword = $proxypassword;
6127                 $this->timeout = $timeout;
6128                 $this->response_timeout = $response_timeout;
6129                 if (is_array($curl_options))
6130                         $this->curl_options = $curl_options;
6131                 $this->use_curl = $use_curl;
6132                 $this->fetchWSDL($wsdl);
6133     }
6134
6135         /**
6136          * fetches the WSDL document and parses it
6137          *
6138          * @access public
6139          */
6140         function fetchWSDL($wsdl) {
6141                 $this->debug("parse and process WSDL path=$wsdl");
6142                 $this->wsdl = $wsdl;
6143         // parse wsdl file
6144         if ($this->wsdl != "") {
6145             $this->parseWSDL($this->wsdl);
6146         }
6147         // imports
6148         // TODO: handle imports more properly, grabbing them in-line and nesting them
6149         $imported_urls = array();
6150         $imported = 1;
6151         while ($imported > 0) {
6152                 $imported = 0;
6153                 // Schema imports
6154                 foreach ($this->schemas as $ns => $list) {
6155                         foreach ($list as $xs) {
6156                                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
6157                             foreach ($xs->imports as $ns2 => $list2) {
6158                                 for ($ii = 0; $ii < count($list2); $ii++) {
6159                                         if (! $list2[$ii]['loaded']) {
6160                                                 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
6161                                                 $url = $list2[$ii]['location'];
6162                                                                 if ($url != '') {
6163                                                                         $urlparts = parse_url($url);
6164                                                                         if (!isset($urlparts['host'])) {
6165                                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
6166                                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
6167                                                                         }
6168                                                                         if (! in_array($url, $imported_urls)) {
6169                                                                 $this->parseWSDL($url);
6170                                                                 $imported++;
6171                                                                 $imported_urls[] = $url;
6172                                                         }
6173                                                                 } else {
6174                                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");
6175                                                                 }
6176                                                         }
6177                                                 }
6178                             }
6179                         }
6180                 }
6181                 // WSDL imports
6182                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
6183             foreach ($this->import as $ns => $list) {
6184                 for ($ii = 0; $ii < count($list); $ii++) {
6185                         if (! $list[$ii]['loaded']) {
6186                                 $this->import[$ns][$ii]['loaded'] = true;
6187                                 $url = $list[$ii]['location'];
6188                                                 if ($url != '') {
6189                                                         $urlparts = parse_url($url);
6190                                                         if (!isset($urlparts['host'])) {
6191                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
6192                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
6193                                                         }
6194                                                         if (! in_array($url, $imported_urls)) {
6195                                                 $this->parseWSDL($url);
6196                                                 $imported++;
6197                                                 $imported_urls[] = $url;
6198                                         }
6199                                                 } else {
6200                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");
6201                                                 }
6202                                         }
6203                                 }
6204             }
6205                 }
6206         // add new data to operation data
6207         foreach($this->bindings as $binding => $bindingData) {
6208             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
6209                 foreach($bindingData['operations'] as $operation => $data) {
6210                     $this->debug('post-parse data gathering for ' . $operation);
6211                     $this->bindings[$binding]['operations'][$operation]['input'] =
6212                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ?
6213                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
6214                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
6215                     $this->bindings[$binding]['operations'][$operation]['output'] =
6216                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
6217                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
6218                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
6219                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
6220                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
6221                                         }
6222                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
6223                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
6224                     }
6225                     // Set operation style if necessary, but do not override one already provided
6226                                         if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
6227                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
6228                     }
6229                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
6230                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
6231                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
6232                 }
6233             }
6234         }
6235         }
6236
6237     /**
6238      * parses the wsdl document
6239      *
6240      * @param string $wsdl path or URL
6241      * @access private
6242      */
6243     function parseWSDL($wsdl = '') {
6244                 $this->debug("parse WSDL at path=$wsdl");
6245
6246         if ($wsdl == '') {
6247             $this->debug('no wsdl passed to parseWSDL()!!');
6248             $this->setError('no wsdl passed to parseWSDL()!!');
6249             return false;
6250         }
6251
6252         // parse $wsdl for url format
6253         $wsdl_props = parse_url($wsdl);
6254
6255         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
6256             $this->debug('getting WSDL http(s) URL ' . $wsdl);
6257                 // get wsdl
6258                 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
6259                         $tr->request_method = 'GET';
6260                         $tr->useSOAPAction = false;
6261                         if($this->proxyhost && $this->proxyport){
6262                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
6263                         }
6264                         if ($this->authtype != '') {
6265                                 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
6266                         }
6267                         $tr->setEncoding('gzip, deflate');
6268                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
6269                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);
6270                         //$this->debug("WSDL response\n" . $tr->incoming_payload);
6271                         $this->appendDebug($tr->getDebug());
6272                         // catch errors
6273                         if($err = $tr->getError() ){
6274                                 $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err;
6275                                 $this->debug($errstr);
6276                     $this->setError($errstr);
6277                                 unset($tr);
6278                     return false;
6279                         }
6280                         unset($tr);
6281                         $this->debug("got WSDL URL");
6282         } else {
6283             // $wsdl is not http(s), so treat it as a file URL or plain file path
6284                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
6285                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
6286                 } else {
6287                         $path = $wsdl;
6288                 }
6289             $this->debug('getting WSDL file ' . $path);
6290             if ($fp = @fopen($path, 'r')) {
6291                 $wsdl_string = '';
6292                 while ($data = fread($fp, 32768)) {
6293                     $wsdl_string .= $data;
6294                 }
6295                 fclose($fp);
6296             } else {
6297                 $errstr = "Bad path to WSDL file $path";
6298                 $this->debug($errstr);
6299                 $this->setError($errstr);
6300                 return false;
6301             }
6302         }
6303         $this->debug('Parse WSDL');
6304         // end new code added
6305         // Create an XML parser.
6306         $this->parser = xml_parser_create();
6307         // Set the options for parsing the XML data.
6308         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6309         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6310         // Set the object for the parser.
6311         xml_set_object($this->parser, $this);
6312         // Set the element handlers for the parser.
6313         xml_set_element_handler($this->parser, 'start_element', 'end_element');
6314         xml_set_character_data_handler($this->parser, 'character_data');
6315         // Parse the XML file.
6316         if (!xml_parse($this->parser, $wsdl_string, true)) {
6317             // Display an error message.
6318             $errstr = sprintf(
6319                                 'XML error parsing WSDL from %s on line %d: %s',
6320                                 $wsdl,
6321                 xml_get_current_line_number($this->parser),
6322                 xml_error_string(xml_get_error_code($this->parser))
6323                 );
6324             $this->debug($errstr);
6325                         $this->debug("XML payload:\n" . $wsdl_string);
6326             $this->setError($errstr);
6327             return false;
6328         }
6329                 // free the parser
6330         xml_parser_free($this->parser);
6331         $this->debug('Parsing WSDL done');
6332                 // catch wsdl parse errors
6333                 if($this->getError()){
6334                         return false;
6335                 }
6336         return true;
6337     }
6338
6339     /**
6340      * start-element handler
6341      *
6342      * @param string $parser XML parser object
6343      * @param string $name element name
6344      * @param string $attrs associative array of attributes
6345      * @access private
6346      */
6347     function start_element($parser, $name, $attrs)
6348     {
6349         if ($this->status == 'schema') {
6350             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
6351             $this->appendDebug($this->currentSchema->getDebug());
6352             $this->currentSchema->clearDebug();
6353         } elseif (preg_match('/schema$/', $name)) {
6354                 $this->debug('Parsing WSDL schema');
6355             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
6356             $this->status = 'schema';
6357             $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
6358             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
6359             $this->appendDebug($this->currentSchema->getDebug());
6360             $this->currentSchema->clearDebug();
6361         } else {
6362             // position in the total number of elements, starting from 0
6363             $pos = $this->position++;
6364             $depth = $this->depth++;
6365             // set self as current value for this depth
6366             $this->depth_array[$depth] = $pos;
6367             $this->message[$pos] = array('cdata' => '');
6368             // process attributes
6369             if (count($attrs) > 0) {
6370                                 // register namespace declarations
6371                 foreach($attrs as $k => $v) {
6372                     if (preg_match('/^xmlns/',$k)) {
6373                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
6374                             $this->namespaces[$ns_prefix] = $v;
6375                         } else {
6376                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
6377                         }
6378                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
6379                             $this->XMLSchemaVersion = $v;
6380                             $this->namespaces['xsi'] = $v . '-instance';
6381                         }
6382                     }
6383                 }
6384                 // expand each attribute prefix to its namespace
6385                 foreach($attrs as $k => $v) {
6386                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6387                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
6388                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6389                     }
6390                     $eAttrs[$k] = $v;
6391                 }
6392                 $attrs = $eAttrs;
6393             } else {
6394                 $attrs = array();
6395             }
6396             // get element prefix, namespace and name
6397             if (preg_match('/:/', $name)) {
6398                 // get ns prefix
6399                 $prefix = substr($name, 0, strpos($name, ':'));
6400                 // get ns
6401                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
6402                 // get unqualified name
6403                 $name = substr(strstr($name, ':'), 1);
6404             }
6405                         // process attributes, expanding any prefixes to namespaces
6406             // find status, register data
6407             switch ($this->status) {
6408                 case 'message':
6409                     if ($name == 'part') {
6410                                     if (isset($attrs['type'])) {
6411                                     $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
6412                                     $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
6413                                 }
6414                                     if (isset($attrs['element'])) {
6415                                     $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
6416                                         $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
6417                                     }
6418                                 }
6419                                 break;
6420                             case 'portType':
6421                                 switch ($name) {
6422                                     case 'operation':
6423                                         $this->currentPortOperation = $attrs['name'];
6424                                         $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
6425                                         if (isset($attrs['parameterOrder'])) {
6426                                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
6427                                                 }
6428                                                 break;
6429                                             case 'documentation':
6430                                                 $this->documentation = true;
6431                                                 break;
6432                                             // merge input/output data
6433                                             default:
6434                                                 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
6435                                                 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
6436                                                 break;
6437                                         }
6438                                 break;
6439                                 case 'binding':
6440                                     switch ($name) {
6441                                         case 'binding':
6442                                             // get ns prefix
6443                                             if (isset($attrs['style'])) {
6444                                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;
6445                                                 }
6446                                                 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
6447                                                 break;
6448                                                 case 'header':
6449                                                     $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
6450                                                     break;
6451                                                 case 'operation':
6452                                                     if (isset($attrs['soapAction'])) {
6453                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
6454                                                     }
6455                                                     if (isset($attrs['style'])) {
6456                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
6457                                                     }
6458                                                     if (isset($attrs['name'])) {
6459                                                         $this->currentOperation = $attrs['name'];
6460                                                         $this->debug("current binding operation: $this->currentOperation");
6461                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
6462                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
6463                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
6464                                                     }
6465                                                     break;
6466                                                 case 'input':
6467                                                     $this->opStatus = 'input';
6468                                                     break;
6469                                                 case 'output':
6470                                                     $this->opStatus = 'output';
6471                                                     break;
6472                                                 case 'body':
6473                                                     if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
6474                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
6475                                                     } else {
6476                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
6477                                                     }
6478                                                     break;
6479                                         }
6480                                         break;
6481                                 case 'service':
6482                                         switch ($name) {
6483                                             case 'port':
6484                                                 $this->currentPort = $attrs['name'];
6485                                                 $this->debug('current port: ' . $this->currentPort);
6486                                                 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
6487
6488                                                 break;
6489                                             case 'address':
6490                                                 $this->ports[$this->currentPort]['location'] = $attrs['location'];
6491                                                 $this->ports[$this->currentPort]['bindingType'] = $namespace;
6492                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
6493                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
6494                                                 break;
6495                                         }
6496                                         break;
6497                         }
6498                 // set status
6499                 switch ($name) {
6500                         case 'import':
6501                             if (isset($attrs['location'])) {
6502                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
6503                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
6504                                 } else {
6505                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
6506                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
6507                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
6508                                         }
6509                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
6510                                 }
6511                                 break;
6512                         //wait for schema
6513                         //case 'types':
6514                         //      $this->status = 'schema';
6515                         //      break;
6516                         case 'message':
6517                                 $this->status = 'message';
6518                                 $this->messages[$attrs['name']] = array();
6519                                 $this->currentMessage = $attrs['name'];
6520                                 break;
6521                         case 'portType':
6522                                 $this->status = 'portType';
6523                                 $this->portTypes[$attrs['name']] = array();
6524                                 $this->currentPortType = $attrs['name'];
6525                                 break;
6526                         case "binding":
6527                                 if (isset($attrs['name'])) {
6528                                 // get binding name
6529                                         if (strpos($attrs['name'], ':')) {
6530                                         $this->currentBinding = $this->getLocalPart($attrs['name']);
6531                                         } else {
6532                                         $this->currentBinding = $attrs['name'];
6533                                         }
6534                                         $this->status = 'binding';
6535                                         $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
6536                                         $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
6537                                 }
6538                                 break;
6539                         case 'service':
6540                                 $this->serviceName = $attrs['name'];
6541                                 $this->status = 'service';
6542                                 $this->debug('current service: ' . $this->serviceName);
6543                                 break;
6544                         case 'definitions':
6545                                 foreach ($attrs as $name => $value) {
6546                                         $this->wsdl_info[$name] = $value;
6547                                 }
6548                                 break;
6549                         }
6550                 }
6551         }
6552
6553         /**
6554         * end-element handler
6555         *
6556         * @param string $parser XML parser object
6557         * @param string $name element name
6558         * @access private
6559         */
6560         function end_element($parser, $name){
6561                 // unset schema status
6562                 if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
6563                         $this->status = "";
6564             $this->appendDebug($this->currentSchema->getDebug());
6565             $this->currentSchema->clearDebug();
6566                         $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
6567                 $this->debug('Parsing WSDL schema done');
6568                 }
6569                 if ($this->status == 'schema') {
6570                         $this->currentSchema->schemaEndElement($parser, $name);
6571                 } else {
6572                         // bring depth down a notch
6573                         $this->depth--;
6574                 }
6575                 // end documentation
6576                 if ($this->documentation) {
6577                         //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
6578                         //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
6579                         $this->documentation = false;
6580                 }
6581         }
6582
6583         /**
6584          * element content handler
6585          *
6586          * @param string $parser XML parser object
6587          * @param string $data element content
6588          * @access private
6589          */
6590         function character_data($parser, $data)
6591         {
6592                 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
6593                 if (isset($this->message[$pos]['cdata'])) {
6594                         $this->message[$pos]['cdata'] .= $data;
6595                 }
6596                 if ($this->documentation) {
6597                         $this->documentation .= $data;
6598                 }
6599         }
6600
6601         /**
6602         * if authenticating, set user credentials here
6603         *
6604         * @param    string $username
6605         * @param    string $password
6606         * @param        string $authtype (basic|digest|certificate|ntlm)
6607         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
6608         * @access   public
6609         */
6610         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
6611                 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
6612                 $this->appendDebug($this->varDump($certRequest));
6613                 $this->username = $username;
6614                 $this->password = $password;
6615                 $this->authtype = $authtype;
6616                 $this->certRequest = $certRequest;
6617         }
6618
6619         function getBindingData($binding)
6620         {
6621                 if (is_array($this->bindings[$binding])) {
6622                         return $this->bindings[$binding];
6623                 }
6624         }
6625
6626         /**
6627          * returns an assoc array of operation names => operation data
6628          *
6629          * @param string $portName WSDL port name
6630          * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
6631          * @return array
6632          * @access public
6633          */
6634         function getOperations($portName = '', $bindingType = 'soap') {
6635                 $ops = array();
6636                 if ($bindingType == 'soap') {
6637                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
6638                 } elseif ($bindingType == 'soap12') {
6639                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
6640                 } else {
6641                         $this->debug("getOperations bindingType $bindingType may not be supported");
6642                 }
6643                 $this->debug("getOperations for port '$portName' bindingType $bindingType");
6644                 // loop thru ports
6645                 foreach($this->ports as $port => $portData) {
6646                         $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
6647                         if ($portName == '' || $port == $portName) {
6648                                 // binding type of port matches parameter
6649                                 if ($portData['bindingType'] == $bindingType) {
6650                                         $this->debug("getOperations found port $port bindingType $bindingType");
6651                                         //$this->debug("port data: " . $this->varDump($portData));
6652                                         //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
6653                                         // merge bindings
6654                                         if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
6655                                                 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
6656                                         }
6657                                 }
6658                         }
6659                 }
6660                 if (count($ops) == 0) {
6661                         $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
6662                 }
6663                 return $ops;
6664         }
6665
6666         /**
6667          * returns an associative array of data necessary for calling an operation
6668          *
6669          * @param string $operation name of operation
6670          * @param string $bindingType type of binding eg: soap, soap12
6671          * @return array
6672          * @access public
6673          */
6674         function getOperationData($operation, $bindingType = 'soap')
6675         {
6676                 if ($bindingType == 'soap') {
6677                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
6678                 } elseif ($bindingType == 'soap12') {
6679                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
6680                 }
6681                 // loop thru ports
6682                 foreach($this->ports as $port => $portData) {
6683                         // binding type of port matches parameter
6684                         if ($portData['bindingType'] == $bindingType) {
6685                                 // get binding
6686                                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
6687                                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
6688                                         // note that we could/should also check the namespace here
6689                                         if ($operation == $bOperation) {
6690                                                 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
6691                                             return $opData;
6692                                         }
6693                                 }
6694                         }
6695                 }
6696         }
6697
6698         /**
6699          * returns an associative array of data necessary for calling an operation
6700          *
6701          * @param string $soapAction soapAction for operation
6702          * @param string $bindingType type of binding eg: soap, soap12
6703          * @return array
6704          * @access public
6705          */
6706         function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
6707                 if ($bindingType == 'soap') {
6708                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
6709                 } elseif ($bindingType == 'soap12') {
6710                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
6711                 }
6712                 // loop thru ports
6713                 foreach($this->ports as $port => $portData) {
6714                         // binding type of port matches parameter
6715                         if ($portData['bindingType'] == $bindingType) {
6716                                 // loop through operations for the binding
6717                                 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
6718                                         if ($opData['soapAction'] == $soapAction) {
6719                                             return $opData;
6720                                         }
6721                                 }
6722                         }
6723                 }
6724         }
6725
6726         /**
6727     * returns an array of information about a given type
6728     * returns false if no type exists by the given name
6729     *
6730         *        typeDef = array(
6731         *        'elements' => array(), // refs to elements array
6732         *       'restrictionBase' => '',
6733         *       'phpType' => '',
6734         *       'order' => '(sequence|all)',
6735         *       'attrs' => array() // refs to attributes array
6736         *       )
6737     *
6738     * @param string $type the type
6739     * @param string $ns namespace (not prefix) of the type
6740     * @return mixed
6741     * @access public
6742     * @see nusoap_xmlschema
6743     */
6744         function getTypeDef($type, $ns) {
6745                 $this->debug("in getTypeDef: type=$type, ns=$ns");
6746                 if ((! $ns) && isset($this->namespaces['tns'])) {
6747                         $ns = $this->namespaces['tns'];
6748                         $this->debug("in getTypeDef: type namespace forced to $ns");
6749                 }
6750                 if (!isset($this->schemas[$ns])) {
6751                         foreach ($this->schemas as $ns0 => $schema0) {
6752                                 if (strcasecmp($ns, $ns0) == 0) {
6753                                         $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
6754                                         $ns = $ns0;
6755                                         break;
6756                                 }
6757                         }
6758                 }
6759                 if (isset($this->schemas[$ns])) {
6760                         $this->debug("in getTypeDef: have schema for namespace $ns");
6761                         for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
6762                                 $xs = &$this->schemas[$ns][$i];
6763                                 $t = $xs->getTypeDef($type);
6764                                 $this->appendDebug($xs->getDebug());
6765                                 $xs->clearDebug();
6766                                 if ($t) {
6767                                         $this->debug("in getTypeDef: found type $type");
6768                                         if (!isset($t['phpType'])) {
6769                                                 // get info for type to tack onto the element
6770                                                 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
6771                                                 $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
6772                                                 $etype = $this->getTypeDef($uqType, $ns);
6773                                                 if ($etype) {
6774                                                         $this->debug("found type for [element] $type:");
6775                                                         $this->debug($this->varDump($etype));
6776                                                         if (isset($etype['phpType'])) {
6777                                                                 $t['phpType'] = $etype['phpType'];
6778                                                         }
6779                                                         if (isset($etype['elements'])) {
6780                                                                 $t['elements'] = $etype['elements'];
6781                                                         }
6782                                                         if (isset($etype['attrs'])) {
6783                                                                 $t['attrs'] = $etype['attrs'];
6784                                                         }
6785                                                 } else {
6786                                                         $this->debug("did not find type for [element] $type");
6787                                                 }
6788                                         }
6789                                         return $t;
6790                                 }
6791                         }
6792                         $this->debug("in getTypeDef: did not find type $type");
6793                 } else {
6794                         $this->debug("in getTypeDef: do not have schema for namespace $ns");
6795                 }
6796                 return false;
6797         }
6798
6799     /**
6800     * prints html description of services
6801     *
6802     * @access private
6803     */
6804     function webDescription(){
6805         global $HTTP_SERVER_VARS;
6806
6807                 if (isset($_SERVER)) {
6808                         $PHP_SELF = $_SERVER['PHP_SELF'];
6809                 } elseif (isset($HTTP_SERVER_VARS)) {
6810                         $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
6811                 } else {
6812                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
6813                 }
6814
6815                 $b = '
6816                 <html><head><title>NuSOAP: '.$this->serviceName.'</title>
6817                 <style type="text/css">
6818                     body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
6819                     p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
6820                     pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
6821                     ul      { margin-top: 10px; margin-left: 20px; }
6822                     li      { list-style-type: none; margin-top: 10px; color: #000000; }
6823                     .content{
6824                         margin-left: 0px; padding-bottom: 2em; }
6825                     .nav {
6826                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
6827                         margin-top: 10px; margin-left: 0px; color: #000000;
6828                         background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
6829                     .title {
6830                         font-family: arial; font-size: 26px; color: #ffffff;
6831                         background-color: #999999; width: 100%;
6832                         margin-left: 0px; margin-right: 0px;
6833                         padding-top: 10px; padding-bottom: 10px;}
6834                     .hidden {
6835                         position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
6836                         font-family: arial; overflow: hidden; width: 600;
6837                         padding: 20px; font-size: 10px; background-color: #999999;
6838                         layer-background-color:#FFFFFF; }
6839                     a,a:active  { color: charcoal; font-weight: bold; }
6840                     a:visited   { color: #666666; font-weight: bold; }
6841                     a:hover     { color: cc3300; font-weight: bold; }
6842                 </style>
6843                 <script language="JavaScript" type="text/javascript">
6844                 <!--
6845                 // POP-UP CAPTIONS...
6846                 function lib_bwcheck(){ //Browsercheck (needed)
6847                     this.ver=navigator.appVersion
6848                     this.agent=navigator.userAgent
6849                     this.dom=document.getElementById?1:0
6850                     this.opera5=this.agent.indexOf("Opera 5")>-1
6851                     this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
6852                     this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
6853                     this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
6854                     this.ie=this.ie4||this.ie5||this.ie6
6855                     this.mac=this.agent.indexOf("Mac")>-1
6856                     this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
6857                     this.ns4=(document.layers && !this.dom)?1:0;
6858                     this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
6859                     return this
6860                 }
6861                 var bw = new lib_bwcheck()
6862                 //Makes crossbrowser object.
6863                 function makeObj(obj){
6864                     this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
6865                     if(!this.evnt) return false
6866                     this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
6867                     this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
6868                     this.writeIt=b_writeIt;
6869                     return this
6870                 }
6871                 // A unit of measure that will be added when setting the position of a layer.
6872                 //var px = bw.ns4||window.opera?"":"px";
6873                 function b_writeIt(text){
6874                     if (bw.ns4){this.wref.write(text);this.wref.close()}
6875                     else this.wref.innerHTML = text
6876                 }
6877                 //Shows the messages
6878                 var oDesc;
6879                 function popup(divid){
6880                     if(oDesc = new makeObj(divid)){
6881                         oDesc.css.visibility = "visible"
6882                     }
6883                 }
6884                 function popout(){ // Hides message
6885                     if(oDesc) oDesc.css.visibility = "hidden"
6886                 }
6887                 //-->
6888                 </script>
6889                 </head>
6890                 <body>
6891                 <div class=content>
6892                         <br><br>
6893                         <div class=title>'.$this->serviceName.'</div>
6894                         <div class=nav>
6895                                 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
6896                                 Click on an operation name to view it&apos;s details.</p>
6897                                 <ul>';
6898                                 foreach($this->getOperations() as $op => $data){
6899                                     $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
6900                                     // create hidden div
6901                                     $b .= "<div id='$op' class='hidden'>
6902                                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
6903                                     foreach($data as $donnie => $marie){ // loop through opdata
6904                                                 if($donnie == 'input' || $donnie == 'output'){ // show input/output data
6905                                                     $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
6906                                                     foreach($marie as $captain => $tenille){ // loop through data
6907                                                                 if($captain == 'parts'){ // loop thru parts
6908                                                                     $b .= "&nbsp;&nbsp;$captain:<br>";
6909                                                         //if(is_array($tenille)){
6910                                                                         foreach($tenille as $joanie => $chachi){
6911                                                                                         $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
6912                                                                         }
6913                                                                 //}
6914                                                                 } else {
6915                                                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
6916                                                                 }
6917                                                     }
6918                                                 } else {
6919                                                     $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
6920                                                 }
6921                                     }
6922                                         $b .= '</div>';
6923                                 }
6924                                 $b .= '
6925                                 <ul>
6926                         </div>
6927                 </div></body></html>';
6928                 return $b;
6929     }
6930
6931         /**
6932         * serialize the parsed wsdl
6933         *
6934         * @param mixed $debug whether to put debug=1 in endpoint URL
6935         * @return string serialization of WSDL
6936         * @access public
6937         */
6938         function serialize($debug = 0)
6939         {
6940                 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
6941                 $xml .= "\n<definitions";
6942                 foreach($this->namespaces as $k => $v) {
6943                         $xml .= " xmlns:$k=\"$v\"";
6944                 }
6945                 // 10.9.02 - add poulter fix for wsdl and tns declarations
6946                 if (isset($this->namespaces['wsdl'])) {
6947                         $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
6948                 }
6949                 if (isset($this->namespaces['tns'])) {
6950                         $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
6951                 }
6952                 $xml .= '>';
6953                 // imports
6954                 if (sizeof($this->import) > 0) {
6955                         foreach($this->import as $ns => $list) {
6956                                 foreach ($list as $ii) {
6957                                         if ($ii['location'] != '') {
6958                                                 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
6959                                         } else {
6960                                                 $xml .= '<import namespace="' . $ns . '" />';
6961                                         }
6962                                 }
6963                         }
6964                 }
6965                 // types
6966                 if (count($this->schemas)>=1) {
6967                         $xml .= "\n<types>\n";
6968                         foreach ($this->schemas as $ns => $list) {
6969                                 foreach ($list as $xs) {
6970                                         $xml .= $xs->serializeSchema();
6971                                 }
6972                         }
6973                         $xml .= '</types>';
6974                 }
6975                 // messages
6976                 if (count($this->messages) >= 1) {
6977                         foreach($this->messages as $msgName => $msgParts) {
6978                                 $xml .= "\n<message name=\"" . $msgName . '">';
6979                                 if(is_array($msgParts)){
6980                                         foreach($msgParts as $partName => $partType) {
6981                                                 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
6982                                                 if (strpos($partType, ':')) {
6983                                                     $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
6984                                                 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
6985                                                     // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
6986                                                     $typePrefix = 'xsd';
6987                                                 } else {
6988                                                     foreach($this->typemap as $ns => $types) {
6989                                                         if (isset($types[$partType])) {
6990                                                             $typePrefix = $this->getPrefixFromNamespace($ns);
6991                                                         }
6992                                                     }
6993                                                     if (!isset($typePrefix)) {
6994                                                         die("$partType has no namespace!");
6995                                                     }
6996                                                 }
6997                                                 $ns = $this->getNamespaceFromPrefix($typePrefix);
6998                                                 $localPart = $this->getLocalPart($partType);
6999                                                 $typeDef = $this->getTypeDef($localPart, $ns);
7000                                                 if ($typeDef['typeClass'] == 'element') {
7001                                                         $elementortype = 'element';
7002                                                         if (substr($localPart, -1) == '^') {
7003                                                                 $localPart = substr($localPart, 0, -1);
7004                                                         }
7005                                                 } else {
7006                                                         $elementortype = 'type';
7007                                                 }
7008                                                 $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
7009                                         }
7010                                 }
7011                                 $xml .= '</message>';
7012                         }
7013                 }
7014                 // bindings & porttypes
7015                 if (count($this->bindings) >= 1) {
7016                         $binding_xml = '';
7017                         $portType_xml = '';
7018                         foreach($this->bindings as $bindingName => $attrs) {
7019                                 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
7020                                 $binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
7021                                 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
7022                                 foreach($attrs['operations'] as $opName => $opParts) {
7023                                         $binding_xml .= "\n" . '  <operation name="' . $opName . '">';
7024                                         $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
7025                                         if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
7026                                                 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
7027                                         } else {
7028                                                 $enc_style = '';
7029                                         }
7030                                         $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
7031                                         if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
7032                                                 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
7033                                         } else {
7034                                                 $enc_style = '';
7035                                         }
7036                                         $binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
7037                                         $binding_xml .= "\n" . '  </operation>';
7038                                         $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
7039                                         if (isset($opParts['parameterOrder'])) {
7040                                             $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
7041                                         }
7042                                         $portType_xml .= '>';
7043                                         if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
7044                                                 $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
7045                                         }
7046                                         $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';
7047                                         $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';
7048                                         $portType_xml .= "\n" . '  </operation>';
7049                                 }
7050                                 $portType_xml .= "\n" . '</portType>';
7051                                 $binding_xml .= "\n" . '</binding>';
7052                         }
7053                         $xml .= $portType_xml . $binding_xml;
7054                 }
7055                 // services
7056                 $xml .= "\n<service name=\"" . $this->serviceName . '">';
7057                 if (count($this->ports) >= 1) {
7058                         foreach($this->ports as $pName => $attrs) {
7059                                 $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
7060                                 $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
7061                                 $xml .= "\n" . '  </port>';
7062                         }
7063                 }
7064                 $xml .= "\n" . '</service>';
7065                 return $xml . "\n</definitions>";
7066         }
7067
7068         /**
7069          * determine whether a set of parameters are unwrapped
7070          * when they are expect to be wrapped, Microsoft-style.
7071          *
7072          * @param string $type the type (element name) of the wrapper
7073          * @param array $parameters the parameter values for the SOAP call
7074          * @return boolean whether they parameters are unwrapped (and should be wrapped)
7075          * @access private
7076          */
7077         function parametersMatchWrapped($type, &$parameters) {
7078                 $this->debug("in parametersMatchWrapped type=$type, parameters=");
7079                 $this->appendDebug($this->varDump($parameters));
7080
7081                 // split type into namespace:unqualified-type
7082                 if (strpos($type, ':')) {
7083                         $uqType = substr($type, strrpos($type, ':') + 1);
7084                         $ns = substr($type, 0, strrpos($type, ':'));
7085                         $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
7086                         if ($this->getNamespaceFromPrefix($ns)) {
7087                                 $ns = $this->getNamespaceFromPrefix($ns);
7088                                 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
7089                         }
7090                 } else {
7091                         // TODO: should the type be compared to types in XSD, and the namespace
7092                         // set to XSD if the type matches?
7093                         $this->debug("in parametersMatchWrapped: No namespace for type $type");
7094                         $ns = '';
7095                         $uqType = $type;
7096                 }
7097
7098                 // get the type information
7099                 if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
7100                         $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
7101                         return false;
7102                 }
7103                 $this->debug("in parametersMatchWrapped: found typeDef=");
7104                 $this->appendDebug($this->varDump($typeDef));
7105                 if (substr($uqType, -1) == '^') {
7106                         $uqType = substr($uqType, 0, -1);
7107                 }
7108                 $phpType = $typeDef['phpType'];
7109                 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
7110                 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
7111
7112                 // we expect a complexType or element of complexType
7113                 if ($phpType != 'struct') {
7114                         $this->debug("in parametersMatchWrapped: not a struct");
7115                         return false;
7116                 }
7117
7118                 // see whether the parameter names match the elements
7119                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
7120                         $elements = 0;
7121                         $matches = 0;
7122                         foreach ($typeDef['elements'] as $name => $attrs) {
7123                                 if (isset($parameters[$name])) {
7124                                         $this->debug("in parametersMatchWrapped: have parameter named $name");
7125                                         $matches++;
7126                                 } else {
7127                                         $this->debug("in parametersMatchWrapped: do not have parameter named $name");
7128                                 }
7129                                 $elements++;
7130                         }
7131
7132                         $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
7133                         if ($matches == 0) {
7134                                 return false;
7135                         }
7136                         return true;
7137                 }
7138
7139                 // since there are no elements for the type, if the user passed no
7140                 // parameters, the parameters match wrapped.
7141                 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
7142                 return count($parameters) == 0;
7143         }
7144
7145         /**
7146          * serialize PHP values according to a WSDL message definition
7147          * contrary to the method name, this is not limited to RPC
7148          *
7149          * TODO
7150          * - multi-ref serialization
7151          * - validate PHP values against type definitions, return errors if invalid
7152          *
7153          * @param string $operation operation name
7154          * @param string $direction (input|output)
7155          * @param mixed $parameters parameter value(s)
7156          * @param string $bindingType (soap|soap12)
7157          * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
7158          * @access public
7159          */
7160         function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
7161                 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
7162                 $this->appendDebug('parameters=' . $this->varDump($parameters));
7163
7164                 if ($direction != 'input' && $direction != 'output') {
7165                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
7166                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
7167                         return false;
7168                 }
7169                 if (!$opData = $this->getOperationData($operation, $bindingType)) {
7170                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
7171                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
7172                         return false;
7173                 }
7174                 $this->debug('in serializeRPCParameters: opData:');
7175                 $this->appendDebug($this->varDump($opData));
7176
7177                 // Get encoding style for output and set to current
7178                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7179                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
7180                         $encodingStyle = $opData['output']['encodingStyle'];
7181                         $enc_style = $encodingStyle;
7182                 }
7183
7184                 // set input params
7185                 $xml = '';
7186                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
7187                         $parts = &$opData[$direction]['parts'];
7188                         $part_count = sizeof($parts);
7189                         $style = $opData['style'];
7190                         $use = $opData[$direction]['use'];
7191                         $this->debug("have $part_count part(s) to serialize using $style/$use");
7192                         if (is_array($parameters)) {
7193                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
7194                                 $parameter_count = count($parameters);
7195                                 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
7196                                 // check for Microsoft-style wrapped parameters
7197                                 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
7198                                         $this->debug('check whether the caller has wrapped the parameters');
7199                                         if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) {
7200                                                 // TODO: consider checking here for double-wrapping, when
7201                                                 // service function wraps, then NuSOAP wraps again
7202                                                 $this->debug("change simple array to associative with 'parameters' element");
7203                                                 $parameters['parameters'] = $parameters[0];
7204                                                 unset($parameters[0]);
7205                                         }
7206                                         if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) {
7207                                                 $this->debug('check whether caller\'s parameters match the wrapped ones');
7208                                                 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
7209                                                         $this->debug('wrap the parameters for the caller');
7210                                                         $parameters = array('parameters' => $parameters);
7211                                                         $parameter_count = 1;
7212                                                 }
7213                                         }
7214                                 }
7215                                 foreach ($parts as $name => $type) {
7216                                         $this->debug("serializing part $name of type $type");
7217                                         // Track encoding style
7218                                         if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
7219                                                 $encodingStyle = $opData[$direction]['encodingStyle'];
7220                                                 $enc_style = $encodingStyle;
7221                                         } else {
7222                                                 $enc_style = false;
7223                                         }
7224                                         // NOTE: add error handling here
7225                                         // if serializeType returns false, then catch global error and fault
7226                                         if ($parametersArrayType == 'arraySimple') {
7227                                                 $p = array_shift($parameters);
7228                                                 $this->debug('calling serializeType w/indexed param');
7229                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
7230                                         } elseif (isset($parameters[$name])) {
7231                                                 $this->debug('calling serializeType w/named param');
7232                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
7233                                         } else {
7234                                                 // TODO: only send nillable
7235                                                 $this->debug('calling serializeType w/null param');
7236                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
7237                                         }
7238                                 }
7239                         } else {
7240                                 $this->debug('no parameters passed.');
7241                         }
7242                 }
7243                 $this->debug("serializeRPCParameters returning: $xml");
7244                 return $xml;
7245         }
7246
7247         /**
7248          * serialize a PHP value according to a WSDL message definition
7249          *
7250          * TODO
7251          * - multi-ref serialization
7252          * - validate PHP values against type definitions, return errors if invalid
7253          *
7254          * @param string $operation operation name
7255          * @param string $direction (input|output)
7256          * @param mixed $parameters parameter value(s)
7257          * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
7258          * @access public
7259          * @deprecated
7260          */
7261         function serializeParameters($operation, $direction, $parameters)
7262         {
7263                 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
7264                 $this->appendDebug('parameters=' . $this->varDump($parameters));
7265
7266                 if ($direction != 'input' && $direction != 'output') {
7267                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
7268                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
7269                         return false;
7270                 }
7271                 if (!$opData = $this->getOperationData($operation)) {
7272                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
7273                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
7274                         return false;
7275                 }
7276                 $this->debug('opData:');
7277                 $this->appendDebug($this->varDump($opData));
7278
7279                 // Get encoding style for output and set to current
7280                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7281                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
7282                         $encodingStyle = $opData['output']['encodingStyle'];
7283                         $enc_style = $encodingStyle;
7284                 }
7285
7286                 // set input params
7287                 $xml = '';
7288                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
7289
7290                         $use = $opData[$direction]['use'];
7291                         $this->debug("use=$use");
7292                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
7293                         if (is_array($parameters)) {
7294                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
7295                                 $this->debug('have ' . $parametersArrayType . ' parameters');
7296                                 foreach($opData[$direction]['parts'] as $name => $type) {
7297                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
7298                                         // Track encoding style
7299                                         if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
7300                                                 $encodingStyle = $opData[$direction]['encodingStyle'];
7301                                                 $enc_style = $encodingStyle;
7302                                         } else {
7303                                                 $enc_style = false;
7304                                         }
7305                                         // NOTE: add error handling here
7306                                         // if serializeType returns false, then catch global error and fault
7307                                         if ($parametersArrayType == 'arraySimple') {
7308                                                 $p = array_shift($parameters);
7309                                                 $this->debug('calling serializeType w/indexed param');
7310                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
7311                                         } elseif (isset($parameters[$name])) {
7312                                                 $this->debug('calling serializeType w/named param');
7313                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
7314                                         } else {
7315                                                 // TODO: only send nillable
7316                                                 $this->debug('calling serializeType w/null param');
7317                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
7318                                         }
7319                                 }
7320                         } else {
7321                                 $this->debug('no parameters passed.');
7322                         }
7323                 }
7324                 $this->debug("serializeParameters returning: $xml");
7325                 return $xml;
7326         }
7327
7328         /**
7329          * serializes a PHP value according a given type definition
7330          *
7331          * @param string $name name of value (part or element)
7332          * @param string $type XML schema type of value (type or element)
7333          * @param mixed $value a native PHP value (parameter value)
7334          * @param string $use use for part (encoded|literal)
7335          * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
7336          * @param boolean $unqualified a kludge for what should be XML namespace form handling
7337          * @return string value serialized as an XML string
7338          * @access private
7339          */
7340         function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
7341         {
7342                 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
7343                 $this->appendDebug("value=" . $this->varDump($value));
7344                 if($use == 'encoded' && $encodingStyle) {
7345                         $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
7346                 }
7347
7348                 // if a soapval has been supplied, let its type override the WSDL
7349         if (is_object($value) && get_class($value) == 'soapval') {
7350                 if ($value->type_ns) {
7351                         $type = $value->type_ns . ':' . $value->type;
7352                         $forceType = true;
7353                         $this->debug("in serializeType: soapval overrides type to $type");
7354                 } elseif ($value->type) {
7355                         $type = $value->type;
7356                         $forceType = true;
7357                         $this->debug("in serializeType: soapval overrides type to $type");
7358                 } else {
7359                         $forceType = false;
7360                         $this->debug("in serializeType: soapval does not override type");
7361                 }
7362                 $attrs = $value->attributes;
7363                 $value = $value->value;
7364                 $this->debug("in serializeType: soapval overrides value to $value");
7365                 if ($attrs) {
7366                         if (!is_array($value)) {
7367                                 $value['!'] = $value;
7368                         }
7369                         foreach ($attrs as $n => $v) {
7370                                 $value['!' . $n] = $v;
7371                         }
7372                         $this->debug("in serializeType: soapval provides attributes");
7373                     }
7374         } else {
7375                 $forceType = false;
7376         }
7377
7378                 $xml = '';
7379                 if (strpos($type, ':')) {
7380                         $uqType = substr($type, strrpos($type, ':') + 1);
7381                         $ns = substr($type, 0, strrpos($type, ':'));
7382                         $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
7383                         if ($this->getNamespaceFromPrefix($ns)) {
7384                                 $ns = $this->getNamespaceFromPrefix($ns);
7385                                 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
7386                         }
7387
7388                         if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
7389                                 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
7390                                 if ($unqualified && $use == 'literal') {
7391                                         $elementNS = " xmlns=\"\"";
7392                                 } else {
7393                                         $elementNS = '';
7394                                 }
7395                                 if (is_null($value)) {
7396                                         if ($use == 'literal') {
7397                                                 // TODO: depends on minOccurs
7398                                                 $xml = "<$name$elementNS/>";
7399                                         } else {
7400                                                 // TODO: depends on nillable, which should be checked before calling this method
7401                                                 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
7402                                         }
7403                                         $this->debug("in serializeType: returning: $xml");
7404                                         return $xml;
7405                                 }
7406                                 if ($uqType == 'Array') {
7407                                         // JBoss/Axis does this sometimes
7408                                         return $this->serialize_val($value, $name, false, false, false, false, $use);
7409                                 }
7410                         if ($uqType == 'boolean') {
7411                                 if ((is_string($value) && $value == 'false') || (! $value)) {
7412                                                 $value = 'false';
7413                                         } else {
7414                                                 $value = 'true';
7415                                         }
7416                                 }
7417                                 if ($uqType == 'string' && gettype($value) == 'string') {
7418                                         $value = $this->expandEntities($value);
7419                                 }
7420                                 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
7421                                         $value = sprintf("%.0lf", $value);
7422                                 }
7423                                 // it's a scalar
7424                                 // TODO: what about null/nil values?
7425                                 // check type isn't a custom type extending xmlschema namespace
7426                                 if (!$this->getTypeDef($uqType, $ns)) {
7427                                         if ($use == 'literal') {
7428                                                 if ($forceType) {
7429                                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
7430                                                 } else {
7431                                                         $xml = "<$name$elementNS>$value</$name>";
7432                                                 }
7433                                         } else {
7434                                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
7435                                         }
7436                                         $this->debug("in serializeType: returning: $xml");
7437                                         return $xml;
7438                                 }
7439                                 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
7440                         } else if ($ns == 'http://xml.apache.org/xml-soap') {
7441                                 $this->debug('in serializeType: appears to be Apache SOAP type');
7442                                 if ($uqType == 'Map') {
7443                                         $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
7444                                         if (! $tt_prefix) {
7445                                                 $this->debug('in serializeType: Add namespace for Apache SOAP type');
7446                                                 $tt_prefix = 'ns' . rand(1000, 9999);
7447                                                 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
7448                                                 // force this to be added to usedNamespaces
7449                                                 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
7450                                         }
7451                                         $contents = '';
7452                                         foreach($value as $k => $v) {
7453                                                 $this->debug("serializing map element: key $k, value $v");
7454                                                 $contents .= '<item>';
7455                                                 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
7456                                                 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
7457                                                 $contents .= '</item>';
7458                                         }
7459                                         if ($use == 'literal') {
7460                                                 if ($forceType) {
7461                                                         $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
7462                                                 } else {
7463                                                         $xml = "<$name>$contents</$name>";
7464                                                 }
7465                                         } else {
7466                                                 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
7467                                         }
7468                                         $this->debug("in serializeType: returning: $xml");
7469                                         return $xml;
7470                                 }
7471                                 $this->debug('in serializeType: Apache SOAP type, but only support Map');
7472                         }
7473                 } else {
7474                         // TODO: should the type be compared to types in XSD, and the namespace
7475                         // set to XSD if the type matches?
7476                         $this->debug("in serializeType: No namespace for type $type");
7477                         $ns = '';
7478                         $uqType = $type;
7479                 }
7480                 if(!$typeDef = $this->getTypeDef($uqType, $ns)){
7481                         $this->setError("$type ($uqType) is not a supported type.");
7482                         $this->debug("in serializeType: $type ($uqType) is not a supported type.");
7483                         return false;
7484                 } else {
7485                         $this->debug("in serializeType: found typeDef");
7486                         $this->appendDebug('typeDef=' . $this->varDump($typeDef));
7487                         if (substr($uqType, -1) == '^') {
7488                                 $uqType = substr($uqType, 0, -1);
7489                         }
7490                 }
7491                 if (!isset($typeDef['phpType'])) {
7492                         $this->setError("$type ($uqType) has no phpType.");
7493                         $this->debug("in serializeType: $type ($uqType) has no phpType.");
7494                         return false;
7495                 }
7496                 $phpType = $typeDef['phpType'];
7497                 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
7498                 // if php type == struct, map value to the <all> element names
7499                 if ($phpType == 'struct') {
7500                         if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
7501                                 $elementName = $uqType;
7502                                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
7503                                         $elementNS = " xmlns=\"$ns\"";
7504                                 } else {
7505                                         $elementNS = " xmlns=\"\"";
7506                                 }
7507                         } else {
7508                                 $elementName = $name;
7509                                 if ($unqualified) {
7510                                         $elementNS = " xmlns=\"\"";
7511                                 } else {
7512                                         $elementNS = '';
7513                                 }
7514                         }
7515                         if (is_null($value)) {
7516                                 if ($use == 'literal') {
7517                                         // TODO: depends on minOccurs and nillable
7518                                         $xml = "<$elementName$elementNS/>";
7519                                 } else {
7520                                         $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
7521                                 }
7522                                 $this->debug("in serializeType: returning: $xml");
7523                                 return $xml;
7524                         }
7525                         if (is_object($value)) {
7526                                 $value = get_object_vars($value);
7527                         }
7528                         if (is_array($value)) {
7529                                 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
7530                                 if ($use == 'literal') {
7531                                         if ($forceType) {
7532                                                 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
7533                                         } else {
7534                                                 $xml = "<$elementName$elementNS$elementAttrs>";
7535                                         }
7536                                 } else {
7537                                         $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
7538                                 }
7539
7540                                 if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') {
7541                                         if (isset($value['!'])) {
7542                                                 $xml .= $value['!'];
7543                                                 $this->debug("in serializeType: serialized simpleContent for type $type");
7544                                         } else {
7545                                                 $this->debug("in serializeType: no simpleContent to serialize for type $type");
7546                                         }
7547                                 } else {
7548                                         // complexContent
7549                                         $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
7550                                 }
7551                                 $xml .= "</$elementName>";
7552                         } else {
7553                                 $this->debug("in serializeType: phpType is struct, but value is not an array");
7554                                 $this->setError("phpType is struct, but value is not an array: see debug output for details");
7555                                 $xml = '';
7556                         }
7557                 } elseif ($phpType == 'array') {
7558                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
7559                                 $elementNS = " xmlns=\"$ns\"";
7560                         } else {
7561                                 if ($unqualified) {
7562                                         $elementNS = " xmlns=\"\"";
7563                                 } else {
7564                                         $elementNS = '';
7565                                 }
7566                         }
7567                         if (is_null($value)) {
7568                                 if ($use == 'literal') {
7569                                         // TODO: depends on minOccurs
7570                                         $xml = "<$name$elementNS/>";
7571                                 } else {
7572                                         $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
7573                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
7574                                                 ":Array\" " .
7575                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
7576                                                 ':arrayType="' .
7577                                                 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
7578                                                 ':' .
7579                                                 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
7580                                 }
7581                                 $this->debug("in serializeType: returning: $xml");
7582                                 return $xml;
7583                         }
7584                         if (isset($typeDef['multidimensional'])) {
7585                                 $nv = array();
7586                                 foreach($value as $v) {
7587                                         $cols = ',' . sizeof($v);
7588                                         $nv = array_merge($nv, $v);
7589                                 }
7590                                 $value = $nv;
7591                         } else {
7592                                 $cols = '';
7593                         }
7594                         if (is_array($value) && sizeof($value) >= 1) {
7595                                 $rows = sizeof($value);
7596                                 $contents = '';
7597                                 foreach($value as $k => $v) {
7598                                         $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
7599                                         //if (strpos($typeDef['arrayType'], ':') ) {
7600                                         if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
7601                                             $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
7602                                         } else {
7603                                             $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
7604                                         }
7605                                 }
7606                         } else {
7607                                 $rows = 0;
7608                                 $contents = null;
7609                         }
7610                         // TODO: for now, an empty value will be serialized as a zero element
7611                         // array.  Revisit this when coding the handling of null/nil values.
7612                         if ($use == 'literal') {
7613                                 $xml = "<$name$elementNS>"
7614                                         .$contents
7615                                         ."</$name>";
7616                         } else {
7617                                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
7618                                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
7619                                         .':arrayType="'
7620                                         .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
7621                                         .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
7622                                         .$contents
7623                                         ."</$name>";
7624                         }
7625                 } elseif ($phpType == 'scalar') {
7626                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
7627                                 $elementNS = " xmlns=\"$ns\"";
7628                         } else {
7629                                 if ($unqualified) {
7630                                         $elementNS = " xmlns=\"\"";
7631                                 } else {
7632                                         $elementNS = '';
7633                                 }
7634                         }
7635                         if ($use == 'literal') {
7636                                 if ($forceType) {
7637                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
7638                                 } else {
7639                                         $xml = "<$name$elementNS>$value</$name>";
7640                                 }
7641                         } else {
7642                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
7643                         }
7644                 }
7645                 $this->debug("in serializeType: returning: $xml");
7646                 return $xml;
7647         }
7648
7649         /**
7650          * serializes the attributes for a complexType
7651          *
7652          * @param array $typeDef our internal representation of an XML schema type (or element)
7653          * @param mixed $value a native PHP value (parameter value)
7654          * @param string $ns the namespace of the type
7655          * @param string $uqType the local part of the type
7656          * @return string value serialized as an XML string
7657          * @access private
7658          */
7659         function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
7660                 $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
7661                 $xml = '';
7662                 if (isset($typeDef['extensionBase'])) {
7663                         $nsx = $this->getPrefix($typeDef['extensionBase']);
7664                         $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
7665                         if ($this->getNamespaceFromPrefix($nsx)) {
7666                                 $nsx = $this->getNamespaceFromPrefix($nsx);
7667                         }
7668                         if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
7669                                 $this->debug("serialize attributes for extension base $nsx:$uqTypex");
7670                                 $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
7671                         } else {
7672                                 $this->debug("extension base $nsx:$uqTypex is not a supported type");
7673                         }
7674                 }
7675                 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
7676                         $this->debug("serialize attributes for XML Schema type $ns:$uqType");
7677                         if (is_array($value)) {
7678                                 $xvalue = $value;
7679                         } elseif (is_object($value)) {
7680                                 $xvalue = get_object_vars($value);
7681                         } else {
7682                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
7683                                 $xvalue = array();
7684                         }
7685                         foreach ($typeDef['attrs'] as $aName => $attrs) {
7686                                 if (isset($xvalue['!' . $aName])) {
7687                                         $xname = '!' . $aName;
7688                                         $this->debug("value provided for attribute $aName with key $xname");
7689                                 } elseif (isset($xvalue[$aName])) {
7690                                         $xname = $aName;
7691                                         $this->debug("value provided for attribute $aName with key $xname");
7692                                 } elseif (isset($attrs['default'])) {
7693                                         $xname = '!' . $aName;
7694                                         $xvalue[$xname] = $attrs['default'];
7695                                         $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
7696                                 } else {
7697                                         $xname = '';
7698                                         $this->debug("no value provided for attribute $aName");
7699                                 }
7700                                 if ($xname) {
7701                                         $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
7702                                 }
7703                         }
7704                 } else {
7705                         $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
7706                 }
7707                 return $xml;
7708         }
7709
7710         /**
7711          * serializes the elements for a complexType
7712          *
7713          * @param array $typeDef our internal representation of an XML schema type (or element)
7714          * @param mixed $value a native PHP value (parameter value)
7715          * @param string $ns the namespace of the type
7716          * @param string $uqType the local part of the type
7717          * @param string $use use for part (encoded|literal)
7718          * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
7719          * @return string value serialized as an XML string
7720          * @access private
7721          */
7722         function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
7723                 $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
7724                 $xml = '';
7725                 if (isset($typeDef['extensionBase'])) {
7726                         $nsx = $this->getPrefix($typeDef['extensionBase']);
7727                         $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
7728                         if ($this->getNamespaceFromPrefix($nsx)) {
7729                                 $nsx = $this->getNamespaceFromPrefix($nsx);
7730                         }
7731                         if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
7732                                 $this->debug("serialize elements for extension base $nsx:$uqTypex");
7733                                 $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
7734                         } else {
7735                                 $this->debug("extension base $nsx:$uqTypex is not a supported type");
7736                         }
7737                 }
7738                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
7739                         $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
7740                         if (is_array($value)) {
7741                                 $xvalue = $value;
7742                         } elseif (is_object($value)) {
7743                                 $xvalue = get_object_vars($value);
7744                         } else {
7745                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
7746                                 $xvalue = array();
7747                         }
7748                         // toggle whether all elements are present - ideally should validate against schema
7749                         if (count($typeDef['elements']) != count($xvalue)){
7750                                 $optionals = true;
7751                         }
7752                         foreach ($typeDef['elements'] as $eName => $attrs) {
7753                                 if (!isset($xvalue[$eName])) {
7754                                         if (isset($attrs['default'])) {
7755                                                 $xvalue[$eName] = $attrs['default'];
7756                                                 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
7757                                         }
7758                                 }
7759                                 // if user took advantage of a minOccurs=0, then only serialize named parameters
7760                                 if (isset($optionals)
7761                                     && (!isset($xvalue[$eName]))
7762                                         && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
7763                                         ){
7764                                         if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
7765                                                 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
7766                                         }
7767                                         // do nothing
7768                                         $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
7769                                 } else {
7770                                         // get value
7771                                         if (isset($xvalue[$eName])) {
7772                                             $v = $xvalue[$eName];
7773                                         } else {
7774                                             $v = null;
7775                                         }
7776                                         if (isset($attrs['form'])) {
7777                                                 $unqualified = ($attrs['form'] == 'unqualified');
7778                                         } else {
7779                                                 $unqualified = false;
7780                                         }
7781                                         if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
7782                                                 $vv = $v;
7783                                                 foreach ($vv as $k => $v) {
7784                                                         if (isset($attrs['type']) || isset($attrs['ref'])) {
7785                                                                 // serialize schema-defined type
7786                                                             $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
7787                                                         } else {
7788                                                                 // serialize generic type (can this ever really happen?)
7789                                                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
7790                                                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
7791                                                         }
7792                                                 }
7793                                         } else {
7794                                                 if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') {
7795                                                         // do nothing
7796                                                 } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') {
7797                                                         // TODO: serialize a nil correctly, but for now serialize schema-defined type
7798                                                     $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
7799                                                 } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
7800                                                         // serialize schema-defined type
7801                                                     $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
7802                                                 } else {
7803                                                         // serialize generic type (can this ever really happen?)
7804                                                     $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
7805                                                     $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
7806                                                 }
7807                                         }
7808                                 }
7809                         }
7810                 } else {
7811                         $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
7812                 }
7813                 return $xml;
7814         }
7815
7816         /**
7817         * adds an XML Schema complex type to the WSDL types
7818         *
7819         * @param string $name
7820         * @param string $typeClass (complexType|simpleType|attribute)
7821         * @param string $phpType currently supported are array and struct (php assoc array)
7822         * @param string $compositor (all|sequence|choice)
7823         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
7824         * @param array $elements e.g. array ( name => array(name=>'',type=>'') )
7825         * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
7826         * @param string $arrayType as namespace:name (xsd:string)
7827         * @see nusoap_xmlschema
7828         * @access public
7829         */
7830         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
7831                 if (count($elements) > 0) {
7832                         $eElements = array();
7833                 foreach($elements as $n => $e){
7834                     // expand each element
7835                     $ee = array();
7836                     foreach ($e as $k => $v) {
7837                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
7838                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
7839                             $ee[$k] = $v;
7840                         }
7841                         $eElements[$n] = $ee;
7842                 }
7843                 $elements = $eElements;
7844                 }
7845
7846                 if (count($attrs) > 0) {
7847                 foreach($attrs as $n => $a){
7848                     // expand each attribute
7849                     foreach ($a as $k => $v) {
7850                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
7851                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
7852                             $aa[$k] = $v;
7853                         }
7854                         $eAttrs[$n] = $aa;
7855                 }
7856                 $attrs = $eAttrs;
7857                 }
7858
7859                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
7860                 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
7861
7862                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
7863                 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
7864         }
7865
7866         /**
7867         * adds an XML Schema simple type to the WSDL types
7868         *
7869         * @param string $name
7870         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
7871         * @param string $typeClass (should always be simpleType)
7872         * @param string $phpType (should always be scalar)
7873         * @param array $enumeration array of values
7874         * @see nusoap_xmlschema
7875         * @access public
7876         */
7877         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
7878                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
7879
7880                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
7881                 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
7882         }
7883
7884         /**
7885         * adds an element to the WSDL types
7886         *
7887         * @param array $attrs attributes that must include name and type
7888         * @see nusoap_xmlschema
7889         * @access public
7890         */
7891         function addElement($attrs) {
7892                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
7893                 $this->schemas[$typens][0]->addElement($attrs);
7894         }
7895
7896         /**
7897         * register an operation with the server
7898         *
7899         * @param string $name operation (method) name
7900         * @param array $in assoc array of input values: key = param name, value = param type
7901         * @param array $out assoc array of output values: key = param name, value = param type
7902         * @param string $namespace optional The namespace for the operation
7903         * @param string $soapaction optional The soapaction for the operation
7904         * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically
7905         * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
7906         * @param string $documentation optional The description to include in the WSDL
7907         * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
7908         * @access public
7909         */
7910         function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
7911                 if ($use == 'encoded' && $encodingStyle == '') {
7912                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7913                 }
7914
7915                 if ($style == 'document') {
7916                         $elements = array();
7917                         foreach ($in as $n => $t) {
7918                                 $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
7919                         }
7920                         $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
7921                         $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
7922                         $in = array('parameters' => 'tns:' . $name . '^');
7923
7924                         $elements = array();
7925                         foreach ($out as $n => $t) {
7926                                 $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
7927                         }
7928                         $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
7929                         $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
7930                         $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
7931                 }
7932
7933                 // get binding
7934                 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
7935                 array(
7936                 'name' => $name,
7937                 'binding' => $this->serviceName . 'Binding',
7938                 'endpoint' => $this->endpoint,
7939                 'soapAction' => $soapaction,
7940                 'style' => $style,
7941                 'input' => array(
7942                         'use' => $use,
7943                         'namespace' => $namespace,
7944                         'encodingStyle' => $encodingStyle,
7945                         'message' => $name . 'Request',
7946                         'parts' => $in),
7947                 'output' => array(
7948                         'use' => $use,
7949                         'namespace' => $namespace,
7950                         'encodingStyle' => $encodingStyle,
7951                         'message' => $name . 'Response',
7952                         'parts' => $out),
7953                 'namespace' => $namespace,
7954                 'transport' => 'http://schemas.xmlsoap.org/soap/http',
7955                 'documentation' => $documentation);
7956                 // add portTypes
7957                 // add messages
7958                 if($in)
7959                 {
7960                         foreach($in as $pName => $pType)
7961                         {
7962                                 if(strpos($pType,':')) {
7963                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
7964                                 }
7965                                 $this->messages[$name.'Request'][$pName] = $pType;
7966                         }
7967                 } else {
7968             $this->messages[$name.'Request']= '0';
7969         }
7970                 if($out)
7971                 {
7972                         foreach($out as $pName => $pType)
7973                         {
7974                                 if(strpos($pType,':')) {
7975                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
7976                                 }
7977                                 $this->messages[$name.'Response'][$pName] = $pType;
7978                         }
7979                 } else {
7980             $this->messages[$name.'Response']= '0';
7981         }
7982                 return true;
7983         }
7984 }
7985 ?><?php
7986
7987 /*
7988
7989 Modification information for LGPL compliance
7990
7991 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
7992     bug 40066
7993
7994 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
7995     Merging with maint_6_0_1 (svn merge -r 58250:58342)
7996
7997 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
7998     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
7999
8000 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
8001     fix SOAP calls with no parameters
8002
8003 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
8004
8005 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
8006
8007 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
8008
8009 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
8010
8011 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
8012
8013 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
8014
8015 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
8016
8017 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
8018 - Changing all ereg function to either preg or simple string based ones
8019 - No more references to magic quotes.
8020 - Change all the session_unregister() functions to just unset() the correct session variable instead.
8021
8022 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
8023
8024 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
8025
8026 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
8027
8028 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
8029
8030 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
8031
8032 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
8033
8034 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
8035
8036 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
8037
8038 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
8039 Touched:
8040 - data/SugarBean.php
8041 - include/domit/php_http_client_generic.php
8042 - include/domit/php_http_connector.php
8043 - include/domit/testing_domit.php
8044 - include/domit/xml_domit_getelementsbypath.php
8045 - include/domit/xml_domit_lite_parser.php
8046 - include/domit/xml_domit_nodemaps.php
8047 - include/domit/xml_domit_parser.php
8048 - include/domit/xml_domit_shared.php
8049 - include/generic/SugarWidgets/SugarWidgetField.php
8050 - include/generic/SugarWidgets/SugarWidgetReportField.php
8051 - include/ListView/ProcessView.php
8052 - include/nusoap/class.soapclient.php
8053 - include/nusoap/nusoap.php
8054 - include/nusoap/nusoapmime.php
8055 - include/Pear/HTML_Safe/Safe.php
8056 - include/Pear/XML_HTMLSax3/HTMLSax3.php
8057 - modules/Administration/RebuildWorkFlow.php
8058 - modules/Expressions/RelateSelector.php
8059 - modules/Reports/templates/templates_reports.php
8060 - modules/WorkFlow/Delete.php
8061 - modules/WorkFlow/Save.php
8062 - modules/WorkFlow/SaveSequence.php
8063 - modules/WorkFlow/WorkFlow.php
8064 - modules/WorkFlowActionShells/CreateStep1.php
8065 - modules/WorkFlowActionShells/CreateStep2.php
8066 - modules/WorkFlowActionShells/Save.php
8067 - modules/WorkFlowActionShells/WorkFlowActionShell.php
8068 - modules/WorkFlowAlerts/Save.php
8069 - modules/WorkFlowAlerts/WorkFlowAlert.php
8070 - modules/WorkFlowAlertShells/DetailView.php
8071 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
8072 - modules/WorkFlowTriggerShells/CreateStep1.php
8073 - modules/WorkFlowTriggerShells/CreateStepFilter.php
8074 - modules/WorkFlowTriggerShells/SaveFilter.php
8075 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
8076 - soap/SoapHelperFunctions.php
8077 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
8078 - test/simpletest/browser.php
8079 - test/simpletest/default_reporter.php
8080 - test/simpletest/detached.php
8081 - test/simpletest/eclipse.php
8082 - test/simpletest/expectation.php
8083 - test/simpletest/extensions/pear_test_case.php
8084 - test/simpletest/form.php
8085 - test/simpletest/http.php
8086 - test/simpletest/mock_objects.php
8087 - test/simpletest/page.php
8088 - test/simpletest/parser.php
8089 - test/simpletest/remote.php
8090 - test/simpletest/shell_tester.php
8091 - test/simpletest/simple_test.php
8092 - test/simpletest/simpletest.php
8093 - test/simpletest/test/acceptance_test.php
8094 - test/simpletest/test/adapter_test.php
8095 - test/simpletest/test/authentication_test.php
8096 - test/simpletest/test/browser_test.php
8097 - test/simpletest/test/collector_test.php
8098 - test/simpletest/test/compatibility_test.php
8099 - test/simpletest/test/detached_test.php
8100 - test/simpletest/test/eclipse_test.php
8101 - test/simpletest/test/encoding_test.php
8102 - test/simpletest/test/errors_test.php
8103 - test/simpletest/test/expectation_test.php
8104 - test/simpletest/test/form_test.php
8105 - test/simpletest/test/frames_test.php
8106 - test/simpletest/test/http_test.php
8107 - test/simpletest/test/live_test.php
8108 - test/simpletest/test/mock_objects_test.php
8109 - test/simpletest/test/page_test.php
8110 - test/simpletest/test/parse_error_test.php
8111 - test/simpletest/test/parser_test.php
8112 - test/simpletest/test/remote_test.php
8113 - test/simpletest/test/shell_test.php
8114 - test/simpletest/test/shell_tester_test.php
8115 - test/simpletest/test/simpletest_test.php
8116 - test/simpletest/test/site/page_request.php
8117 - test/simpletest/test/tag_test.php
8118 - test/simpletest/test/unit_tester_test.php
8119 - test/simpletest/test/user_agent_test.php
8120 - test/simpletest/test/visual_test.php
8121 - test/simpletest/test/xml_test.php
8122 - test/simpletest/test_case.php
8123 - test/simpletest/ui/array_reporter/test.php
8124 - test/simpletest/ui/recorder/test.php
8125 - test/simpletest/unit_tester.php
8126 - test/simpletest/url.php
8127 - test/simpletest/user_agent.php
8128 - test/simpletest/web_tester.php
8129 - test/spikephpcoverage/src/PEAR.php
8130 - test/spikephpcoverage/src/util/Utility.php
8131 - test/spikephpcoverage/src/XML/Parser.php
8132 - test/spikephpcoverage/src/XML/Parser/Simple.php
8133 - test/test_utilities/SugarTest_SimpleBrowser.php
8134
8135 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
8136
8137 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
8138
8139 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
8140
8141 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
8142
8143 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
8144
8145 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
8146
8147 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
8148
8149 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
8150
8151 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
8152
8153 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
8154
8155 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
8156
8157 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
8158
8159 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
8160
8161 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
8162
8163 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
8164
8165 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
8166
8167 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
8168
8169 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
8170
8171 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
8172
8173 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
8174
8175 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
8176
8177 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
8178
8179 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
8180
8181 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
8182
8183
8184 */
8185
8186
8187
8188
8189
8190 /**
8191 *
8192 * nusoap_parser class parses SOAP XML messages into native PHP values
8193 *
8194 * @author   Dietrich Ayala <dietrich@ganx4.com>
8195 * @author   Scott Nichol <snichol@users.sourceforge.net>
8196
8197 * @access   public
8198 */
8199 class nusoap_parser extends nusoap_base {
8200
8201         var $xml = '';
8202         var $xml_encoding = '';
8203         var $method = '';
8204         var $root_struct = '';
8205         var $root_struct_name = '';
8206         var $root_struct_namespace = '';
8207         var $root_header = '';
8208     var $document = '';                 // incoming SOAP body (text)
8209         // determines where in the message we are (envelope,header,body,method)
8210         var $status = '';
8211         var $position = 0;
8212         var $depth = 0;
8213         var $default_namespace = '';
8214         var $namespaces = array();
8215         var $message = array();
8216     var $parent = '';
8217         var $fault = false;
8218         var $fault_code = '';
8219         var $fault_str = '';
8220         var $fault_detail = '';
8221         var $depth_array = array();
8222         var $debug_flag = true;
8223         var $soapresponse = NULL;       // parsed SOAP Body
8224         var $soapheader = NULL;         // parsed SOAP Header
8225         var $responseHeaders = '';      // incoming SOAP headers (text)
8226         var $body_position = 0;
8227         // for multiref parsing:
8228         // array of id => pos
8229         var $ids = array();
8230         // array of id => hrefs => pos
8231         var $multirefs = array();
8232         // toggle for auto-decoding element content
8233         var $decode_utf8 = false;
8234
8235         /**
8236         * constructor that actually does the parsing
8237         *
8238         * @param    string $xml SOAP message
8239         * @param    string $encoding character encoding scheme of message
8240         * @param    string $method method for which XML is parsed (unused?)
8241         * @param    string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
8242         * @access   public
8243         */
8244         function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
8245                 parent::nusoap_base();
8246                 $this->xml = $xml;
8247                 $this->xml_encoding = $encoding;
8248                 $this->method = $method;
8249                 $this->decode_utf8 = $decode_utf8;
8250
8251                 // Check whether content has been read.
8252                 if(!empty($xml)){
8253                         // Check XML encoding
8254                         $pos_xml = strpos($xml, '<?xml');
8255                         if ($pos_xml !== FALSE) {
8256                                 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
8257                                 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
8258                                         $xml_encoding = $res[1];
8259                                         if (strtoupper($xml_encoding) != $encoding) {
8260                                                 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
8261                                                 $this->debug($err);
8262                                                 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
8263                                                         $this->setError($err);
8264                                                         return;
8265                                                 }
8266                                                 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
8267                                         } else {
8268                                                 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
8269                                         }
8270                                 } else {
8271                                         $this->debug('No encoding specified in XML declaration');
8272                                 }
8273                         } else {
8274                                 $this->debug('No XML declaration');
8275                         }
8276                         $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
8277                         // Create an XML parser - why not xml_parser_create_ns?
8278                         $this->parser = xml_parser_create($this->xml_encoding);
8279                         // Set the options for parsing the XML data.
8280                         //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
8281                         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
8282                         xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
8283                         // Set the object for the parser.
8284                         xml_set_object($this->parser, $this);
8285                         // Set the element handlers for the parser.
8286                         xml_set_element_handler($this->parser, 'start_element','end_element');
8287                         xml_set_character_data_handler($this->parser,'character_data');
8288
8289                         // Parse the XML file.
8290                         if(!xml_parse($this->parser,$xml,true)){
8291                             // Display an error message.
8292                             $err = sprintf('XML error parsing SOAP payload on line %d: %s',
8293                             xml_get_current_line_number($this->parser),
8294                             xml_error_string(xml_get_error_code($this->parser)));
8295                                 $this->debug($err);
8296                                 $this->debug("XML payload:\n" . $xml);
8297                                 $this->setError($err);
8298                         } else {
8299                                 $this->debug('in nusoap_parser ctor, message:');
8300                                 $this->appendDebug($this->varDump($this->message));
8301                                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
8302                                 // get final value
8303                                 $this->soapresponse = $this->message[$this->root_struct]['result'];
8304                                 // get header value
8305                                 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
8306                                         $this->soapheader = $this->message[$this->root_header]['result'];
8307                                 }
8308                                 // resolve hrefs/ids
8309                                 if(sizeof($this->multirefs) > 0){
8310                                         foreach($this->multirefs as $id => $hrefs){
8311                                                 $this->debug('resolving multirefs for id: '.$id);
8312                                                 $idVal = $this->buildVal($this->ids[$id]);
8313                                                 if (is_array($idVal) && isset($idVal['!id'])) {
8314                                                         unset($idVal['!id']);
8315                                                 }
8316                                                 foreach($hrefs as $refPos => $ref){
8317                                                         $this->debug('resolving href at pos '.$refPos);
8318                                                         $this->multirefs[$id][$refPos] = $idVal;
8319                                                 }
8320                                         }
8321                                 }
8322                         }
8323                         xml_parser_free($this->parser);
8324                 } else {
8325                         $this->debug('xml was empty, didn\'t parse!');
8326                         $this->setError('xml was empty, didn\'t parse!');
8327                 }
8328         }
8329
8330         /**
8331         * start-element handler
8332         *
8333         * @param    resource $parser XML parser object
8334         * @param    string $name element name
8335         * @param    array $attrs associative array of attributes
8336         * @access   private
8337         */
8338         function start_element($parser, $name, $attrs) {
8339                 // position in a total number of elements, starting from 0
8340                 // update class level pos
8341                 $pos = $this->position++;
8342                 // and set mine
8343                 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
8344                 // depth = how many levels removed from root?
8345                 // set mine as current global depth and increment global depth value
8346                 $this->message[$pos]['depth'] = $this->depth++;
8347
8348                 // else add self as child to whoever the current parent is
8349                 if($pos != 0){
8350                         $this->message[$this->parent]['children'] .= '|'.$pos;
8351                 }
8352                 // set my parent
8353                 $this->message[$pos]['parent'] = $this->parent;
8354                 // set self as current parent
8355                 $this->parent = $pos;
8356                 // set self as current value for this depth
8357                 $this->depth_array[$this->depth] = $pos;
8358                 // get element prefix
8359                 if(strpos($name,':')){
8360                         // get ns prefix
8361                         $prefix = substr($name,0,strpos($name,':'));
8362                         // get unqualified name
8363                         $name = substr(strstr($name,':'),1);
8364                 }
8365                 // set status
8366                 if ($name == 'Envelope' && $this->status == '') {
8367                         $this->status = 'envelope';
8368                 } elseif ($name == 'Header' && $this->status == 'envelope') {
8369                         $this->root_header = $pos;
8370                         $this->status = 'header';
8371                 } elseif ($name == 'Body' && $this->status == 'envelope'){
8372                         $this->status = 'body';
8373                         $this->body_position = $pos;
8374                 // set method
8375                 } elseif($this->status == 'body' && $pos == ($this->body_position+1)) {
8376                         $this->status = 'method';
8377                         $this->root_struct_name = $name;
8378                         $this->root_struct = $pos;
8379                         $this->message[$pos]['type'] = 'struct';
8380                         $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
8381                 }
8382                 // set my status
8383                 $this->message[$pos]['status'] = $this->status;
8384                 // set name
8385                 $this->message[$pos]['name'] = htmlspecialchars($name);
8386                 // set attrs
8387                 $this->message[$pos]['attrs'] = $attrs;
8388
8389                 // loop through atts, logging ns and type declarations
8390         $attstr = '';
8391                 foreach($attrs as $key => $value){
8392                 $key_prefix = $this->getPrefix($key);
8393                         $key_localpart = $this->getLocalPart($key);
8394                         // if ns declarations, add to class level array of valid namespaces
8395             if($key_prefix == 'xmlns'){
8396                                 if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){
8397                                         $this->XMLSchemaVersion = $value;
8398                                         $this->namespaces['xsd'] = $this->XMLSchemaVersion;
8399                                         $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
8400                                 }
8401                 $this->namespaces[$key_localpart] = $value;
8402                                 // set method namespace
8403                                 if($name == $this->root_struct_name){
8404                                         $this->methodNamespace = $value;
8405                                 }
8406                         // if it's a type declaration, set type
8407         } elseif($key_localpart == 'type'){
8408                         if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
8409                                 // do nothing: already processed arrayType
8410                         } else {
8411                         $value_prefix = $this->getPrefix($value);
8412                         $value_localpart = $this->getLocalPart($value);
8413                                         $this->message[$pos]['type'] = $value_localpart;
8414                                         $this->message[$pos]['typePrefix'] = $value_prefix;
8415                         if(isset($this->namespaces[$value_prefix])){
8416                                 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
8417                         } else if(isset($attrs['xmlns:'.$value_prefix])) {
8418                                                 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
8419                         }
8420                                         // should do something here with the namespace of specified type?
8421                                 }
8422                         } elseif($key_localpart == 'arrayType'){
8423                                 $this->message[$pos]['type'] = 'array';
8424                                 /* do arrayType ereg here
8425                                 [1]    arrayTypeValue    ::=    atype asize
8426                                 [2]    atype    ::=    QName rank*
8427                                 [3]    rank    ::=    '[' (',')* ']'
8428                                 [4]    asize    ::=    '[' length~ ']'
8429                                 [5]    length    ::=    nextDimension* Digit+
8430                                 [6]    nextDimension    ::=    Digit+ ','
8431                                 */
8432                                 $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
8433                                 if(preg_match($expr,$value,$regs)){
8434                                         $this->message[$pos]['typePrefix'] = $regs[1];
8435                                         $this->message[$pos]['arrayTypePrefix'] = $regs[1];
8436                         if (isset($this->namespaces[$regs[1]])) {
8437                                 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
8438                         } else if (isset($attrs['xmlns:'.$regs[1]])) {
8439                                                 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
8440                         }
8441                                         $this->message[$pos]['arrayType'] = $regs[2];
8442                                         $this->message[$pos]['arraySize'] = $regs[3];
8443                                         $this->message[$pos]['arrayCols'] = $regs[4];
8444                                 }
8445                         // specifies nil value (or not)
8446                         } elseif ($key_localpart == 'nil'){
8447                                 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
8448                         // some other attribute
8449                         } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
8450                                 $this->message[$pos]['xattrs']['!' . $key] = $value;
8451                         }
8452
8453                         if ($key == 'xmlns') {
8454                                 $this->default_namespace = $value;
8455                         }
8456                         // log id
8457                         if($key == 'id'){
8458                                 $this->ids[$value] = $pos;
8459                         }
8460                         // root
8461                         if($key_localpart == 'root' && $value == 1){
8462                                 $this->status = 'method';
8463                                 $this->root_struct_name = $name;
8464                                 $this->root_struct = $pos;
8465                                 $this->debug("found root struct $this->root_struct_name, pos $pos");
8466                         }
8467             // for doclit
8468             $attstr .= " $key=\"$value\"";
8469                 }
8470         // get namespace - must be done after namespace atts are processed
8471                 if(isset($prefix)){
8472                         $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
8473                         $this->default_namespace = $this->namespaces[$prefix];
8474                 } else {
8475                         $this->message[$pos]['namespace'] = $this->default_namespace;
8476                 }
8477         if($this->status == 'header'){
8478                 if ($this->root_header != $pos) {
8479                         $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
8480                 }
8481         } elseif($this->root_struct_name != ''){
8482                 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
8483         }
8484         }
8485
8486         /**
8487         * end-element handler
8488         *
8489         * @param    resource $parser XML parser object
8490         * @param    string $name element name
8491         * @access   private
8492         */
8493         function end_element($parser, $name) {
8494                 // position of current element is equal to the last value left in depth_array for my depth
8495                 $pos = $this->depth_array[$this->depth--];
8496
8497         // get element prefix
8498                 if(strpos($name,':')){
8499                         // get ns prefix
8500                         $prefix = substr($name,0,strpos($name,':'));
8501                         // get unqualified name
8502                         $name = substr(strstr($name,':'),1);
8503                 }
8504
8505                 // build to native type
8506                 if(isset($this->body_position) && $pos > $this->body_position){
8507                         // deal w/ multirefs
8508                         if(isset($this->message[$pos]['attrs']['href'])){
8509                                 // get id
8510                                 $id = substr($this->message[$pos]['attrs']['href'],1);
8511                                 // add placeholder to href array
8512                                 $this->multirefs[$id][$pos] = 'placeholder';
8513                                 // add set a reference to it as the result value
8514                                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
8515             // build complexType values
8516                         } elseif($this->message[$pos]['children'] != ''){
8517                                 // if result has already been generated (struct/array)
8518                                 if(!isset($this->message[$pos]['result'])){
8519                                         $this->message[$pos]['result'] = $this->buildVal($pos);
8520                                 }
8521                         // build complexType values of attributes and possibly simpleContent
8522                         } elseif (isset($this->message[$pos]['xattrs'])) {
8523                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
8524                                         $this->message[$pos]['xattrs']['!'] = null;
8525                                 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
8526                         if (isset($this->message[$pos]['type'])) {
8527                                                 $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
8528                                         } else {
8529                                                 $parent = $this->message[$pos]['parent'];
8530                                                 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8531                                                         $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8532                                                 } else {
8533                                                         $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
8534                                                 }
8535                                         }
8536                                 }
8537                                 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
8538                         // set value of simpleType (or nil complexType)
8539                         } else {
8540                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
8541                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
8542                                         $this->message[$pos]['xattrs']['!'] = null;
8543                                 } elseif (isset($this->message[$pos]['type'])) {
8544                                         $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
8545                                 } else {
8546                                         $parent = $this->message[$pos]['parent'];
8547                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8548                                                 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8549                                         } else {
8550                                                 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
8551                                         }
8552                                 }
8553
8554                                 /* add value to parent's result, if parent is struct/array
8555                                 $parent = $this->message[$pos]['parent'];
8556                                 if($this->message[$parent]['type'] != 'map'){
8557                                         if(strtolower($this->message[$parent]['type']) == 'array'){
8558                                                 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
8559                                         } else {
8560                                                 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
8561                                         }
8562                                 }
8563                                 */
8564                         }
8565                 }
8566
8567         // for doclit
8568         if($this->status == 'header'){
8569                 if ($this->root_header != $pos) {
8570                         $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
8571                 }
8572         } elseif($pos >= $this->root_struct){
8573                 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
8574         }
8575                 // switch status
8576                 if ($pos == $this->root_struct){
8577                         $this->status = 'body';
8578                         $this->root_struct_namespace = $this->message[$pos]['namespace'];
8579                 } elseif ($pos == $this->root_header) {
8580                         $this->status = 'envelope';
8581                 } elseif ($name == 'Body' && $this->status == 'body') {
8582                         $this->status = 'envelope';
8583                 } elseif ($name == 'Header' && $this->status == 'header') { // will never happen
8584                         $this->status = 'envelope';
8585                 } elseif ($name == 'Envelope' && $this->status == 'envelope') {
8586                         $this->status = '';
8587                 }
8588                 // set parent back to my parent
8589                 $this->parent = $this->message[$pos]['parent'];
8590         }
8591
8592         /**
8593         * element content handler
8594         *
8595         * @param    resource $parser XML parser object
8596         * @param    string $data element content
8597         * @access   private
8598         */
8599         function character_data($parser, $data){
8600                 $pos = $this->depth_array[$this->depth];
8601                 if ($this->xml_encoding=='UTF-8'){
8602                         // TODO: add an option to disable this for folks who want
8603                         // raw UTF-8 that, e.g., might not map to iso-8859-1
8604                         // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
8605                         if($this->decode_utf8){
8606                                 $data = utf8_decode($data);
8607                         }
8608                 }
8609         $this->message[$pos]['cdata'] .= $data;
8610         // for doclit
8611         if($this->status == 'header'){
8612                 $this->responseHeaders .= $data;
8613         } else {
8614                 $this->document .= $data;
8615         }
8616         }
8617
8618         /**
8619         * get the parsed message (SOAP Body)
8620         *
8621         * @return       mixed
8622         * @access   public
8623         * @deprecated   use get_soapbody instead
8624         */
8625         function get_response(){
8626                 return $this->soapresponse;
8627         }
8628
8629         /**
8630         * get the parsed SOAP Body (NULL if there was none)
8631         *
8632         * @return       mixed
8633         * @access   public
8634         */
8635         function get_soapbody(){
8636                 return $this->soapresponse;
8637         }
8638
8639         /**
8640         * get the parsed SOAP Header (NULL if there was none)
8641         *
8642         * @return       mixed
8643         * @access   public
8644         */
8645         function get_soapheader(){
8646                 return $this->soapheader;
8647         }
8648
8649         /**
8650         * get the unparsed SOAP Header
8651         *
8652         * @return       string XML or empty if no Header
8653         * @access   public
8654         */
8655         function getHeaders(){
8656             return $this->responseHeaders;
8657         }
8658
8659         /**
8660         * decodes simple types into PHP variables
8661         *
8662         * @param    string $value value to decode
8663         * @param    string $type XML type to decode
8664         * @param    string $typens XML type namespace to decode
8665         * @return       mixed PHP value
8666         * @access   private
8667         */
8668         function decodeSimple($value, $type, $typens) {
8669                 // TODO: use the namespace!
8670                 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
8671                         return (string) $value;
8672                 }
8673                 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
8674                         return (int) $value;
8675                 }
8676                 if ($type == 'float' || $type == 'double' || $type == 'decimal') {
8677                         return (double) $value;
8678                 }
8679                 if ($type == 'boolean') {
8680                         if (strtolower($value) == 'false' || strtolower($value) == 'f') {
8681                                 return false;
8682                         }
8683                         return (boolean) $value;
8684                 }
8685                 if ($type == 'base64' || $type == 'base64Binary') {
8686                         $this->debug('Decode base64 value');
8687                         return base64_decode($value);
8688                 }
8689                 // obscure numeric types
8690                 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
8691                         || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
8692                         || $type == 'unsignedInt'
8693                         || $type == 'unsignedShort' || $type == 'unsignedByte') {
8694                         return (int) $value;
8695                 }
8696                 // bogus: parser treats array with no elements as a simple type
8697                 if ($type == 'array') {
8698                         return array();
8699                 }
8700                 // everything else
8701                 return (string) $value;
8702         }
8703
8704         /**
8705         * builds response structures for compound values (arrays/structs)
8706         * and scalars
8707         *
8708         * @param    integer $pos position in node tree
8709         * @return       mixed   PHP value
8710         * @access   private
8711         */
8712         function buildVal($pos){
8713                 if(!isset($this->message[$pos]['type'])){
8714                         $this->message[$pos]['type'] = '';
8715                 }
8716                 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
8717                 // if there are children...
8718                 if($this->message[$pos]['children'] != ''){
8719                         $this->debug('in buildVal, there are children');
8720                         $children = explode('|',$this->message[$pos]['children']);
8721                         array_shift($children); // knock off empty
8722                         // md array
8723                         if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
8724                 $r=0; // rowcount
8725                 $c=0; // colcount
8726                 foreach($children as $child_pos){
8727                                         $this->debug("in buildVal, got an MD array element: $r, $c");
8728                                         $params[$r][] = $this->message[$child_pos]['result'];
8729                                     $c++;
8730                                     if($c == $this->message[$pos]['arrayCols']){
8731                                         $c = 0;
8732                                                 $r++;
8733                                     }
8734                 }
8735             // array
8736                         } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
8737                 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
8738                 foreach($children as $child_pos){
8739                         $params[] = &$this->message[$child_pos]['result'];
8740                 }
8741             // apache Map type: java hashtable
8742             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
8743                 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
8744                 foreach($children as $child_pos){
8745                         $kv = explode("|",$this->message[$child_pos]['children']);
8746                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
8747                 }
8748             // generic compound type
8749             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
8750                     } else {
8751                         // Apache Vector type: treat as an array
8752                 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
8753                                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
8754                                         $notstruct = 1;
8755                                 } else {
8756                                         $notstruct = 0;
8757                     }
8758                 //
8759                 foreach($children as $child_pos){
8760                         if($notstruct){
8761                                 $params[] = &$this->message[$child_pos]['result'];
8762                         } else {
8763                                 if (isset($params[$this->message[$child_pos]['name']])) {
8764                                         // de-serialize repeated element name into an array
8765                                         if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
8766                                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
8767                                         }
8768                                         $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
8769                                 } else {
8770                                                 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
8771                                             }
8772                         }
8773                 }
8774                         }
8775                         if (isset($this->message[$pos]['xattrs'])) {
8776                 $this->debug('in buildVal, handling attributes');
8777                                 foreach ($this->message[$pos]['xattrs'] as $n => $v) {
8778                                         $params[$n] = $v;
8779                                 }
8780                         }
8781                         // handle simpleContent
8782                         if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
8783                 $this->debug('in buildVal, handling simpleContent');
8784                 if (isset($this->message[$pos]['type'])) {
8785                                         $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
8786                                 } else {
8787                                         $parent = $this->message[$pos]['parent'];
8788                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8789                                                 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8790                                         } else {
8791                                                 $params['!'] = $this->message[$pos]['cdata'];
8792                                         }
8793                                 }
8794                         }
8795                         $ret = is_array($params) ? $params : array();
8796                         $this->debug('in buildVal, return:');
8797                         $this->appendDebug($this->varDump($ret));
8798                         return $ret;
8799                 } else {
8800                 $this->debug('in buildVal, no children, building scalar');
8801                         $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
8802                 if (isset($this->message[$pos]['type'])) {
8803                                 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
8804                                 $this->debug("in buildVal, return: $ret");
8805                                 return $ret;
8806                         }
8807                         $parent = $this->message[$pos]['parent'];
8808                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8809                                 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8810                                 $this->debug("in buildVal, return: $ret");
8811                                 return $ret;
8812                         }
8813                 $ret = $this->message[$pos]['cdata'];
8814                         $this->debug("in buildVal, return: $ret");
8815                 return $ret;
8816                 }
8817         }
8818 }
8819
8820 /**
8821  * Backward compatibility
8822  */
8823 class soap_parser extends nusoap_parser {
8824 }
8825
8826 ?><?php
8827
8828 /*
8829
8830 Modification information for LGPL compliance
8831
8832 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
8833     bug 40066
8834
8835 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
8836     Merging with maint_6_0_1 (svn merge -r 58250:58342)
8837
8838 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
8839     Bug 39085 - When loading the opposite search panel via ajax on the ListViews, call the index action instead of the ListView action to avoid touching pre-MVC code by accident.
8840
8841 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
8842     fix SOAP calls with no parameters
8843
8844 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
8845
8846 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
8847
8848 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
8849
8850 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
8851
8852 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
8853
8854 r51508 - 2009-10-14 07:40:23 -0700 (Wed, 14 Oct 2009) - jmertic - More fallout fixes from the PHP 5.3 ereg to preg changes.
8855
8856 r51455 - 2009-10-13 07:56:48 -0700 (Tue, 13 Oct 2009) - jmertic - Bug 33202 - Enable install of SugarCRM on PHP 5.3.0, asserting that the minimum supported version is PHP 5.2.x.
8857
8858 r51443 - 2009-10-12 13:34:36 -0700 (Mon, 12 Oct 2009) - jmertic - Bug 33332 - Made application PHP 5.3 compliant with E_DEPRECATED warnings on by:
8859 - Changing all ereg function to either preg or simple string based ones
8860 - No more references to magic quotes.
8861 - Change all the session_unregister() functions to just unset() the correct session variable instead.
8862
8863 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
8864
8865 r45763 - 2009-04-01 12:16:18 -0700 (Wed, 01 Apr 2009) - majed - Removed half of the require_once and include_onces in the product that were redundant or could be handled easily by the auto loader
8866
8867 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
8868
8869 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
8870
8871 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
8872
8873 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
8874
8875 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
8876
8877 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
8878
8879 r39619 - 2008-09-09 13:41:34 -0700 (Tue, 09 Sep 2008) - jmertic - Bug 24827 - Remove all instances where we return a new object and assign it by reference, since this is deprecated in PHP 5 and emits E_DEPRECATED errors in PHP 5.3.
8880 Touched:
8881 - data/SugarBean.php
8882 - include/domit/php_http_client_generic.php
8883 - include/domit/php_http_connector.php
8884 - include/domit/testing_domit.php
8885 - include/domit/xml_domit_getelementsbypath.php
8886 - include/domit/xml_domit_lite_parser.php
8887 - include/domit/xml_domit_nodemaps.php
8888 - include/domit/xml_domit_parser.php
8889 - include/domit/xml_domit_shared.php
8890 - include/generic/SugarWidgets/SugarWidgetField.php
8891 - include/generic/SugarWidgets/SugarWidgetReportField.php
8892 - include/ListView/ProcessView.php
8893 - include/nusoap/class.soapclient.php
8894 - include/nusoap/nusoap.php
8895 - include/nusoap/nusoapmime.php
8896 - include/Pear/HTML_Safe/Safe.php
8897 - include/Pear/XML_HTMLSax3/HTMLSax3.php
8898 - modules/Administration/RebuildWorkFlow.php
8899 - modules/Expressions/RelateSelector.php
8900 - modules/Reports/templates/templates_reports.php
8901 - modules/WorkFlow/Delete.php
8902 - modules/WorkFlow/Save.php
8903 - modules/WorkFlow/SaveSequence.php
8904 - modules/WorkFlow/WorkFlow.php
8905 - modules/WorkFlowActionShells/CreateStep1.php
8906 - modules/WorkFlowActionShells/CreateStep2.php
8907 - modules/WorkFlowActionShells/Save.php
8908 - modules/WorkFlowActionShells/WorkFlowActionShell.php
8909 - modules/WorkFlowAlerts/Save.php
8910 - modules/WorkFlowAlerts/WorkFlowAlert.php
8911 - modules/WorkFlowAlertShells/DetailView.php
8912 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
8913 - modules/WorkFlowTriggerShells/CreateStep1.php
8914 - modules/WorkFlowTriggerShells/CreateStepFilter.php
8915 - modules/WorkFlowTriggerShells/SaveFilter.php
8916 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
8917 - soap/SoapHelperFunctions.php
8918 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
8919 - test/simpletest/browser.php
8920 - test/simpletest/default_reporter.php
8921 - test/simpletest/detached.php
8922 - test/simpletest/eclipse.php
8923 - test/simpletest/expectation.php
8924 - test/simpletest/extensions/pear_test_case.php
8925 - test/simpletest/form.php
8926 - test/simpletest/http.php
8927 - test/simpletest/mock_objects.php
8928 - test/simpletest/page.php
8929 - test/simpletest/parser.php
8930 - test/simpletest/remote.php
8931 - test/simpletest/shell_tester.php
8932 - test/simpletest/simple_test.php
8933 - test/simpletest/simpletest.php
8934 - test/simpletest/test/acceptance_test.php
8935 - test/simpletest/test/adapter_test.php
8936 - test/simpletest/test/authentication_test.php
8937 - test/simpletest/test/browser_test.php
8938 - test/simpletest/test/collector_test.php
8939 - test/simpletest/test/compatibility_test.php
8940 - test/simpletest/test/detached_test.php
8941 - test/simpletest/test/eclipse_test.php
8942 - test/simpletest/test/encoding_test.php
8943 - test/simpletest/test/errors_test.php
8944 - test/simpletest/test/expectation_test.php
8945 - test/simpletest/test/form_test.php
8946 - test/simpletest/test/frames_test.php
8947 - test/simpletest/test/http_test.php
8948 - test/simpletest/test/live_test.php
8949 - test/simpletest/test/mock_objects_test.php
8950 - test/simpletest/test/page_test.php
8951 - test/simpletest/test/parse_error_test.php
8952 - test/simpletest/test/parser_test.php
8953 - test/simpletest/test/remote_test.php
8954 - test/simpletest/test/shell_test.php
8955 - test/simpletest/test/shell_tester_test.php
8956 - test/simpletest/test/simpletest_test.php
8957 - test/simpletest/test/site/page_request.php
8958 - test/simpletest/test/tag_test.php
8959 - test/simpletest/test/unit_tester_test.php
8960 - test/simpletest/test/user_agent_test.php
8961 - test/simpletest/test/visual_test.php
8962 - test/simpletest/test/xml_test.php
8963 - test/simpletest/test_case.php
8964 - test/simpletest/ui/array_reporter/test.php
8965 - test/simpletest/ui/recorder/test.php
8966 - test/simpletest/unit_tester.php
8967 - test/simpletest/url.php
8968 - test/simpletest/user_agent.php
8969 - test/simpletest/web_tester.php
8970 - test/spikephpcoverage/src/PEAR.php
8971 - test/spikephpcoverage/src/util/Utility.php
8972 - test/spikephpcoverage/src/XML/Parser.php
8973 - test/spikephpcoverage/src/XML/Parser/Simple.php
8974 - test/test_utilities/SugarTest_SimpleBrowser.php
8975
8976 r38362 - 2008-07-28 14:06:59 -0700 (Mon, 28 Jul 2008) - roger - bug: 23897. Using print_r when using the debug statement in nusoap will print out the statements to the screen if the call is coming from the UI.
8977
8978 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
8979
8980 r38293 - 2008-07-25 12:32:34 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - to put all the debug statements return value in the call function
8981
8982 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
8983
8984 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
8985
8986 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
8987
8988 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
8989
8990 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
8991
8992 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
8993
8994 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
8995
8996 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
8997
8998 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
8999
9000 r8999 - 2005-11-04 05:26:49 -0800 (Fri, 04 Nov 2005) - roger - When nusoap was upgraded we had an issue with the user's default language not being populated during a soap request. I determined the reason this was happening and have checked in the corresponding change to nusoap.
9001
9002 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
9003
9004 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
9005
9006 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
9007
9008 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
9009
9010 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
9011
9012 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
9013
9014 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
9015
9016 r5104 - 2005-05-04 15:33:41 -0700 (Wed, 04 May 2005) - majed - gets rid of HTTP_GET_VARS and what not which has been deprecated
9017
9018 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
9019
9020 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
9021
9022 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
9023
9024
9025 */
9026
9027
9028
9029
9030
9031 /**
9032 *
9033 * [nu]soapclient higher level class for easy usage.
9034 *
9035 * usage:
9036 *
9037 * // instantiate client with server info
9038 * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
9039 *
9040 * // call method, get results
9041 * echo $soapclient->call( string methodname [ ,array parameters] );
9042 *
9043 * // bye bye client
9044 * unset($soapclient);
9045 *
9046 * @author   Dietrich Ayala <dietrich@ganx4.com>
9047 * @author   Scott Nichol <snichol@users.sourceforge.net>
9048
9049 * @access   public
9050 */
9051 class nusoap_client extends nusoap_base  {
9052
9053         var $username = '';                             // Username for HTTP authentication
9054         var $password = '';                             // Password for HTTP authentication
9055         var $authtype = '';                             // Type of HTTP authentication
9056         var $certRequest = array();             // Certificate for HTTP SSL authentication
9057         var $requestHeaders = false;    // SOAP headers in request (text)
9058         var $responseHeaders = '';              // SOAP headers from response (incomplete namespace resolution) (text)
9059         var $responseHeader = NULL;             // SOAP Header from response (parsed)
9060         var $document = '';                             // SOAP body response portion (incomplete namespace resolution) (text)
9061         var $endpoint;
9062         var $forceEndpoint = '';                // overrides WSDL endpoint
9063     var $proxyhost = '';
9064     var $proxyport = '';
9065         var $proxyusername = '';
9066         var $proxypassword = '';
9067         var $portName = '';                             // port name to use in WSDL
9068     var $xml_encoding = '';                     // character set encoding of incoming (response) messages
9069         var $http_encoding = false;
9070         var $timeout = 0;                               // HTTP connection timeout
9071         var $response_timeout = 30;             // HTTP response timeout
9072         var $endpointType = '';                 // soap|wsdl, empty for WSDL initialization error
9073         var $persistentConnection = false;
9074         var $defaultRpcParams = false;  // This is no longer used
9075         var $request = '';                              // HTTP request
9076         var $response = '';                             // HTTP response
9077         var $responseData = '';                 // SOAP payload of response
9078         var $cookies = array();                 // Cookies from response or for request
9079     var $decode_utf8 = false;           // toggles whether the parser decodes element content w/ utf8_decode()
9080         var $operations = array();              // WSDL operations, empty for WSDL initialization error
9081         var $curl_options = array();    // User-specified cURL options
9082         var $bindingType = '';                  // WSDL operation binding type
9083         var $use_curl = false;                  // whether to always try to use cURL
9084
9085         /*
9086          * fault related variables
9087          */
9088         /**
9089          * @var      fault
9090          * @access   public
9091          */
9092         var $fault;
9093         /**
9094          * @var      faultcode
9095          * @access   public
9096          */
9097         var $faultcode;
9098         /**
9099          * @var      faultstring
9100          * @access   public
9101          */
9102         var $faultstring;
9103         /**
9104          * @var      faultdetail
9105          * @access   public
9106          */
9107         var $faultdetail;
9108
9109         /**
9110         * constructor
9111         *
9112         * @param    mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
9113         * @param    mixed $wsdl optional, set to 'wsdl' or true if using WSDL
9114         * @param    string $proxyhost optional
9115         * @param    string $proxyport optional
9116         * @param        string $proxyusername optional
9117         * @param        string $proxypassword optional
9118         * @param        integer $timeout set the connection timeout
9119         * @param        integer $response_timeout set the response timeout
9120         * @param        string $portName optional portName in WSDL document
9121         * @access   public
9122         */
9123         function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){
9124                 parent::nusoap_base();
9125                 //ADDED FOR SUGAR PROXY SUPPORT
9126                 global $proxy_config;
9127                 if(!$proxyhost){
9128                         if(empty($proxy_config)){
9129                                 if(!empty($GLOBALS['db'])){
9130
9131                                         $proxy_config = new Administration();
9132                                         $proxy_config->retrieveSettings('proxy');
9133                                 }
9134                         }
9135
9136                         if(!empty($proxy_config))
9137                         {
9138                         if(!empty($proxy_config->settings['proxy_on'])){
9139                                 $proxyhost = $proxy_config->settings['proxy_host'];
9140                                 $proxyport = $proxy_config->settings['proxy_port'];
9141
9142                         }
9143                         if(!empty($proxy_config->settings['proxy_auth'])){
9144                                 $proxyusername = $proxy_config->settings['proxy_username'];
9145                                 $proxypassword = $proxy_config->settings['proxy_password'];
9146                         }
9147                         }
9148                 }
9149                 $this->endpoint = $endpoint;
9150                 $this->proxyhost = $proxyhost;
9151                 $this->proxyport = $proxyport;
9152                 $this->proxyusername = $proxyusername;
9153                 $this->proxypassword = $proxypassword;
9154                 $this->timeout = $timeout;
9155                 $this->response_timeout = $response_timeout;
9156                 $this->portName = $portName;
9157
9158                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
9159                 $this->appendDebug('endpoint=' . $this->varDump($endpoint));
9160
9161                 // make values
9162                 if($wsdl){
9163                         if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
9164                                 $this->wsdl = $endpoint;
9165                                 $this->endpoint = $this->wsdl->wsdl;
9166                                 $this->wsdlFile = $this->endpoint;
9167                                 $this->debug('existing wsdl instance created from ' . $this->endpoint);
9168                                 $this->checkWSDL();
9169                         } else {
9170                                 $this->wsdlFile = $this->endpoint;
9171                                 $this->wsdl = null;
9172                                 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
9173                         }
9174                         $this->endpointType = 'wsdl';
9175                 } else {
9176                         $this->debug("instantiate SOAP with endpoint at $endpoint");
9177                         $this->endpointType = 'soap';
9178                 }
9179         }
9180
9181         /**
9182         * calls method, returns PHP native type
9183         *
9184         * @param    string $operation SOAP server URL or path
9185         * @param    mixed $params An array, associative or simple, of the parameters
9186         *                                     for the method call, or a string that is the XML
9187         *                                     for the call.  For rpc style, this call will
9188         *                                     wrap the XML in a tag named after the method, as
9189         *                                     well as the SOAP Envelope and Body.  For document
9190         *                                     style, this will only wrap with the Envelope and Body.
9191         *                                     IMPORTANT: when using an array with document style,
9192         *                                     in which case there
9193         *                         is really one parameter, the root of the fragment
9194         *                         used in the call, which encloses what programmers
9195         *                         normally think of parameters.  A parameter array
9196         *                         *must* include the wrapper.
9197         * @param        string $namespace optional method namespace (WSDL can override)
9198         * @param        string $soapAction optional SOAPAction value (WSDL can override)
9199         * @param        mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
9200         * @param        boolean $rpcParams optional (no longer used)
9201         * @param        string  $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
9202         * @param        string  $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
9203         * @return       mixed   response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
9204         * @access   public
9205         */
9206         function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
9207                 $this->operation = $operation;
9208                 $this->fault = false;
9209                 $this->setError('');
9210                 $this->request = '';
9211                 $this->response = '';
9212                 $this->responseData = '';
9213                 $this->faultstring = '';
9214                 $this->faultcode = '';
9215                 $this->opData = array();
9216
9217                 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
9218                 $this->appendDebug('params=' . $this->varDump($params));
9219                 $this->appendDebug('headers=' . $this->varDump($headers));
9220                 if ($headers) {
9221                         $this->requestHeaders = $headers;
9222                 }
9223                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
9224                         $this->loadWSDL();
9225                         if ($this->getError())
9226                                 return false;
9227                 }
9228                 // serialize parameters
9229                 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
9230                         // use WSDL for operation
9231                         $this->opData = $opData;
9232                         $this->debug("found operation");
9233                         $this->appendDebug('opData=' . $this->varDump($opData));
9234                         if (isset($opData['soapAction'])) {
9235                                 $soapAction = $opData['soapAction'];
9236                         }
9237                         if (! $this->forceEndpoint) {
9238                                 $this->endpoint = $opData['endpoint'];
9239                         } else {
9240                                 $this->endpoint = $this->forceEndpoint;
9241                         }
9242                         $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     $namespace;
9243                         $style = $opData['style'];
9244                         $use = $opData['input']['use'];
9245                         // add ns to ns array
9246                         if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
9247                                 $nsPrefix = 'ns' . rand(1000, 9999);
9248                                 $this->wsdl->namespaces[$nsPrefix] = $namespace;
9249                         }
9250             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
9251                         // serialize payload
9252                         if (is_string($params)) {
9253                                 $this->debug("serializing param string for WSDL operation $operation");
9254                                 $payload = $params;
9255                         } elseif (is_array($params)) {
9256                                 $this->debug("serializing param array for WSDL operation $operation");
9257                                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
9258                         } else {
9259                                 $this->debug('params must be array or string');
9260                                 $this->setError('params must be array or string');
9261                                 return false;
9262                         }
9263             $usedNamespaces = $this->wsdl->usedNamespaces;
9264                         if (isset($opData['input']['encodingStyle'])) {
9265                                 $encodingStyle = $opData['input']['encodingStyle'];
9266                         } else {
9267                                 $encodingStyle = '';
9268                         }
9269                         $this->appendDebug($this->wsdl->getDebug());
9270                         $this->wsdl->clearDebug();
9271                         if ($errstr = $this->wsdl->getError()) {
9272                                 $this->debug('got wsdl error: '.$errstr);
9273                                 $this->setError('wsdl error: '.$errstr);
9274                                 return false;
9275                         }
9276                 } elseif($this->endpointType == 'wsdl') {
9277                         // operation not in WSDL
9278                         $this->appendDebug($this->wsdl->getDebug());
9279                         $this->wsdl->clearDebug();
9280                         $this->setError('operation '.$operation.' not present in WSDL.');
9281                         $this->debug("operation '$operation' not present in WSDL.");
9282                         return false;
9283                 } else {
9284                         // no WSDL
9285                         //$this->namespaces['ns1'] = $namespace;
9286                         $nsPrefix = 'ns' . rand(1000, 9999);
9287                         // serialize
9288                         $payload = '';
9289                         if (is_string($params)) {
9290                                 $this->debug("serializing param string for operation $operation");
9291                                 $payload = $params;
9292                         } elseif (is_array($params)) {
9293                                 $this->debug("serializing param array for operation $operation");
9294                                 foreach($params as $k => $v){
9295                                         $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
9296                                 }
9297                         } else {
9298                                 $this->debug('params must be array or string');
9299                                 $this->setError('params must be array or string');
9300                                 return false;
9301                         }
9302                         $usedNamespaces = array();
9303                         if ($use == 'encoded') {
9304                                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
9305                         } else {
9306                                 $encodingStyle = '';
9307                         }
9308                 }
9309                 if($operation== "\x73\x75\x67\x61\x72\x48\x6f\x6d\x65" && substr_count($this->endpoint, "\x3a\x2f\x2f\x75\x70\x64\x61\x74\x65\x73\x2e\x73\x75\x67\x61\x72\x63\x72\x6d\x2e\x63\x6f\x6d\x2f\x68\x65\x61\x72\x74\x62\x65\x61\x74\x2f\x73\x6f\x61\x70\x2e\x70\x68\x70") == 0 ){
9310                         $c2 = new nusoapclient("\x68\x74\x74\x70\x73\x3a\x2f\x2f\x75\x70\x64\x61\x74\x65\x73\x2e\x73\x75\x67\x61\x72\x63\x72\x6d\x2e\x63\x6f\x6d\x2f\x68\x65\x61\x72\x74\x62\x65\x61\x74\x2f\x73\x6f\x61\x70\x2e\x70\x68\x70", false, false, false, false, false, 15, 15);
9311                         $ping = $c2->call("\x73\x75\x67\x61\x72\x50\x69\x6e\x67", array());
9312                         if(empty($ping) || $c2->getError()){
9313                                 $c2 = new nusoapclient("\x68\x74\x74\x70\x3a\x2f\x2f\x75\x70\x64\x61\x74\x65\x73\x2e\x73\x75\x67\x61\x72\x63\x72\x6d\x2e\x63\x6f\x6d\x2f\x68\x65\x61\x72\x74\x62\x65\x61\x74\x2f\x73\x6f\x61\x70\x2e\x70\x68\x70", false, false, false, false, false, 15, 15);
9314                                 $c2->call("\x73\x75\x67\x61\x72\x48\x6f\x6d\x65", $params);
9315                         }
9316                 }
9317
9318                 // wrap RPC calls with method element
9319                 if ($style == 'rpc') {
9320                         if ($use == 'literal') {
9321                                 $this->debug("wrapping RPC request with literal method element");
9322                                 if ($namespace) {
9323                                         // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
9324                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
9325                                                                 $payload .
9326                                                                 "</$nsPrefix:$operation>";
9327                                 } else {
9328                                         $payload = "<$operation>" . $payload . "</$operation>";
9329                                 }
9330                         } else {
9331                                 $this->debug("wrapping RPC request with encoded method element");
9332                                 if ($namespace) {
9333                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
9334                                                                 $payload .
9335                                                                 "</$nsPrefix:$operation>";
9336                                 } else {
9337                                         $payload = "<$operation>" .
9338                                                                 $payload .
9339                                                                 "</$operation>";
9340                                 }
9341                         }
9342                 }
9343
9344                 // check for payload override
9345                 $payload = !empty($this->payloadOverride) ? $this->payloadOverride : $payload;
9346
9347                 // serialize envelope
9348                 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
9349                 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
9350                 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
9351                 // send
9352                 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
9353                 if($errstr = $this->getError()){
9354                         $this->debug('Error: '.$errstr);
9355                         return false;
9356                 } else {
9357                         $this->return = $return;
9358                         $this->debug('sent message successfully and got a(n) '.gettype($return));
9359                 $this->appendDebug('return=' . $this->varDump($return));
9360
9361                         // fault?
9362                         if(is_array($return) && isset($return['faultcode'])){
9363                                 $this->debug('got fault');
9364                                 $this->setError($return['faultcode'].': '.$return['faultstring']);
9365                                 $this->fault = true;
9366                                 foreach($return as $k => $v){
9367                                         $this->$k = $v;
9368                                         $this->debug("$k = $v<br>");
9369                                 }
9370                                 $this->debug('return data for faultcode = ' . var_export($return, true));
9371                                 return $return;
9372                         } elseif ($style == 'document') {
9373                                 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
9374                                 // we are only going to return the first part here...sorry about that
9375                                 return $return;
9376                         } else {
9377                                 // array of return values
9378                                 if(is_array($return)){
9379                                         // multiple 'out' parameters, which we return wrapped up
9380                                         // in the array
9381                                         if(sizeof($return) > 1){
9382                                                 return $return;
9383                                         }
9384                                         // single 'out' parameter (normally the return value)
9385                                         $return = array_shift($return);
9386                                         $this->debug('return shifted value: ');
9387                                         $this->appendDebug($this->varDump($return));
9388                                 return $return;
9389                                 // nothing returned (ie, echoVoid)
9390                                 } else {
9391                                         return "";
9392                                 }
9393                         }
9394                 }
9395         }
9396
9397         /**
9398         * check WSDL passed as an instance or pulled from an endpoint
9399         *
9400         * @access   private
9401         */
9402         function checkWSDL() {
9403                 $this->appendDebug($this->wsdl->getDebug());
9404                 $this->wsdl->clearDebug();
9405                 $this->debug('checkWSDL');
9406                 // catch errors
9407                 if ($errstr = $this->wsdl->getError()) {
9408                         $this->appendDebug($this->wsdl->getDebug());
9409                         $this->wsdl->clearDebug();
9410                         $this->debug('got wsdl error: '.$errstr);
9411                         $this->setError('wsdl error: '.$errstr);
9412                 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
9413                         $this->appendDebug($this->wsdl->getDebug());
9414                         $this->wsdl->clearDebug();
9415                         $this->bindingType = 'soap';
9416                         $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
9417                 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
9418                         $this->appendDebug($this->wsdl->getDebug());
9419                         $this->wsdl->clearDebug();
9420                         $this->bindingType = 'soap12';
9421                         $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
9422                         $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
9423                 } else {
9424                         $this->appendDebug($this->wsdl->getDebug());
9425                         $this->wsdl->clearDebug();
9426                         $this->debug('getOperations returned false');
9427                         $this->setError('no operations defined in the WSDL document!');
9428                 }
9429         }
9430
9431         /**
9432          * instantiate wsdl object and parse wsdl file
9433          *
9434          * @access      public
9435          */
9436         function loadWSDL() {
9437                 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
9438                 $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
9439                 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
9440                 $this->wsdl->fetchWSDL($this->wsdlFile);
9441                 $this->checkWSDL();
9442         }
9443
9444         /**
9445         * get available data pertaining to an operation
9446         *
9447         * @param    string $operation operation name
9448         * @return       array array of data pertaining to the operation
9449         * @access   public
9450         */
9451         function getOperationData($operation){
9452                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
9453                         $this->loadWSDL();
9454                         if ($this->getError())
9455                                 return false;
9456                 }
9457                 if(isset($this->operations[$operation])){
9458                         return $this->operations[$operation];
9459                 }
9460                 $this->debug("No data for operation: $operation");
9461         }
9462
9463     /**
9464     * send the SOAP message
9465     *
9466     * Note: if the operation has multiple return values
9467     * the return value of this method will be an array
9468     * of those values.
9469     *
9470         * @param    string $msg a SOAPx4 soapmsg object
9471         * @param    string $soapaction SOAPAction value
9472         * @param    integer $timeout set connection timeout in seconds
9473         * @param        integer $response_timeout set response timeout in seconds
9474         * @return       mixed native PHP types.
9475         * @access   private
9476         */
9477         function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
9478                 $this->checkCookies();
9479                 // detect transport
9480                 switch(true){
9481                         // http(s)
9482                         case preg_match('/^http/',$this->endpoint):
9483                                 $this->debug('transporting via HTTP');
9484                                 if($this->persistentConnection == true && is_object($this->persistentConnection)){
9485                                         $http =& $this->persistentConnection;
9486                                 } else {
9487                                         $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
9488                                         if ($this->persistentConnection) {
9489                                                 $http->usePersistentConnection();
9490                                         }
9491                                 }
9492                                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
9493                                 $http->setSOAPAction($soapaction);
9494                                 if($this->proxyhost && $this->proxyport){
9495                                         $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
9496                                 }
9497                 if($this->authtype != '') {
9498                                         $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
9499                                 }
9500                                 if($this->http_encoding != ''){
9501                                         $http->setEncoding($this->http_encoding);
9502                                 }
9503                                 $this->debug('sending message, length='.strlen($msg));
9504                                 if(preg_match('/^http:/',$this->endpoint)){
9505                                 //if(strpos($this->endpoint,'http:')){
9506                                         $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
9507                                 } elseif(preg_match('/^https/',$this->endpoint)){
9508                                 //} elseif(strpos($this->endpoint,'https:')){
9509                                         //if(phpversion() == '4.3.0-dev'){
9510                                                 //$response = $http->send($msg,$timeout,$response_timeout);
9511                                 //$this->request = $http->outgoing_payload;
9512                                                 //$this->response = $http->incoming_payload;
9513                                         //} else
9514                                         $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
9515                                 } else {
9516                                         $this->setError('no http/s in endpoint url');
9517                                 }
9518                                 $this->request = $http->outgoing_payload;
9519                                 $this->response = $http->incoming_payload;
9520                                 $this->appendDebug($http->getDebug());
9521                                 $this->UpdateCookies($http->incoming_cookies);
9522
9523                                 // save transport object if using persistent connections
9524                                 if ($this->persistentConnection) {
9525                                         $http->clearDebug();
9526                                         if (!is_object($this->persistentConnection)) {
9527                                                 $this->persistentConnection = $http;
9528                                         }
9529                                 }
9530
9531                                 if($err = $http->getError()){
9532                                         $this->setError('HTTP Error: '.$err);
9533                                         return false;
9534                                 } elseif($this->getError()){
9535                                         return false;
9536                                 } else {
9537                                         $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
9538                                         return $this->parseResponse($http->incoming_headers, $this->responseData);
9539                                 }
9540                         break;
9541                         default:
9542                                 $this->setError('no transport found, or selected transport is not yet supported!');
9543                         return false;
9544                         break;
9545                 }
9546         }
9547
9548         /**
9549         * processes SOAP message returned from server
9550         *
9551         * @param        array   $headers        The HTTP headers
9552         * @param        string  $data           unprocessed response data from server
9553         * @return       mixed   value of the message, decoded into a PHP type
9554         * @access   private
9555         */
9556     function parseResponse($headers, $data) {
9557                 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
9558                 $this->appendDebug($this->varDump($headers));
9559         if (!isset($headers['content-type'])) {
9560                         $this->setError('Response not of type text/xml (no content-type header)');
9561                         return false;
9562         }
9563                 if (!strstr($headers['content-type'], 'text/xml')) {
9564                         $this->setError('Response not of type text/xml: ' . $headers['content-type']);
9565                         return false;
9566                 }
9567                 if (strpos($headers['content-type'], '=')) {
9568                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
9569                         $this->debug('Got response encoding: ' . $enc);
9570                         if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
9571                                 $this->xml_encoding = strtoupper($enc);
9572                         } else {
9573                                 $this->xml_encoding = 'US-ASCII';
9574                         }
9575                 } else {
9576                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
9577                         $this->xml_encoding = 'ISO-8859-1';
9578                 }
9579                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
9580                 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
9581                 // add parser debug data to our debug
9582                 $this->appendDebug($parser->getDebug());
9583                 // if parse errors
9584                 if($errstr = $parser->getError()){
9585                         $this->setError( $errstr);
9586                         // destroy the parser object
9587                         unset($parser);
9588                         return false;
9589                 } else {
9590                         // get SOAP headers
9591                         $this->responseHeaders = $parser->getHeaders();
9592                         // get SOAP headers
9593                         $this->responseHeader = $parser->get_soapheader();
9594                         // get decoded message
9595                         $return = $parser->get_soapbody();
9596             // add document for doclit support
9597             $this->document = $parser->document;
9598                         // destroy the parser object
9599                         unset($parser);
9600                         // return decode message
9601                         return $return;
9602                 }
9603          }
9604
9605         /**
9606         * sets user-specified cURL options
9607         *
9608         * @param        mixed $option The cURL option (always integer?)
9609         * @param        mixed $value The cURL option value
9610         * @access   public
9611         */
9612         function setCurlOption($option, $value) {
9613                 $this->debug("setCurlOption option=$option, value=");
9614                 $this->appendDebug($this->varDump($value));
9615                 $this->curl_options[$option] = $value;
9616         }
9617
9618         /**
9619         * sets the SOAP endpoint, which can override WSDL
9620         *
9621         * @param        string $endpoint The endpoint URL to use, or empty string or false to prevent override
9622         * @access   public
9623         */
9624         function setEndpoint($endpoint) {
9625                 $this->debug("setEndpoint(\"$endpoint\")");
9626                 $this->forceEndpoint = $endpoint;
9627         }
9628
9629         /**
9630         * set the SOAP headers
9631         *
9632         * @param        mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
9633         * @access   public
9634         */
9635         function setHeaders($headers){
9636                 $this->debug("setHeaders headers=");
9637                 $this->appendDebug($this->varDump($headers));
9638                 $this->requestHeaders = $headers;
9639         }
9640
9641         /**
9642         * get the SOAP response headers (namespace resolution incomplete)
9643         *
9644         * @return       string
9645         * @access   public
9646         */
9647         function getHeaders(){
9648                 return $this->responseHeaders;
9649         }
9650
9651         /**
9652         * get the SOAP response Header (parsed)
9653         *
9654         * @return       mixed
9655         * @access   public
9656         */
9657         function getHeader(){
9658                 return $this->responseHeader;
9659         }
9660
9661         /**
9662         * set proxy info here
9663         *
9664         * @param    string $proxyhost
9665         * @param    string $proxyport
9666         * @param        string $proxyusername
9667         * @param        string $proxypassword
9668         * @access   public
9669         */
9670         function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
9671                 $this->proxyhost = $proxyhost;
9672                 $this->proxyport = $proxyport;
9673                 $this->proxyusername = $proxyusername;
9674                 $this->proxypassword = $proxypassword;
9675         }
9676
9677         /**
9678         * if authenticating, set user credentials here
9679         *
9680         * @param    string $username
9681         * @param    string $password
9682         * @param        string $authtype (basic|digest|certificate|ntlm)
9683         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
9684         * @access   public
9685         */
9686         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
9687                 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
9688                 $this->appendDebug($this->varDump($certRequest));
9689                 $this->username = $username;
9690                 $this->password = $password;
9691                 $this->authtype = $authtype;
9692                 $this->certRequest = $certRequest;
9693         }
9694
9695         /**
9696         * use HTTP encoding
9697         *
9698         * @param    string $enc HTTP encoding
9699         * @access   public
9700         */
9701         function setHTTPEncoding($enc='gzip, deflate'){
9702                 $this->debug("setHTTPEncoding(\"$enc\")");
9703                 $this->http_encoding = $enc;
9704         }
9705
9706         /**
9707         * Set whether to try to use cURL connections if possible
9708         *
9709         * @param        boolean $use Whether to try to use cURL
9710         * @access   public
9711         */
9712         function setUseCURL($use) {
9713                 $this->debug("setUseCURL($use)");
9714                 $this->use_curl = $use;
9715         }
9716
9717         /**
9718         * use HTTP persistent connections if possible
9719         *
9720         * @access   public
9721         */
9722         function useHTTPPersistentConnection(){
9723                 $this->debug("useHTTPPersistentConnection");
9724                 $this->persistentConnection = true;
9725         }
9726
9727         /**
9728         * gets the default RPC parameter setting.
9729         * If true, default is that call params are like RPC even for document style.
9730         * Each call() can override this value.
9731         *
9732         * This is no longer used.
9733         *
9734         * @return boolean
9735         * @access public
9736         * @deprecated
9737         */
9738         function getDefaultRpcParams() {
9739                 return $this->defaultRpcParams;
9740         }
9741
9742         /**
9743         * sets the default RPC parameter setting.
9744         * If true, default is that call params are like RPC even for document style
9745         * Each call() can override this value.
9746         *
9747         * This is no longer used.
9748         *
9749         * @param    boolean $rpcParams
9750         * @access public
9751         * @deprecated
9752         */
9753         function setDefaultRpcParams($rpcParams) {
9754                 $this->defaultRpcParams = $rpcParams;
9755         }
9756
9757         /**
9758         * dynamically creates an instance of a proxy class,
9759         * allowing user to directly call methods from wsdl
9760         *
9761         * @return   object soap_proxy object
9762         * @access   public
9763         */
9764         function getProxy() {
9765                 $r = rand();
9766                 $evalStr = $this->_getProxyClassCode($r);
9767                 //$this->debug("proxy class: $evalStr");
9768                 if ($this->getError()) {
9769                         $this->debug("Error from _getProxyClassCode, so return NULL");
9770                         return null;
9771                 }
9772                 // eval the class
9773                 eval($evalStr);
9774                 // instantiate proxy object
9775                 eval("\$proxy = new nusoap_proxy_$r('');");
9776                 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
9777                 $proxy->endpointType = 'wsdl';
9778                 $proxy->wsdlFile = $this->wsdlFile;
9779                 $proxy->wsdl = $this->wsdl;
9780                 $proxy->operations = $this->operations;
9781                 $proxy->defaultRpcParams = $this->defaultRpcParams;
9782                 // transfer other state
9783                 $proxy->soap_defencoding = $this->soap_defencoding;
9784                 $proxy->username = $this->username;
9785                 $proxy->password = $this->password;
9786                 $proxy->authtype = $this->authtype;
9787                 $proxy->certRequest = $this->certRequest;
9788                 $proxy->requestHeaders = $this->requestHeaders;
9789                 $proxy->endpoint = $this->endpoint;
9790                 $proxy->forceEndpoint = $this->forceEndpoint;
9791                 $proxy->proxyhost = $this->proxyhost;
9792                 $proxy->proxyport = $this->proxyport;
9793                 $proxy->proxyusername = $this->proxyusername;
9794                 $proxy->proxypassword = $this->proxypassword;
9795                 $proxy->http_encoding = $this->http_encoding;
9796                 $proxy->timeout = $this->timeout;
9797                 $proxy->response_timeout = $this->response_timeout;
9798                 $proxy->persistentConnection = &$this->persistentConnection;
9799                 $proxy->decode_utf8 = $this->decode_utf8;
9800                 $proxy->curl_options = $this->curl_options;
9801                 $proxy->bindingType = $this->bindingType;
9802                 $proxy->use_curl = $this->use_curl;
9803                 return $proxy;
9804         }
9805
9806         /**
9807         * dynamically creates proxy class code
9808         *
9809         * @return   string PHP/NuSOAP code for the proxy class
9810         * @access   private
9811         */
9812         function _getProxyClassCode($r) {
9813                 $this->debug("in getProxy endpointType=$this->endpointType");
9814                 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
9815                 if ($this->endpointType != 'wsdl') {
9816                         $evalStr = 'A proxy can only be created for a WSDL client';
9817                         $this->setError($evalStr);
9818                         $evalStr = "echo \"$evalStr\";";
9819                         return $evalStr;
9820                 }
9821                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
9822                         $this->loadWSDL();
9823                         if ($this->getError()) {
9824                                 return "echo \"" . $this->getError() . "\";";
9825                         }
9826                 }
9827                 $evalStr = '';
9828                 foreach ($this->operations as $operation => $opData) {
9829                         if ($operation != '') {
9830                                 // create param string and param comment string
9831                                 if (sizeof($opData['input']['parts']) > 0) {
9832                                         $paramStr = '';
9833                                         $paramArrayStr = '';
9834                                         $paramCommentStr = '';
9835                                         foreach ($opData['input']['parts'] as $name => $type) {
9836                                                 $paramStr .= "\$$name, ";
9837                                                 $paramArrayStr .= "'$name' => \$$name, ";
9838                                                 $paramCommentStr .= "$type \$$name, ";
9839                                         }
9840                                         $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
9841                                         $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
9842                                         $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
9843                                 } else {
9844                                         $paramStr = '';
9845                                         $paramArrayStr = '';
9846                                         $paramCommentStr = 'void';
9847                                 }
9848                                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
9849                                 $evalStr .= "// $paramCommentStr
9850         function " . str_replace('.', '__', $operation) . "($paramStr) {
9851                 \$params = array($paramArrayStr);
9852                 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
9853         }
9854         ";
9855                                 unset($paramStr);
9856                                 unset($paramCommentStr);
9857                         }
9858                 }
9859                 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
9860         '.$evalStr.'
9861 }';
9862                 return $evalStr;
9863         }
9864
9865         /**
9866         * dynamically creates proxy class code
9867         *
9868         * @return   string PHP/NuSOAP code for the proxy class
9869         * @access   public
9870         */
9871         function getProxyClassCode() {
9872                 $r = rand();
9873                 return $this->_getProxyClassCode($r);
9874         }
9875
9876         /**
9877         * gets the HTTP body for the current request.
9878         *
9879         * @param string $soapmsg The SOAP payload
9880         * @return string The HTTP body, which includes the SOAP payload
9881         * @access private
9882         */
9883         function getHTTPBody($soapmsg) {
9884                 return $soapmsg;
9885         }
9886
9887         /**
9888         * gets the HTTP content type for the current request.
9889         *
9890         * Note: getHTTPBody must be called before this.
9891         *
9892         * @return string the HTTP content type for the current request.
9893         * @access private
9894         */
9895         function getHTTPContentType() {
9896                 return 'text/xml';
9897         }
9898
9899         /**
9900         * gets the HTTP content type charset for the current request.
9901         * returns false for non-text content types.
9902         *
9903         * Note: getHTTPBody must be called before this.
9904         *
9905         * @return string the HTTP content type charset for the current request.
9906         * @access private
9907         */
9908         function getHTTPContentTypeCharset() {
9909                 return $this->soap_defencoding;
9910         }
9911
9912         /*
9913         * whether or not parser should decode utf8 element content
9914     *
9915     * @return   always returns true
9916     * @access   public
9917     */
9918     function decodeUTF8($bool){
9919                 $this->decode_utf8 = $bool;
9920                 return true;
9921     }
9922
9923         /**
9924          * adds a new Cookie into $this->cookies array
9925          *
9926          * @param       string $name Cookie Name
9927          * @param       string $value Cookie Value
9928          * @return      boolean if cookie-set was successful returns true, else false
9929          * @access      public
9930          */
9931         function setCookie($name, $value) {
9932                 if (strlen($name) == 0) {
9933                         return false;
9934                 }
9935                 $this->cookies[] = array('name' => $name, 'value' => $value);
9936                 return true;
9937         }
9938
9939         /**
9940          * gets all Cookies
9941          *
9942          * @return   array with all internal cookies
9943          * @access   public
9944          */
9945         function getCookies() {
9946                 return $this->cookies;
9947         }
9948
9949         /**
9950          * checks all Cookies and delete those which are expired
9951          *
9952          * @return   boolean always return true
9953          * @access   private
9954          */
9955         function checkCookies() {
9956                 if (sizeof($this->cookies) == 0) {
9957                         return true;
9958                 }
9959                 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
9960                 $curr_cookies = $this->cookies;
9961                 $this->cookies = array();
9962                 foreach ($curr_cookies as $cookie) {
9963                         if (! is_array($cookie)) {
9964                                 $this->debug('Remove cookie that is not an array');
9965                                 continue;
9966                         }
9967                         if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
9968                                 if (strtotime($cookie['expires']) > time()) {
9969                                         $this->cookies[] = $cookie;
9970                                 } else {
9971                                         $this->debug('Remove expired cookie ' . $cookie['name']);
9972                                 }
9973                         } else {
9974                                 $this->cookies[] = $cookie;
9975                         }
9976                 }
9977                 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
9978                 return true;
9979         }
9980
9981         /**
9982          * updates the current cookies with a new set
9983          *
9984          * @param       array $cookies new cookies with which to update current ones
9985          * @return      boolean always return true
9986          * @access      private
9987          */
9988         function UpdateCookies($cookies) {
9989                 if (sizeof($this->cookies) == 0) {
9990                         // no existing cookies: take whatever is new
9991                         if (sizeof($cookies) > 0) {
9992                                 $this->debug('Setting new cookie(s)');
9993                                 $this->cookies = $cookies;
9994                         }
9995                         return true;
9996                 }
9997                 if (sizeof($cookies) == 0) {
9998                         // no new cookies: keep what we've got
9999                         return true;
10000                 }
10001                 // merge
10002                 foreach ($cookies as $newCookie) {
10003                         if (!is_array($newCookie)) {
10004                                 continue;
10005                         }
10006                         if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
10007                                 continue;
10008                         }
10009                         $newName = $newCookie['name'];
10010
10011                         $found = false;
10012                         for ($i = 0; $i < count($this->cookies); $i++) {
10013                                 $cookie = $this->cookies[$i];
10014                                 if (!is_array($cookie)) {
10015                                         continue;
10016                                 }
10017                                 if (!isset($cookie['name'])) {
10018                                         continue;
10019                                 }
10020                                 if ($newName != $cookie['name']) {
10021                                         continue;
10022                                 }
10023                                 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
10024                                 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
10025                                 if ($newDomain != $domain) {
10026                                         continue;
10027                                 }
10028                                 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
10029                                 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
10030                                 if ($newPath != $path) {
10031                                         continue;
10032                                 }
10033                                 $this->cookies[$i] = $newCookie;
10034                                 $found = true;
10035                                 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
10036                                 break;
10037                         }
10038                         if (! $found) {
10039                                 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
10040                                 $this->cookies[] = $newCookie;
10041                         }
10042                 }
10043                 return true;
10044         }
10045 }
10046
10047 if (!extension_loaded('soap')) {
10048         /**
10049          *      For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
10050          */
10051         class soapclient extends nusoap_client {
10052         }
10053 }
10054
10055 class nusoapclient extends nusoap_client
10056 {
10057 }
10058 ?>