]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/nusoap/nusoap.php
Release 6.5.10
[Github/sugarcrm.git] / include / nusoap / nusoap.php
1 <?php
2
3 /*
4 Modification information for LGPL compliance
5
6 commit 76702f8945b5e4076d406d8e3388c23d7959a2e3
7 Author: Stanislav Malyshev <smalyshev@gmail.com>
8 Date:   Mon Nov 26 15:35:58 2012 -0800
9
10     bug #50736 - fix proxy with different port
11
12 commit 70759790576f88f2b0480b50d35c95c84b9e6879
13 Author: Stanislav Malyshev <smalyshev@gmail.com>
14 Date:   Thu Feb 17 18:09:12 2011 -0800
15
16     bug 34897 - remove characters that aren't valid in XML
17
18 commit 1767411d701b8216cc5e043888fd1337e2eca315
19 Author: Stanislav Malyshev <smalyshev@gmail.com>
20 Date:   Fri Jan 7 12:19:10 2011 -0800
21
22     conserve memory when no debug is enabled
23
24 commit 843510ebf455368865302a05b9d5041815a32c23
25 Author: John Mertic <jmertic@sugarcrm.com>
26 Date:   Wed Nov 17 13:18:09 2010 -0500
27
28     Bug 40716 - Fix WSDL validation problem by removing hardcoded schemaLocation attribute for the <xsd:import> tag.
29
30 commit 2bd12c02078f3e291bd9c1e76179a144c788ce97
31 Author: Collin Lee <clee@Collin-Lee-MacBook-Pro.local>
32 Date:   Fri Oct 22 16:37:42 2010 -0400
33
34     Bug: 39937
35
36     We traced the error to a combination of the new Hoovers' WSDL + the nusoapclient code that winds up improperly encoding the parameter elem
37 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
38 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
39  and also re-enabled those for Hoovers that were marked skipped.
40
41 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
42     bug 40066
43
44 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
45     Merging with maint_6_0_1 (svn merge -r 58250:58342)
46
47 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
48     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.
49
50 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
51     fix SOAP calls with no parameters
52
53 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
54
55 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
56
57 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
58
59 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
60
61 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
62
63 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.
64
65 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.
66
67 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:
68 - Changing all ereg function to either preg or simple string based ones
69 - No more references to magic quotes.
70 - Change all the session_unregister() functions to just unset() the correct session variable instead.
71
72 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
73
74 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
75
76 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
77
78 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
79
80 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
81
82 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
83
84 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
85
86 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
87
88 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.
89 Touched:
90 - data/SugarBean.php
91 - include/domit/php_http_client_generic.php
92 - include/domit/php_http_connector.php
93 - include/domit/testing_domit.php
94 - include/domit/xml_domit_getelementsbypath.php
95 - include/domit/xml_domit_lite_parser.php
96 - include/domit/xml_domit_nodemaps.php
97 - include/domit/xml_domit_parser.php
98 - include/domit/xml_domit_shared.php
99 - include/generic/SugarWidgets/SugarWidgetField.php
100 - include/generic/SugarWidgets/SugarWidgetReportField.php
101 - include/ListView/ProcessView.php
102 - include/nusoap/class.soapclient.php
103 - include/nusoap/nusoap.php
104 - include/nusoap/nusoapmime.php
105 - include/Pear/HTML_Safe/Safe.php
106 - include/Pear/XML_HTMLSax3/HTMLSax3.php
107 - modules/Administration/RebuildWorkFlow.php
108 - modules/Expressions/RelateSelector.php
109 - modules/Reports/templates/templates_reports.php
110 - modules/WorkFlow/Delete.php
111 - modules/WorkFlow/Save.php
112 - modules/WorkFlow/SaveSequence.php
113 - modules/WorkFlow/WorkFlow.php
114 - modules/WorkFlowActionShells/CreateStep1.php
115 - modules/WorkFlowActionShells/CreateStep2.php
116 - modules/WorkFlowActionShells/Save.php
117 - modules/WorkFlowActionShells/WorkFlowActionShell.php
118 - modules/WorkFlowAlerts/Save.php
119 - modules/WorkFlowAlerts/WorkFlowAlert.php
120 - modules/WorkFlowAlertShells/DetailView.php
121 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
122 - modules/WorkFlowTriggerShells/CreateStep1.php
123 - modules/WorkFlowTriggerShells/CreateStepFilter.php
124 - modules/WorkFlowTriggerShells/SaveFilter.php
125 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
126 - soap/SoapHelperFunctions.php
127 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
128 - test/simpletest/browser.php
129 - test/simpletest/default_reporter.php
130 - test/simpletest/detached.php
131 - test/simpletest/eclipse.php
132 - test/simpletest/expectation.php
133 - test/simpletest/extensions/pear_test_case.php
134 - test/simpletest/form.php
135 - test/simpletest/http.php
136 - test/simpletest/mock_objects.php
137 - test/simpletest/page.php
138 - test/simpletest/parser.php
139 - test/simpletest/remote.php
140 - test/simpletest/shell_tester.php
141 - test/simpletest/simple_test.php
142 - test/simpletest/simpletest.php
143 - test/simpletest/test/acceptance_test.php
144 - test/simpletest/test/adapter_test.php
145 - test/simpletest/test/authentication_test.php
146 - test/simpletest/test/browser_test.php
147 - test/simpletest/test/collector_test.php
148 - test/simpletest/test/compatibility_test.php
149 - test/simpletest/test/detached_test.php
150 - test/simpletest/test/eclipse_test.php
151 - test/simpletest/test/encoding_test.php
152 - test/simpletest/test/errors_test.php
153 - test/simpletest/test/expectation_test.php
154 - test/simpletest/test/form_test.php
155 - test/simpletest/test/frames_test.php
156 - test/simpletest/test/http_test.php
157 - test/simpletest/test/live_test.php
158 - test/simpletest/test/mock_objects_test.php
159 - test/simpletest/test/page_test.php
160 - test/simpletest/test/parse_error_test.php
161 - test/simpletest/test/parser_test.php
162 - test/simpletest/test/remote_test.php
163 - test/simpletest/test/shell_test.php
164 - test/simpletest/test/shell_tester_test.php
165 - test/simpletest/test/simpletest_test.php
166 - test/simpletest/test/site/page_request.php
167 - test/simpletest/test/tag_test.php
168 - test/simpletest/test/unit_tester_test.php
169 - test/simpletest/test/user_agent_test.php
170 - test/simpletest/test/visual_test.php
171 - test/simpletest/test/xml_test.php
172 - test/simpletest/test_case.php
173 - test/simpletest/ui/array_reporter/test.php
174 - test/simpletest/ui/recorder/test.php
175 - test/simpletest/unit_tester.php
176 - test/simpletest/url.php
177 - test/simpletest/user_agent.php
178 - test/simpletest/web_tester.php
179 - test/spikephpcoverage/src/PEAR.php
180 - test/spikephpcoverage/src/util/Utility.php
181 - test/spikephpcoverage/src/XML/Parser.php
182 - test/spikephpcoverage/src/XML/Parser/Simple.php
183 - test/test_utilities/SugarTest_SimpleBrowser.php
184
185 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.
186
187 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
188
189 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
190
191 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
192
193 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
194
195 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
196
197 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
198
199 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
200
201 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
202
203 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
204
205 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
206
207 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
208
209 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.
210
211 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
212
213 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
214
215 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
216
217 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
218
219 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
220
221 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
222
223 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
224
225 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
226
227 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
228
229 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
230
231 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
232
233
234 */
235
236
237 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
238
239 /*
240 $Id: nusoap.php 58622 2010-10-23 01:18:59Z engsvnbuild $
241
242 NuSOAP - Web Services Toolkit for PHP
243
244 Copyright (c) 2002 NuSphere Corporation
245
246 This library is free software; you can redistribute it and/or
247 modify it under the terms of the GNU Lesser General Public
248 License as published by the Free Software Foundation; either
249 version 2.1 of the License, or (at your option) any later version.
250 n
251 This library is distributed in the hope that it will be useful,
252 but WITHOUT ANY WARRANTY; without even the implied warranty of
253 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
254 Lesser General Public License for more details.
255
256 You should have received a copy of the GNU Lesser General Public
257 License along with this library; if not, write to the Free Software
258 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
259
260 The NuSOAP project home is:
261 http://sourceforge.net/projects/nusoap/
262
263 The primary support for NuSOAP is the Help forum on the project home page.
264
265 If you have any questions or comments, please email:
266
267 Dietrich Ayala
268 dietrich@ganx4.com
269 http://dietrich.ganx4.com/nusoap
270
271 NuSphere Corporation
272 http://www.nusphere.com
273
274 */
275
276 /*
277  *      Some of the standards implmented in whole or part by NuSOAP:
278  *
279  *      SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
280  *      WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
281  *      SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
282  *      XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
283  *      Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
284  *      XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
285  *      RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
286  *      RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
287  *      RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
288  */
289
290 /* load classes
291
292 // necessary classes
293 require_once('class.soapclient.php');
294 require_once('class.soap_val.php');
295 require_once('class.soap_parser.php');
296 require_once('class.soap_fault.php');
297
298 // transport classes
299 require_once('class.soap_transport_http.php');
300
301 // optional add-on classes
302 require_once('class.xmlschema.php');
303 require_once('class.wsdl.php');
304
305 // server class
306 require_once('class.soap_server.php');*/
307
308 // class variable emulation
309 // cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
310 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 0;
311
312 /**
313 *
314 * nusoap_base
315 *
316 * @author   Dietrich Ayala <dietrich@ganx4.com>
317 * @author   Scott Nichol <snichol@users.sourceforge.net>
318
319 * @access   public
320 */
321 class nusoap_base {
322         /**
323          * Identification for HTTP headers.
324          *
325          * @var string
326          * @access private
327          */
328         var $title = 'NuSOAP';
329         /**
330          * Version for HTTP headers.
331          *
332          * @var string
333          * @access private
334          */
335         var $version = '0.9.5';
336         /**
337          * CVS revision for HTTP headers.
338          *
339          * @var string
340          * @access private
341          */
342         var $revision = '$Revision: 58622 $';
343     /**
344      * Current error string (manipulated by getError/setError)
345          *
346          * @var string
347          * @access private
348          */
349         var $error_str = '';
350     /**
351      * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
352          *
353          * @var string
354          * @access private
355          */
356     var $debug_str = '';
357     /**
358          * toggles automatic encoding of special characters as entities
359          * (should always be true, I think)
360          *
361          * @var boolean
362          * @access private
363          */
364         var $charencoding = true;
365         /**
366          * the debug level for this instance
367          *
368          * @var integer
369          * @access private
370          */
371         var $debugLevel;
372
373     /**
374         * set schema version
375         *
376         * @var      string
377         * @access   public
378         */
379         var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
380
381     /**
382         * charset encoding for outgoing messages
383         *
384         * @var      string
385         * @access   public
386         */
387     //var $soap_defencoding = 'ISO-8859-1';
388         var $soap_defencoding = 'UTF-8';
389
390         /**
391         * namespaces in an array of prefix => uri
392         *
393         * this is "seeded" by a set of constants, but it may be altered by code
394         *
395         * @var      array
396         * @access   public
397         */
398         var $namespaces = array(
399                 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
400                 'xsd' => 'http://www.w3.org/2001/XMLSchema',
401                 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
402                 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
403                 );
404
405         /**
406         * namespaces used in the current context, e.g. during serialization
407         *
408         * @var      array
409         * @access   private
410         */
411         var $usedNamespaces = array();
412
413         /**
414         * XML Schema types in an array of uri => (array of xml type => php type)
415         * is this legacy yet?
416         * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
417         * @var      array
418         * @access   public
419         */
420         var $typemap = array(
421         'http://www.w3.org/2001/XMLSchema' => array(
422                 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double',
423                 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'',
424                 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string',
425                 // abstract "any" types
426                 'anyType'=>'string','anySimpleType'=>'string',
427                 // derived datatypes
428                 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'',
429                 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer',
430                 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer',
431                 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''),
432         'http://www.w3.org/2000/10/XMLSchema' => array(
433                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
434                 'float'=>'double','dateTime'=>'string',
435                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
436         'http://www.w3.org/1999/XMLSchema' => array(
437                 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double',
438                 'float'=>'double','dateTime'=>'string',
439                 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'),
440         'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'),
441         'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'),
442     'http://xml.apache.org/xml-soap' => array('Map')
443         );
444
445         /**
446         * XML entities to convert
447         *
448         * @var      array
449         * @access   public
450         * @deprecated
451         * @see  expandEntities
452         */
453         var $xmlEntities = array('quot' => '"','amp' => '&',
454                 'lt' => '<','gt' => '>','apos' => "'");
455
456         /**
457          * Payload override
458          * This is to allows us to override the payload to resolve issues where we need to take
459          * control of the xml content
460          * @var string
461          * @access public
462          *
463          */
464         var $payloadOverride;
465
466         /**
467         * constructor
468         *
469         * @access       public
470         */
471         function nusoap_base() {
472                 $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
473         }
474
475         /**
476         * gets the global debug level, which applies to future instances
477         *
478         * @return       integer Debug level 0-9, where 0 turns off
479         * @access       public
480         */
481         function getGlobalDebugLevel() {
482                 return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
483         }
484
485         /**
486         * sets the global debug level, which applies to future instances
487         *
488         * @param        int     $level  Debug level 0-9, where 0 turns off
489         * @access       public
490         */
491         function setGlobalDebugLevel($level) {
492                 $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
493         }
494
495         /**
496         * gets the debug level for this instance
497         *
498         * @return       int     Debug level 0-9, where 0 turns off
499         * @access       public
500         */
501         function getDebugLevel() {
502                 return $this->debugLevel;
503         }
504
505         /**
506         * sets the debug level for this instance
507         *
508         * @param        int     $level  Debug level 0-9, where 0 turns off
509         * @access       public
510         */
511         function setDebugLevel($level) {
512                 $this->debugLevel = $level;
513         }
514
515         /**
516         * adds debug data to the instance debug string with formatting
517         *
518         * @param    string $string debug data
519         * @access   private
520         */
521         function debug($string){
522                 if ($this->debugLevel > 0) {
523                         $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n");
524                 }
525         }
526
527         /**
528         * adds debug data to the instance debug string without formatting
529         *
530         * @param    string $string debug data
531         * @access   public
532         */
533         function appendDebug($string){
534                 if ($this->debugLevel > 0) {
535                         // it would be nice to use a memory stream here to use
536                         // memory more efficiently
537                         $this->debug_str .= $string;
538                 }
539         }
540
541         /**
542         * clears the current debug data for this instance
543         *
544         * @access   public
545         */
546         function clearDebug() {
547                 // it would be nice to use a memory stream here to use
548                 // memory more efficiently
549                 $this->debug_str = '';
550         }
551
552         /**
553         * gets the current debug data for this instance
554         *
555         * @return   debug data
556         * @access   public
557         */
558         function &getDebug() {
559                 // it would be nice to use a memory stream here to use
560                 // memory more efficiently
561                 return $this->debug_str;
562         }
563
564         /**
565         * gets the current debug data for this instance as an XML comment
566         * this may change the contents of the debug data
567         *
568         * @return   debug data as an XML comment
569         * @access   public
570         */
571         function &getDebugAsXMLComment() {
572                 // it would be nice to use a memory stream here to use
573                 // memory more efficiently
574                 while (strpos($this->debug_str, '--')) {
575                         $this->debug_str = str_replace('--', '- -', $this->debug_str);
576                 }
577                 $ret = "<!--\n" . $this->debug_str . "\n-->";
578         return $ret;
579         }
580
581         /**
582         * expands entities, e.g. changes '<' to '&lt;'.
583         *
584         * @param        string  $val    The string in which to expand entities.
585         * @access       private
586         */
587         function expandEntities($val) {
588                 if ($this->charencoding) {
589                 $val = htmlspecialchars($val, ENT_QUOTES, $this->soap_defencoding);
590                 // XML 1.0 doesn't allow those...
591                 $val = preg_replace("/([\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F])/", '', $val);
592             }
593             return $val;
594         }
595
596         /**
597         * returns error string if present
598         *
599         * @return   mixed error string or false
600         * @access   public
601         */
602         function getError(){
603                 if($this->error_str != ''){
604                         return $this->error_str;
605                 }
606                 return false;
607         }
608
609         /**
610         * sets error string
611         *
612         * @return   boolean $string error string
613         * @access   private
614         */
615         function setError($str){
616                 $this->error_str = $str;
617         }
618
619         /**
620         * detect if array is a simple array or a struct (associative array)
621         *
622         * @param        mixed   $val    The PHP array
623         * @return       string  (arraySimple|arrayStruct)
624         * @access       private
625         */
626         function isArraySimpleOrStruct($val) {
627         $keyList = array_keys($val);
628                 foreach ($keyList as $keyListValue) {
629                         if (!is_int($keyListValue)) {
630                                 return 'arrayStruct';
631                         }
632                 }
633                 return 'arraySimple';
634         }
635
636         /**
637         * serializes PHP values in accordance w/ section 5. Type information is
638         * not serialized if $use == 'literal'.
639         *
640         * @param        mixed   $val    The value to serialize
641         * @param        string  $name   The name (local part) of the XML element
642         * @param        string  $type   The XML schema type (local part) for the element
643         * @param        string  $name_ns        The namespace for the name of the XML element
644         * @param        string  $type_ns        The namespace for the type of the element
645         * @param        array   $attributes     The attributes to serialize as name=>value pairs
646         * @param        string  $use    The WSDL "use" (encoded|literal)
647         * @param        boolean $soapval        Whether this is called from soapval.
648         * @return       string  The serialized element, possibly with child elements
649     * @access   public
650         */
651         function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) {
652                 $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
653                 $this->appendDebug('value=' . $this->varDump($val));
654                 $this->appendDebug('attributes=' . $this->varDump($attributes));
655
656         if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) {
657                 $this->debug("serialize_val: serialize soapval");
658                 $xml = $val->serialize($use);
659                         $this->appendDebug($val->getDebug());
660                         $val->clearDebug();
661                         $this->debug("serialize_val of soapval returning $xml");
662                         return $xml;
663         }
664                 // force valid name if necessary
665                 if (is_numeric($name)) {
666                         $name = '__numeric_' . $name;
667                 } elseif (! $name) {
668                         $name = 'noname';
669                 }
670                 // if name has ns, add ns prefix to name
671                 $xmlns = '';
672         if($name_ns){
673                         $prefix = 'nu'.rand(1000,9999);
674                         $name = $prefix.':'.$name;
675                         $xmlns .= " xmlns:$prefix=\"$name_ns\"";
676                 }
677                 // if type is prefixed, create type prefix
678                 if($type_ns != '' && $type_ns == $this->namespaces['xsd']){
679                         // need to fix this. shouldn't default to xsd if no ns specified
680                     // w/o checking against typemap
681                         $type_prefix = 'xsd';
682                 } elseif($type_ns){
683                         $type_prefix = 'ns'.rand(1000,9999);
684                         $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
685                 }
686                 // serialize attributes if present
687                 $atts = '';
688                 if($attributes){
689                         foreach($attributes as $k => $v){
690                                 $atts .= " $k=\"".$this->expandEntities($v).'"';
691                         }
692                 }
693                 // serialize null value
694                 if (is_null($val)) {
695                 $this->debug("serialize_val: serialize null");
696                         if ($use == 'literal') {
697                                 // TODO: depends on minOccurs
698                                 $xml = "<$name$xmlns$atts/>";
699                                 $this->debug("serialize_val returning $xml");
700                         return $xml;
701                 } else {
702                                 if (isset($type) && isset($type_prefix)) {
703                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
704                                 } else {
705                                         $type_str = '';
706                                 }
707                                 $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
708                                 $this->debug("serialize_val returning $xml");
709                         return $xml;
710                 }
711                 }
712         // serialize if an xsd built-in primitive type
713         if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){
714                 $this->debug("serialize_val: serialize xsd built-in primitive type");
715                 if (is_bool($val)) {
716                         if ($type == 'boolean') {
717                                 $val = $val ? 'true' : 'false';
718                         } elseif (! $val) {
719                                 $val = 0;
720                         }
721                         } else if (is_string($val)) {
722                                 $val = $this->expandEntities($val);
723                         }
724                         if ($use == 'literal') {
725                                 $xml = "<$name$xmlns$atts>$val</$name>";
726                                 $this->debug("serialize_val returning $xml");
727                         return $xml;
728                 } else {
729                                 $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
730                                 $this->debug("serialize_val returning $xml");
731                         return $xml;
732                 }
733         }
734                 // detect type and serialize
735                 $xml = '';
736                 switch(true) {
737                         case (is_bool($val) || $type == 'boolean'):
738                                 $this->debug("serialize_val: serialize boolean");
739                         if ($type == 'boolean') {
740                                 $val = $val ? 'true' : 'false';
741                         } elseif (! $val) {
742                                 $val = 0;
743                         }
744                                 if ($use == 'literal') {
745                                         $xml .= "<$name$xmlns$atts>$val</$name>";
746                                 } else {
747                                         $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
748                                 }
749                                 break;
750                         case (is_int($val) || is_long($val) || $type == 'int'):
751                                 $this->debug("serialize_val: serialize int");
752                                 if ($use == 'literal') {
753                                         $xml .= "<$name$xmlns$atts>$val</$name>";
754                                 } else {
755                                         $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
756                                 }
757                                 break;
758                         case (is_float($val)|| is_double($val) || $type == 'float'):
759                                 $this->debug("serialize_val: serialize float");
760                                 if ($use == 'literal') {
761                                         $xml .= "<$name$xmlns$atts>$val</$name>";
762                                 } else {
763                                         $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
764                                 }
765                                 break;
766                         case (is_string($val) || $type == 'string'):
767                                 $this->debug("serialize_val: serialize string");
768                                 $val = $this->expandEntities($val);
769                                 if ($use == 'literal') {
770                                         $xml .= "<$name$xmlns$atts>$val</$name>";
771                                 } else {
772                                         $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
773                                 }
774                                 break;
775                         case is_object($val):
776                                 $this->debug("serialize_val: serialize object");
777                         if (get_class($val) == 'soapval') {
778                                 $this->debug("serialize_val: serialize soapval object");
779                                 $pXml = $val->serialize($use);
780                                         $this->appendDebug($val->getDebug());
781                                         $val->clearDebug();
782                         } else {
783                                         if (! $name) {
784                                                 $name = get_class($val);
785                                                 $this->debug("In serialize_val, used class name $name as element name");
786                                         } else {
787                                                 $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
788                                         }
789                                         foreach(get_object_vars($val) as $k => $v){
790                                                 $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use);
791                                         }
792                                 }
793                                 if(isset($type) && isset($type_prefix)){
794                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
795                                 } else {
796                                         $type_str = '';
797                                 }
798                                 if ($use == 'literal') {
799                                         $xml .= "<$name$xmlns$atts>$pXml</$name>";
800                                 } else {
801                                         $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
802                                 }
803                                 break;
804                         break;
805                         case (is_array($val) || $type):
806                                 // detect if struct or array
807                                 $valueType = $this->isArraySimpleOrStruct($val);
808                 if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){
809                                         $this->debug("serialize_val: serialize array");
810                                         $i = 0;
811                                         if(is_array($val) && count($val)> 0){
812                                                 foreach($val as $v){
813                                 if(is_object($v) && get_class($v) ==  'soapval'){
814                                                                 $tt_ns = $v->type_ns;
815                                                                 $tt = $v->type;
816                                                         } elseif (is_array($v)) {
817                                                                 $tt = $this->isArraySimpleOrStruct($v);
818                                                         } else {
819                                                                 $tt = gettype($v);
820                                 }
821                                                         $array_types[$tt] = 1;
822                                                         // TODO: for literal, the name should be $name
823                                                         $xml .= $this->serialize_val($v,'item',false,false,false,false,$use);
824                                                         ++$i;
825                                                 }
826                                                 if(count($array_types) > 1){
827                                                         $array_typename = 'xsd:anyType';
828                                                 } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
829                                                         if ($tt == 'integer') {
830                                                                 $tt = 'int';
831                                                         }
832                                                         $array_typename = 'xsd:'.$tt;
833                                                 } elseif(isset($tt) && $tt == 'arraySimple'){
834                                                         $array_typename = 'SOAP-ENC:Array';
835                                                 } elseif(isset($tt) && $tt == 'arrayStruct'){
836                                                         $array_typename = 'unnamed_struct_use_soapval';
837                                                 } else {
838                                                         // if type is prefixed, create type prefix
839                                                         if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){
840                                                                  $array_typename = 'xsd:' . $tt;
841                                                         } elseif ($tt_ns) {
842                                                                 $tt_prefix = 'ns' . rand(1000, 9999);
843                                                                 $array_typename = "$tt_prefix:$tt";
844                                                                 $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
845                                                         } else {
846                                                                 $array_typename = $tt;
847                                                         }
848                                                 }
849                                                 $array_type = $i;
850                                                 if ($use == 'literal') {
851                                                         $type_str = '';
852                                                 } else if (isset($type) && isset($type_prefix)) {
853                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
854                                                 } else {
855                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\"";
856                                                 }
857                                         // empty array
858                                         } else {
859                                                 if ($use == 'literal') {
860                                                         $type_str = '';
861                                                 } else if (isset($type) && isset($type_prefix)) {
862                                                         $type_str = " xsi:type=\"$type_prefix:$type\"";
863                                                 } else {
864                                                         $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
865                                                 }
866                                         }
867                                         // TODO: for array in literal, there is no wrapper here
868                                         $xml = "<$name$xmlns$type_str$atts>".$xml."</$name>";
869                                 } else {
870                                         // got a struct
871                                         $this->debug("serialize_val: serialize struct");
872                                         if(isset($type) && isset($type_prefix)){
873                                                 $type_str = " xsi:type=\"$type_prefix:$type\"";
874                                         } else {
875                                                 $type_str = '';
876                                         }
877                                         if ($use == 'literal') {
878                                                 $xml .= "<$name$xmlns$atts>";
879                                         } else {
880                                                 $xml .= "<$name$xmlns$type_str$atts>";
881                                         }
882                                         foreach($val as $k => $v){
883                                                 // Apache Map
884                                                 if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
885                                                         $xml .= '<item>';
886                                                         $xml .= $this->serialize_val($k,'key',false,false,false,false,$use);
887                                                         $xml .= $this->serialize_val($v,'value',false,false,false,false,$use);
888                                                         $xml .= '</item>';
889                                                 } else {
890                                                         $xml .= $this->serialize_val($v,$k,false,false,false,false,$use);
891                                                 }
892                                         }
893                                         $xml .= "</$name>";
894                                 }
895                                 break;
896                         default:
897                                 $this->debug("serialize_val: serialize unknown");
898                                 $xml .= 'not detected, got '.gettype($val).' for '.$val;
899                                 break;
900                 }
901                 $this->debug("serialize_val returning $xml");
902                 return $xml;
903         }
904
905     /**
906     * serializes a message
907     *
908     * @param string $body the XML of the SOAP body
909     * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
910     * @param array $namespaces optional the namespaces used in generating the body and headers
911     * @param string $style optional (rpc|document)
912     * @param string $use optional (encoded|literal)
913     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
914     * @return string the message
915     * @access public
916     */
917     function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){
918     // TODO: add an option to automatically run utf8_encode on $body and $headers
919     // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
920     // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
921
922         $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
923         $this->debug("headers:");
924         $this->appendDebug($this->varDump($headers));
925         $this->debug("namespaces:");
926         $this->appendDebug($this->varDump($namespaces));
927
928         // serialize namespaces
929     $ns_string = '';
930         foreach(array_merge($this->namespaces,$namespaces) as $k => $v){
931                 $ns_string .= " xmlns:$k=\"$v\"";
932         }
933         if($encodingStyle) {
934                 $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
935         }
936
937         // serialize headers
938         if($headers){
939                 if (is_array($headers)) {
940                         $xml = '';
941                         foreach ($headers as $k => $v) {
942                                 if (is_object($v) && get_class($v) == 'soapval') {
943                                         $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
944                                 } else {
945                                         $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
946                                 }
947                         }
948                         $headers = $xml;
949                         $this->debug("In serializeEnvelope, serialized array of headers to $headers");
950                 }
951                 $headers = "<SOAP-ENV:Header>".$headers."</SOAP-ENV:Header>";
952         }
953         // serialize envelope
954         return
955         '<?xml version="1.0" encoding="'.$this->soap_defencoding .'"?'.">".
956         '<SOAP-ENV:Envelope'.$ns_string.">".
957         $headers.
958         "<SOAP-ENV:Body>".
959                 $body.
960         "</SOAP-ENV:Body>".
961         "</SOAP-ENV:Envelope>";
962     }
963
964         /**
965          * formats a string to be inserted into an HTML stream
966          *
967          * @param string $str The string to format
968          * @return string The formatted string
969          * @access public
970          * @deprecated
971          */
972     function formatDump($str){
973                 $str = htmlspecialchars($str);
974                 return nl2br($str);
975     }
976
977         /**
978         * contracts (changes namespace to prefix) a qualified name
979         *
980         * @param    string $qname qname
981         * @return       string contracted qname
982         * @access   private
983         */
984         function contractQname($qname){
985                 // get element namespace
986                 //$this->xdebug("Contract $qname");
987                 if (strrpos($qname, ':')) {
988                         // get unqualified name
989                         $name = substr($qname, strrpos($qname, ':') + 1);
990                         // get ns
991                         $ns = substr($qname, 0, strrpos($qname, ':'));
992                         $p = $this->getPrefixFromNamespace($ns);
993                         if ($p) {
994                                 return $p . ':' . $name;
995                         }
996                         return $qname;
997                 } else {
998                         return $qname;
999                 }
1000         }
1001
1002         /**
1003         * expands (changes prefix to namespace) a qualified name
1004         *
1005         * @param    string $qname qname
1006         * @return       string expanded qname
1007         * @access   private
1008         */
1009         function expandQname($qname){
1010                 // get element prefix
1011                 if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){
1012                         // get unqualified name
1013                         $name = substr(strstr($qname,':'),1);
1014                         // get ns prefix
1015                         $prefix = substr($qname,0,strpos($qname,':'));
1016                         if(isset($this->namespaces[$prefix])){
1017                                 return $this->namespaces[$prefix].':'.$name;
1018                         } else {
1019                                 return $qname;
1020                         }
1021                 } else {
1022                         return $qname;
1023                 }
1024         }
1025
1026     /**
1027     * returns the local part of a prefixed string
1028     * returns the original string, if not prefixed
1029     *
1030     * @param string $str The prefixed string
1031     * @return string The local part
1032     * @access public
1033     */
1034         function getLocalPart($str){
1035                 if($sstr = strrchr($str,':')){
1036                         // get unqualified name
1037                         return substr( $sstr, 1 );
1038                 } else {
1039                         return $str;
1040                 }
1041         }
1042
1043         /**
1044     * returns the prefix part of a prefixed string
1045     * returns false, if not prefixed
1046     *
1047     * @param string $str The prefixed string
1048     * @return mixed The prefix or false if there is no prefix
1049     * @access public
1050     */
1051         function getPrefix($str){
1052                 if($pos = strrpos($str,':')){
1053                         // get prefix
1054                         return substr($str,0,$pos);
1055                 }
1056                 return false;
1057         }
1058
1059         /**
1060     * pass it a prefix, it returns a namespace
1061     *
1062     * @param string $prefix The prefix
1063     * @return mixed The namespace, false if no namespace has the specified prefix
1064     * @access public
1065     */
1066         function getNamespaceFromPrefix($prefix){
1067                 if (isset($this->namespaces[$prefix])) {
1068                         return $this->namespaces[$prefix];
1069                 }
1070                 //$this->setError("No namespace registered for prefix '$prefix'");
1071                 return false;
1072         }
1073
1074         /**
1075     * returns the prefix for a given namespace (or prefix)
1076     * or false if no prefixes registered for the given namespace
1077     *
1078     * @param string $ns The namespace
1079     * @return mixed The prefix, false if the namespace has no prefixes
1080     * @access public
1081     */
1082         function getPrefixFromNamespace($ns) {
1083                 foreach ($this->namespaces as $p => $n) {
1084                         if ($ns == $n || $ns == $p) {
1085                             $this->usedNamespaces[$p] = $n;
1086                                 return $p;
1087                         }
1088                 }
1089                 return false;
1090         }
1091
1092         /**
1093     * returns the time in ODBC canonical form with microseconds
1094     *
1095     * @return string The time in ODBC canonical form with microseconds
1096     * @access public
1097     */
1098         function getmicrotime() {
1099                 if (function_exists('gettimeofday')) {
1100                         $tod = gettimeofday();
1101                         $sec = $tod['sec'];
1102                         $usec = $tod['usec'];
1103                 } else {
1104                         $sec = time();
1105                         $usec = 0;
1106                 }
1107                 return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
1108         }
1109
1110         /**
1111          * Returns a string with the output of var_dump
1112          *
1113          * @param mixed $data The variable to var_dump
1114          * @return string The output of var_dump
1115          * @access public
1116          */
1117     function varDump($data) {
1118         if ($this->debugLevel <= 0) {
1119             return '';
1120         }
1121         ob_start();
1122                 var_dump($data);
1123                 $ret_val = ob_get_contents();
1124                 ob_end_clean();
1125                 return $ret_val;
1126         }
1127
1128         /**
1129         * represents the object as a string
1130         *
1131         * @return       string
1132         * @access   public
1133         */
1134         function __toString() {
1135                 return $this->varDump($this);
1136         }
1137 }
1138
1139 // XML Schema Datatype Helper Functions
1140
1141 //xsd:dateTime helpers
1142
1143 /**
1144 * convert unix timestamp to ISO 8601 compliant date string
1145 *
1146 * @param    int $timestamp Unix time stamp
1147 * @param        boolean $utc Whether the time stamp is UTC or local
1148 * @return       mixed ISO 8601 date string or false
1149 * @access   public
1150 */
1151 function timestamp_to_iso8601($timestamp,$utc=true){
1152         $datestr = date('Y-m-d\TH:i:sO',$timestamp);
1153         $pos = strrpos($datestr, "+");
1154         if ($pos === FALSE) {
1155                 $pos = strrpos($datestr, "-");
1156         }
1157         if ($pos !== FALSE) {
1158                 if (strlen($datestr) == $pos + 5) {
1159                         $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
1160                 }
1161         }
1162         if($utc){
1163                 $pattern = '/'.
1164                 '([0-9]{4})-'.  // centuries & years CCYY-
1165                 '([0-9]{2})-'.  // months MM-
1166                 '([0-9]{2})'.   // days DD
1167                 'T'.                    // separator T
1168                 '([0-9]{2}):'.  // hours hh:
1169                 '([0-9]{2}):'.  // minutes mm:
1170                 '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss...
1171                 '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1172                 '/';
1173
1174                 if(preg_match($pattern,$datestr,$regs)){
1175                         return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]);
1176                 }
1177                 return false;
1178         } else {
1179                 return $datestr;
1180         }
1181 }
1182
1183 /**
1184 * convert ISO 8601 compliant date string to unix timestamp
1185 *
1186 * @param    string $datestr ISO 8601 compliant date string
1187 * @return       mixed Unix timestamp (int) or false
1188 * @access   public
1189 */
1190 function iso8601_to_timestamp($datestr){
1191         $pattern = '/'.
1192         '([0-9]{4})-'.  // centuries & years CCYY-
1193         '([0-9]{2})-'.  // months MM-
1194         '([0-9]{2})'.   // days DD
1195         'T'.                    // separator T
1196         '([0-9]{2}):'.  // hours hh:
1197         '([0-9]{2}):'.  // minutes mm:
1198         '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss...
1199         '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1200         '/';
1201         if(preg_match($pattern,$datestr,$regs)){
1202                 // not utc
1203                 if($regs[8] != 'Z'){
1204                         $op = substr($regs[8],0,1);
1205                         $h = substr($regs[8],1,2);
1206                         $m = substr($regs[8],strlen($regs[8])-2,2);
1207                         if($op == '-'){
1208                                 $regs[4] = $regs[4] + $h;
1209                                 $regs[5] = $regs[5] + $m;
1210                         } elseif($op == '+'){
1211                                 $regs[4] = $regs[4] - $h;
1212                                 $regs[5] = $regs[5] - $m;
1213                         }
1214                 }
1215                 return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1216 //              return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
1217         } else {
1218                 return false;
1219         }
1220 }
1221
1222 /**
1223 * sleeps some number of microseconds
1224 *
1225 * @param    string $usec the number of microseconds to sleep
1226 * @access   public
1227 * @deprecated
1228 */
1229 function usleepWindows($usec)
1230 {
1231         $start = gettimeofday();
1232
1233         do
1234         {
1235                 $stop = gettimeofday();
1236                 $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
1237                 + $stop['usec'] - $start['usec'];
1238         }
1239         while ($timePassed < $usec);
1240 }
1241
1242 ?><?php
1243
1244 /*
1245
1246 Modification information for LGPL compliance
1247
1248 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
1249     bug 40066
1250
1251 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
1252     Merging with maint_6_0_1 (svn merge -r 58250:58342)
1253
1254 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
1255     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.
1256
1257 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
1258     fix SOAP calls with no parameters
1259
1260 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
1261
1262 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
1263
1264 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
1265
1266 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
1267
1268 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
1269
1270 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.
1271
1272 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.
1273
1274 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:
1275 - Changing all ereg function to either preg or simple string based ones
1276 - No more references to magic quotes.
1277 - Change all the session_unregister() functions to just unset() the correct session variable instead.
1278
1279 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
1280
1281 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
1282
1283 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
1284
1285 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
1286
1287 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
1288
1289 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
1290
1291 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
1292
1293 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
1294
1295 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.
1296 Touched:
1297 - data/SugarBean.php
1298 - include/domit/php_http_client_generic.php
1299 - include/domit/php_http_connector.php
1300 - include/domit/testing_domit.php
1301 - include/domit/xml_domit_getelementsbypath.php
1302 - include/domit/xml_domit_lite_parser.php
1303 - include/domit/xml_domit_nodemaps.php
1304 - include/domit/xml_domit_parser.php
1305 - include/domit/xml_domit_shared.php
1306 - include/generic/SugarWidgets/SugarWidgetField.php
1307 - include/generic/SugarWidgets/SugarWidgetReportField.php
1308 - include/ListView/ProcessView.php
1309 - include/nusoap/class.soapclient.php
1310 - include/nusoap/nusoap.php
1311 - include/nusoap/nusoapmime.php
1312 - include/Pear/HTML_Safe/Safe.php
1313 - include/Pear/XML_HTMLSax3/HTMLSax3.php
1314 - modules/Administration/RebuildWorkFlow.php
1315 - modules/Expressions/RelateSelector.php
1316 - modules/Reports/templates/templates_reports.php
1317 - modules/WorkFlow/Delete.php
1318 - modules/WorkFlow/Save.php
1319 - modules/WorkFlow/SaveSequence.php
1320 - modules/WorkFlow/WorkFlow.php
1321 - modules/WorkFlowActionShells/CreateStep1.php
1322 - modules/WorkFlowActionShells/CreateStep2.php
1323 - modules/WorkFlowActionShells/Save.php
1324 - modules/WorkFlowActionShells/WorkFlowActionShell.php
1325 - modules/WorkFlowAlerts/Save.php
1326 - modules/WorkFlowAlerts/WorkFlowAlert.php
1327 - modules/WorkFlowAlertShells/DetailView.php
1328 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
1329 - modules/WorkFlowTriggerShells/CreateStep1.php
1330 - modules/WorkFlowTriggerShells/CreateStepFilter.php
1331 - modules/WorkFlowTriggerShells/SaveFilter.php
1332 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
1333 - soap/SoapHelperFunctions.php
1334 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
1335 - test/simpletest/browser.php
1336 - test/simpletest/default_reporter.php
1337 - test/simpletest/detached.php
1338 - test/simpletest/eclipse.php
1339 - test/simpletest/expectation.php
1340 - test/simpletest/extensions/pear_test_case.php
1341 - test/simpletest/form.php
1342 - test/simpletest/http.php
1343 - test/simpletest/mock_objects.php
1344 - test/simpletest/page.php
1345 - test/simpletest/parser.php
1346 - test/simpletest/remote.php
1347 - test/simpletest/shell_tester.php
1348 - test/simpletest/simple_test.php
1349 - test/simpletest/simpletest.php
1350 - test/simpletest/test/acceptance_test.php
1351 - test/simpletest/test/adapter_test.php
1352 - test/simpletest/test/authentication_test.php
1353 - test/simpletest/test/browser_test.php
1354 - test/simpletest/test/collector_test.php
1355 - test/simpletest/test/compatibility_test.php
1356 - test/simpletest/test/detached_test.php
1357 - test/simpletest/test/eclipse_test.php
1358 - test/simpletest/test/encoding_test.php
1359 - test/simpletest/test/errors_test.php
1360 - test/simpletest/test/expectation_test.php
1361 - test/simpletest/test/form_test.php
1362 - test/simpletest/test/frames_test.php
1363 - test/simpletest/test/http_test.php
1364 - test/simpletest/test/live_test.php
1365 - test/simpletest/test/mock_objects_test.php
1366 - test/simpletest/test/page_test.php
1367 - test/simpletest/test/parse_error_test.php
1368 - test/simpletest/test/parser_test.php
1369 - test/simpletest/test/remote_test.php
1370 - test/simpletest/test/shell_test.php
1371 - test/simpletest/test/shell_tester_test.php
1372 - test/simpletest/test/simpletest_test.php
1373 - test/simpletest/test/site/page_request.php
1374 - test/simpletest/test/tag_test.php
1375 - test/simpletest/test/unit_tester_test.php
1376 - test/simpletest/test/user_agent_test.php
1377 - test/simpletest/test/visual_test.php
1378 - test/simpletest/test/xml_test.php
1379 - test/simpletest/test_case.php
1380 - test/simpletest/ui/array_reporter/test.php
1381 - test/simpletest/ui/recorder/test.php
1382 - test/simpletest/unit_tester.php
1383 - test/simpletest/url.php
1384 - test/simpletest/user_agent.php
1385 - test/simpletest/web_tester.php
1386 - test/spikephpcoverage/src/PEAR.php
1387 - test/spikephpcoverage/src/util/Utility.php
1388 - test/spikephpcoverage/src/XML/Parser.php
1389 - test/spikephpcoverage/src/XML/Parser/Simple.php
1390 - test/test_utilities/SugarTest_SimpleBrowser.php
1391
1392 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.
1393
1394 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
1395
1396 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
1397
1398 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
1399
1400 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
1401
1402 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
1403
1404 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
1405
1406 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
1407
1408 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
1409
1410 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
1411
1412 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
1413
1414 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
1415
1416 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.
1417
1418 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
1419
1420 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
1421
1422 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
1423
1424 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
1425
1426 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
1427
1428 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
1429
1430 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
1431
1432 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
1433
1434 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
1435
1436 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
1437
1438 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
1439
1440
1441 */
1442
1443
1444
1445
1446
1447 /**
1448 * Contains information for a SOAP fault.
1449 * Mainly used for returning faults from deployed functions
1450 * in a server instance.
1451 * @author   Dietrich Ayala <dietrich@ganx4.com>
1452
1453 * @access public
1454 */
1455 class nusoap_fault extends nusoap_base {
1456         /**
1457          * The fault code (client|server)
1458          * @var string
1459          * @access private
1460          */
1461         var $faultcode;
1462         /**
1463          * The fault actor
1464          * @var string
1465          * @access private
1466          */
1467         var $faultactor;
1468         /**
1469          * The fault string, a description of the fault
1470          * @var string
1471          * @access private
1472          */
1473         var $faultstring;
1474         /**
1475          * The fault detail, typically a string or array of string
1476          * @var mixed
1477          * @access private
1478          */
1479         var $faultdetail;
1480
1481         /**
1482         * constructor
1483     *
1484     * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
1485     * @param string $faultactor only used when msg routed between multiple actors
1486     * @param string $faultstring human readable error message
1487     * @param mixed $faultdetail detail, typically a string or array of string
1488         */
1489         function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){
1490                 parent::nusoap_base();
1491                 $this->faultcode = $faultcode;
1492                 $this->faultactor = $faultactor;
1493                 $this->faultstring = $faultstring;
1494                 $this->faultdetail = $faultdetail;
1495         }
1496
1497         /**
1498         * serialize a fault
1499         *
1500         * @return       string  The serialization of the fault instance.
1501         * @access   public
1502         */
1503         function serialize(){
1504                 $ns_string = '';
1505                 foreach($this->namespaces as $k => $v){
1506                         $ns_string .= "\n  xmlns:$k=\"$v\"";
1507                 }
1508                 $return_msg =
1509                         '<?xml version="1.0" encoding="'.$this->soap_defencoding.'"?>'.
1510                         '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'.$ns_string.">\n".
1511                                 '<SOAP-ENV:Body>'.
1512                                 '<SOAP-ENV:Fault>'.
1513                                         $this->serialize_val($this->faultcode, 'faultcode').
1514                                         $this->serialize_val($this->faultactor, 'faultactor').
1515                                         $this->serialize_val($this->faultstring, 'faultstring').
1516                                         $this->serialize_val($this->faultdetail, 'detail').
1517                                 '</SOAP-ENV:Fault>'.
1518                                 '</SOAP-ENV:Body>'.
1519                         '</SOAP-ENV:Envelope>';
1520                 return $return_msg;
1521         }
1522 }
1523
1524 /**
1525  * Backward compatibility
1526  */
1527 class soap_fault extends nusoap_fault {
1528 }
1529
1530 ?><?php
1531
1532 /*
1533
1534 Modification information for LGPL compliance
1535
1536 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
1537     bug 40066
1538
1539 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
1540     Merging with maint_6_0_1 (svn merge -r 58250:58342)
1541
1542 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
1543     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.
1544
1545 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
1546     fix SOAP calls with no parameters
1547
1548 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
1549
1550 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
1551
1552 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
1553
1554 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
1555
1556 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
1557
1558 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.
1559
1560 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.
1561
1562 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:
1563 - Changing all ereg function to either preg or simple string based ones
1564 - No more references to magic quotes.
1565 - Change all the session_unregister() functions to just unset() the correct session variable instead.
1566
1567 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
1568
1569 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
1570
1571 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
1572
1573 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
1574
1575 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
1576
1577 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
1578
1579 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
1580
1581 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
1582
1583 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.
1584 Touched:
1585 - data/SugarBean.php
1586 - include/domit/php_http_client_generic.php
1587 - include/domit/php_http_connector.php
1588 - include/domit/testing_domit.php
1589 - include/domit/xml_domit_getelementsbypath.php
1590 - include/domit/xml_domit_lite_parser.php
1591 - include/domit/xml_domit_nodemaps.php
1592 - include/domit/xml_domit_parser.php
1593 - include/domit/xml_domit_shared.php
1594 - include/generic/SugarWidgets/SugarWidgetField.php
1595 - include/generic/SugarWidgets/SugarWidgetReportField.php
1596 - include/ListView/ProcessView.php
1597 - include/nusoap/class.soapclient.php
1598 - include/nusoap/nusoap.php
1599 - include/nusoap/nusoapmime.php
1600 - include/Pear/HTML_Safe/Safe.php
1601 - include/Pear/XML_HTMLSax3/HTMLSax3.php
1602 - modules/Administration/RebuildWorkFlow.php
1603 - modules/Expressions/RelateSelector.php
1604 - modules/Reports/templates/templates_reports.php
1605 - modules/WorkFlow/Delete.php
1606 - modules/WorkFlow/Save.php
1607 - modules/WorkFlow/SaveSequence.php
1608 - modules/WorkFlow/WorkFlow.php
1609 - modules/WorkFlowActionShells/CreateStep1.php
1610 - modules/WorkFlowActionShells/CreateStep2.php
1611 - modules/WorkFlowActionShells/Save.php
1612 - modules/WorkFlowActionShells/WorkFlowActionShell.php
1613 - modules/WorkFlowAlerts/Save.php
1614 - modules/WorkFlowAlerts/WorkFlowAlert.php
1615 - modules/WorkFlowAlertShells/DetailView.php
1616 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
1617 - modules/WorkFlowTriggerShells/CreateStep1.php
1618 - modules/WorkFlowTriggerShells/CreateStepFilter.php
1619 - modules/WorkFlowTriggerShells/SaveFilter.php
1620 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
1621 - soap/SoapHelperFunctions.php
1622 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
1623 - test/simpletest/browser.php
1624 - test/simpletest/default_reporter.php
1625 - test/simpletest/detached.php
1626 - test/simpletest/eclipse.php
1627 - test/simpletest/expectation.php
1628 - test/simpletest/extensions/pear_test_case.php
1629 - test/simpletest/form.php
1630 - test/simpletest/http.php
1631 - test/simpletest/mock_objects.php
1632 - test/simpletest/page.php
1633 - test/simpletest/parser.php
1634 - test/simpletest/remote.php
1635 - test/simpletest/shell_tester.php
1636 - test/simpletest/simple_test.php
1637 - test/simpletest/simpletest.php
1638 - test/simpletest/test/acceptance_test.php
1639 - test/simpletest/test/adapter_test.php
1640 - test/simpletest/test/authentication_test.php
1641 - test/simpletest/test/browser_test.php
1642 - test/simpletest/test/collector_test.php
1643 - test/simpletest/test/compatibility_test.php
1644 - test/simpletest/test/detached_test.php
1645 - test/simpletest/test/eclipse_test.php
1646 - test/simpletest/test/encoding_test.php
1647 - test/simpletest/test/errors_test.php
1648 - test/simpletest/test/expectation_test.php
1649 - test/simpletest/test/form_test.php
1650 - test/simpletest/test/frames_test.php
1651 - test/simpletest/test/http_test.php
1652 - test/simpletest/test/live_test.php
1653 - test/simpletest/test/mock_objects_test.php
1654 - test/simpletest/test/page_test.php
1655 - test/simpletest/test/parse_error_test.php
1656 - test/simpletest/test/parser_test.php
1657 - test/simpletest/test/remote_test.php
1658 - test/simpletest/test/shell_test.php
1659 - test/simpletest/test/shell_tester_test.php
1660 - test/simpletest/test/simpletest_test.php
1661 - test/simpletest/test/site/page_request.php
1662 - test/simpletest/test/tag_test.php
1663 - test/simpletest/test/unit_tester_test.php
1664 - test/simpletest/test/user_agent_test.php
1665 - test/simpletest/test/visual_test.php
1666 - test/simpletest/test/xml_test.php
1667 - test/simpletest/test_case.php
1668 - test/simpletest/ui/array_reporter/test.php
1669 - test/simpletest/ui/recorder/test.php
1670 - test/simpletest/unit_tester.php
1671 - test/simpletest/url.php
1672 - test/simpletest/user_agent.php
1673 - test/simpletest/web_tester.php
1674 - test/spikephpcoverage/src/PEAR.php
1675 - test/spikephpcoverage/src/util/Utility.php
1676 - test/spikephpcoverage/src/XML/Parser.php
1677 - test/spikephpcoverage/src/XML/Parser/Simple.php
1678 - test/test_utilities/SugarTest_SimpleBrowser.php
1679
1680 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.
1681
1682 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
1683
1684 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
1685
1686 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
1687
1688 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
1689
1690 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
1691
1692 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
1693
1694 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
1695
1696 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
1697
1698 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
1699
1700 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
1701
1702 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
1703
1704 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.
1705
1706 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
1707
1708 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
1709
1710 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
1711
1712 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
1713
1714 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
1715
1716 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
1717
1718 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
1719
1720 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
1721
1722 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
1723
1724 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
1725
1726 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
1727
1728
1729 */
1730
1731
1732
1733
1734
1735 /**
1736 * parses an XML Schema, allows access to it's data, other utility methods.
1737 * imperfect, no validation... yet, but quite functional.
1738 *
1739 * @author   Dietrich Ayala <dietrich@ganx4.com>
1740 * @author   Scott Nichol <snichol@users.sourceforge.net>
1741
1742 * @access   public
1743 */
1744 class nusoap_xmlschema extends nusoap_base  {
1745
1746         // files
1747         var $schema = '';
1748         var $xml = '';
1749         // namespaces
1750         var $enclosingNamespaces;
1751         // schema info
1752         var $schemaInfo = array();
1753         var $schemaTargetNamespace = '';
1754         // types, elements, attributes defined by the schema
1755         var $attributes = array();
1756         var $complexTypes = array();
1757         var $complexTypeStack = array();
1758         var $currentComplexType = null;
1759         var $elements = array();
1760         var $elementStack = array();
1761         var $currentElement = null;
1762         var $simpleTypes = array();
1763         var $simpleTypeStack = array();
1764         var $currentSimpleType = null;
1765         // imports
1766         var $imports = array();
1767         // parser vars
1768         var $parser;
1769         var $position = 0;
1770         var $depth = 0;
1771         var $depth_array = array();
1772         var $message = array();
1773         var $defaultNamespace = array();
1774
1775         /**
1776         * constructor
1777         *
1778         * @param    string $schema schema document URI
1779         * @param    string $xml xml document URI
1780         * @param        string $namespaces namespaces defined in enclosing XML
1781         * @access   public
1782         */
1783         function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){
1784                 parent::nusoap_base();
1785                 $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1786                 // files
1787                 $this->schema = $schema;
1788                 $this->xml = $xml;
1789
1790                 // namespaces
1791                 $this->enclosingNamespaces = $namespaces;
1792                 $this->namespaces = array_merge($this->namespaces, $namespaces);
1793
1794                 // parse schema file
1795                 if($schema != ''){
1796                         $this->debug('initial schema file: '.$schema);
1797                         $this->parseFile($schema, 'schema');
1798                 }
1799
1800                 // parse xml file
1801                 if($xml != ''){
1802                         $this->debug('initial xml file: '.$xml);
1803                         $this->parseFile($xml, 'xml');
1804                 }
1805
1806         }
1807
1808     /**
1809     * parse an XML file
1810     *
1811     * @param string $xml path/URL to XML file
1812     * @param string $type (schema | xml)
1813         * @return boolean
1814     * @access public
1815     */
1816         function parseFile($xml,$type){
1817                 // parse xml file
1818                 if($xml != ""){
1819                         $xmlStr = @join("",@file($xml));
1820                         if($xmlStr == ""){
1821                                 $msg = 'Error reading XML from '.$xml;
1822                                 $this->setError($msg);
1823                                 $this->debug($msg);
1824                         return false;
1825                         } else {
1826                                 $this->debug("parsing $xml");
1827                                 $this->parseString($xmlStr,$type);
1828                                 $this->debug("done parsing $xml");
1829                         return true;
1830                         }
1831                 }
1832                 return false;
1833         }
1834
1835         /**
1836         * parse an XML string
1837         *
1838         * @param    string $xml path or URL
1839     * @param    string $type (schema|xml)
1840         * @access   private
1841         */
1842         function parseString($xml,$type){
1843                 // parse xml string
1844                 if($xml != ""){
1845
1846                 // Create an XML parser.
1847                 $this->parser = xml_parser_create();
1848                 // Set the options for parsing the XML data.
1849                 xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1850
1851                 // Set the object for the parser.
1852                 xml_set_object($this->parser, $this);
1853
1854                 // Set the element handlers for the parser.
1855                         if($type == "schema"){
1856                         xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement');
1857                         xml_set_character_data_handler($this->parser,'schemaCharacterData');
1858                         } elseif($type == "xml"){
1859                                 xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement');
1860                         xml_set_character_data_handler($this->parser,'xmlCharacterData');
1861                         }
1862
1863                     // Parse the XML file.
1864                     if(!xml_parse($this->parser,$xml,true)){
1865                         // Display an error message.
1866                                 $errstr = sprintf('XML error parsing XML schema on line %d: %s',
1867                                 xml_get_current_line_number($this->parser),
1868                                 xml_error_string(xml_get_error_code($this->parser))
1869                                 );
1870                                 $this->debug($errstr);
1871                                 $this->debug("XML payload:\n" . $xml);
1872                                 $this->setError($errstr);
1873                 }
1874
1875                         xml_parser_free($this->parser);
1876                 } else{
1877                         $this->debug('no xml passed to parseString()!!');
1878                         $this->setError('no xml passed to parseString()!!');
1879                 }
1880         }
1881
1882         /**
1883          * gets a type name for an unnamed type
1884          *
1885          * @param       string  Element name
1886          * @return      string  A type name for an unnamed type
1887          * @access      private
1888          */
1889         function CreateTypeName($ename) {
1890                 $scope = '';
1891                 for ($i = 0; $i < count($this->complexTypeStack); $i++) {
1892                         $scope .= $this->complexTypeStack[$i] . '_';
1893                 }
1894                 return $scope . $ename . '_ContainedType';
1895         }
1896
1897         /**
1898         * start-element handler
1899         *
1900         * @param    string $parser XML parser object
1901         * @param    string $name element name
1902         * @param    string $attrs associative array of attributes
1903         * @access   private
1904         */
1905         function schemaStartElement($parser, $name, $attrs) {
1906
1907                 // position in the total number of elements, starting from 0
1908                 $pos = $this->position++;
1909                 $depth = $this->depth++;
1910                 // set self as current value for this depth
1911                 $this->depth_array[$depth] = $pos;
1912                 $this->message[$pos] = array('cdata' => '');
1913                 if ($depth > 0) {
1914                         $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1915                 } else {
1916                         $this->defaultNamespace[$pos] = false;
1917                 }
1918
1919                 // get element prefix
1920                 if($prefix = $this->getPrefix($name)){
1921                         // get unqualified name
1922                         $name = $this->getLocalPart($name);
1923                 } else {
1924                 $prefix = '';
1925         }
1926
1927         // loop thru attributes, expanding, and registering namespace declarations
1928         if(count($attrs) > 0){
1929                 foreach($attrs as $k => $v){
1930                 // if ns declarations, add to class level array of valid namespaces
1931                                 if(preg_match('/^xmlns/',$k)){
1932                         //$this->xdebug("$k: $v");
1933                         //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
1934                         if($ns_prefix = substr(strrchr($k,':'),1)){
1935                                 //$this->xdebug("Add namespace[$ns_prefix] = $v");
1936                                                 $this->namespaces[$ns_prefix] = $v;
1937                                         } else {
1938                                                 $this->defaultNamespace[$pos] = $v;
1939                                                 if (! $this->getPrefixFromNamespace($v)) {
1940                                                         $this->namespaces['ns'.(count($this->namespaces)+1)] = $v;
1941                                                 }
1942                                         }
1943                                         if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){
1944                                                 $this->XMLSchemaVersion = $v;
1945                                                 $this->namespaces['xsi'] = $v.'-instance';
1946                                         }
1947                                 }
1948                 }
1949                 foreach($attrs as $k => $v){
1950                 // expand each attribute
1951                 $k = strpos($k,':') ? $this->expandQname($k) : $k;
1952                 $v = strpos($v,':') ? $this->expandQname($v) : $v;
1953                         $eAttrs[$k] = $v;
1954                 }
1955                 $attrs = $eAttrs;
1956         } else {
1957                 $attrs = array();
1958         }
1959                 // find status, register data
1960                 switch($name){
1961                         case 'all':                     // (optional) compositor content for a complexType
1962                         case 'choice':
1963                         case 'group':
1964                         case 'sequence':
1965                                 //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
1966                                 $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1967                                 //if($name == 'all' || $name == 'sequence'){
1968                                 //      $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1969                                 //}
1970                         break;
1971                         case 'attribute':       // complexType attribute
1972                 //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
1973                 $this->xdebug("parsing attribute:");
1974                 $this->appendDebug($this->varDump($attrs));
1975                                 if (!isset($attrs['form'])) {
1976                                         // TODO: handle globals
1977                                         $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1978                                 }
1979                 if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1980                                         $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1981                                         if (!strpos($v, ':')) {
1982                                                 // no namespace in arrayType attribute value...
1983                                                 if ($this->defaultNamespace[$pos]) {
1984                                                         // ...so use the default
1985                                                         $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1986                                                 }
1987                                         }
1988                 }
1989                 if(isset($attrs['name'])){
1990                                         $this->attributes[$attrs['name']] = $attrs;
1991                                         $aname = $attrs['name'];
1992                                 } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){
1993                                         if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1994                                 $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1995                         } else {
1996                                 $aname = '';
1997                         }
1998                                 } elseif(isset($attrs['ref'])){
1999                                         $aname = $attrs['ref'];
2000                     $this->attributes[$attrs['ref']] = $attrs;
2001                                 }
2002
2003                                 if($this->currentComplexType){  // This should *always* be
2004                                         $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
2005                                 }
2006                                 // arrayType attribute
2007                                 if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){
2008                                         $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2009                         $prefix = $this->getPrefix($aname);
2010                                         if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){
2011                                                 $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
2012                                         } else {
2013                                                 $v = '';
2014                                         }
2015                     if(strpos($v,'[,]')){
2016                         $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
2017                     }
2018                     $v = substr($v,0,strpos($v,'[')); // clip the []
2019                     if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){
2020                         $v = $this->XMLSchemaVersion.':'.$v;
2021                     }
2022                     $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
2023                                 }
2024                         break;
2025                         case 'complexContent':  // (optional) content for a complexType
2026                                 $this->xdebug("do nothing for element $name");
2027                         break;
2028                         case 'complexType':
2029                                 array_push($this->complexTypeStack, $this->currentComplexType);
2030                                 if(isset($attrs['name'])){
2031                                         // TODO: what is the scope of named complexTypes that appear
2032                                         //       nested within other c complexTypes?
2033                                         $this->xdebug('processing named complexType '.$attrs['name']);
2034                                         //$this->currentElement = false;
2035                                         $this->currentComplexType = $attrs['name'];
2036                                         $this->complexTypes[$this->currentComplexType] = $attrs;
2037                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
2038                                         // This is for constructs like
2039                                         //           <complexType name="ListOfString" base="soap:Array">
2040                                         //                <sequence>
2041                                         //                    <element name="string" type="xsd:string"
2042                                         //                        minOccurs="0" maxOccurs="unbounded" />
2043                                         //                </sequence>
2044                                         //            </complexType>
2045                                         if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
2046                                                 $this->xdebug('complexType is unusual array');
2047                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2048                                         } else {
2049                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
2050                                         }
2051                                 } else {
2052                                         $name = $this->CreateTypeName($this->currentElement);
2053                                         $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
2054                                         $this->currentComplexType = $name;
2055                                         //$this->currentElement = false;
2056                                         $this->complexTypes[$this->currentComplexType] = $attrs;
2057                                         $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
2058                                         // This is for constructs like
2059                                         //           <complexType name="ListOfString" base="soap:Array">
2060                                         //                <sequence>
2061                                         //                    <element name="string" type="xsd:string"
2062                                         //                        minOccurs="0" maxOccurs="unbounded" />
2063                                         //                </sequence>
2064                                         //            </complexType>
2065                                         if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){
2066                                                 $this->xdebug('complexType is unusual array');
2067                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2068                                         } else {
2069                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
2070                                         }
2071                                 }
2072                                 $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
2073                         break;
2074                         case 'element':
2075                                 array_push($this->elementStack, $this->currentElement);
2076                                 if (!isset($attrs['form'])) {
2077                                         if ($this->currentComplexType) {
2078                                                 $attrs['form'] = $this->schemaInfo['elementFormDefault'];
2079                                         } else {
2080                                                 // global
2081                                                 $attrs['form'] = 'qualified';
2082                                         }
2083                                 }
2084                                 if(isset($attrs['type'])){
2085                                         $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']);
2086                                         if (! $this->getPrefix($attrs['type'])) {
2087                                                 if ($this->defaultNamespace[$pos]) {
2088                                                         $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
2089                                                         $this->xdebug('used default namespace to make type ' . $attrs['type']);
2090                                                 }
2091                                         }
2092                                         // This is for constructs like
2093                                         //           <complexType name="ListOfString" base="soap:Array">
2094                                         //                <sequence>
2095                                         //                    <element name="string" type="xsd:string"
2096                                         //                        minOccurs="0" maxOccurs="unbounded" />
2097                                         //                </sequence>
2098                                         //            </complexType>
2099                                         if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
2100                                                 $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
2101                                                 $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
2102                                         }
2103                                         $this->currentElement = $attrs['name'];
2104                                         $ename = $attrs['name'];
2105                                 } elseif(isset($attrs['ref'])){
2106                                         $this->xdebug("processing element as ref to ".$attrs['ref']);
2107                                         $this->currentElement = "ref to ".$attrs['ref'];
2108                                         $ename = $this->getLocalPart($attrs['ref']);
2109                                 } else {
2110                                         $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
2111                                         $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
2112                                         $this->currentElement = $attrs['name'];
2113                                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
2114                                         $ename = $attrs['name'];
2115                                 }
2116                                 if (isset($ename) && $this->currentComplexType) {
2117                                         $this->xdebug("add element $ename to complexType $this->currentComplexType");
2118                                         $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
2119                                 } elseif (!isset($attrs['ref'])) {
2120                                         $this->xdebug("add element $ename to elements array");
2121                                         $this->elements[ $attrs['name'] ] = $attrs;
2122                                         $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2123                                 }
2124                         break;
2125                         case 'enumeration':     //      restriction value list member
2126                                 $this->xdebug('enumeration ' . $attrs['value']);
2127                                 if ($this->currentSimpleType) {
2128                                         $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
2129                                 } elseif ($this->currentComplexType) {
2130                                         $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
2131                                 }
2132                         break;
2133                         case 'extension':       // simpleContent or complexContent type extension
2134                                 $this->xdebug('extension ' . $attrs['base']);
2135                                 if ($this->currentComplexType) {
2136                                         $ns = $this->getPrefix($attrs['base']);
2137                                         if ($ns == '') {
2138                                                 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
2139                                         } else {
2140                                                 $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
2141                                         }
2142                                 } else {
2143                                         $this->xdebug('no current complexType to set extensionBase');
2144                                 }
2145                         break;
2146                         case 'import':
2147                             if (isset($attrs['schemaLocation'])) {
2148                                         $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
2149                     $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
2150                                 } else {
2151                                         $this->xdebug('import namespace ' . $attrs['namespace']);
2152                     $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
2153                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
2154                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
2155                                         }
2156                                 }
2157                         break;
2158                         case 'include':
2159                             if (isset($attrs['schemaLocation'])) {
2160                                         $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
2161                     $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
2162                                 } else {
2163                                         $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
2164                                 }
2165                         break;
2166                         case 'list':    // simpleType value list
2167                                 $this->xdebug("do nothing for element $name");
2168                         break;
2169                         case 'restriction':     // simpleType, simpleContent or complexContent value restriction
2170                                 $this->xdebug('restriction ' . $attrs['base']);
2171                                 if($this->currentSimpleType){
2172                                         $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
2173                                 } elseif($this->currentComplexType){
2174                                         $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
2175                                         if(strstr($attrs['base'],':') == ':Array'){
2176                                                 $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
2177                                         }
2178                                 }
2179                         break;
2180                         case 'schema':
2181                                 $this->schemaInfo = $attrs;
2182                                 $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
2183                                 if (isset($attrs['targetNamespace'])) {
2184                                         $this->schemaTargetNamespace = $attrs['targetNamespace'];
2185                                 }
2186                                 if (!isset($attrs['elementFormDefault'])) {
2187                                         $this->schemaInfo['elementFormDefault'] = 'unqualified';
2188                                 }
2189                                 if (!isset($attrs['attributeFormDefault'])) {
2190                                         $this->schemaInfo['attributeFormDefault'] = 'unqualified';
2191                                 }
2192                         break;
2193                         case 'simpleContent':   // (optional) content for a complexType
2194                                 if ($this->currentComplexType) {        // This should *always* be
2195                                         $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
2196                                 } else {
2197                                         $this->xdebug("do nothing for element $name because there is no current complexType");
2198                                 }
2199                         break;
2200                         case 'simpleType':
2201                                 array_push($this->simpleTypeStack, $this->currentSimpleType);
2202                                 if(isset($attrs['name'])){
2203                                         $this->xdebug("processing simpleType for name " . $attrs['name']);
2204                                         $this->currentSimpleType = $attrs['name'];
2205                                         $this->simpleTypes[ $attrs['name'] ] = $attrs;
2206                                         $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType';
2207                                         $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar';
2208                                 } else {
2209                                         $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
2210                                         $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
2211                                         $this->currentSimpleType = $name;
2212                                         //$this->currentElement = false;
2213                                         $this->simpleTypes[$this->currentSimpleType] = $attrs;
2214                                         $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
2215                                 }
2216                         break;
2217                         case 'union':   // simpleType type list
2218                                 $this->xdebug("do nothing for element $name");
2219                         break;
2220                         default:
2221                                 $this->xdebug("do not have any logic to process element $name");
2222                 }
2223         }
2224
2225         /**
2226         * end-element handler
2227         *
2228         * @param    string $parser XML parser object
2229         * @param    string $name element name
2230         * @access   private
2231         */
2232         function schemaEndElement($parser, $name) {
2233                 // bring depth down a notch
2234                 $this->depth--;
2235                 // position of current element is equal to the last value left in depth_array for my depth
2236                 if(isset($this->depth_array[$this->depth])){
2237                 $pos = $this->depth_array[$this->depth];
2238         }
2239                 // get element prefix
2240                 if ($prefix = $this->getPrefix($name)){
2241                         // get unqualified name
2242                         $name = $this->getLocalPart($name);
2243                 } else {
2244                 $prefix = '';
2245         }
2246                 // move on...
2247                 if($name == 'complexType'){
2248                         $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
2249                         $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
2250                         $this->currentComplexType = array_pop($this->complexTypeStack);
2251                         //$this->currentElement = false;
2252                 }
2253                 if($name == 'element'){
2254                         $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
2255                         $this->currentElement = array_pop($this->elementStack);
2256                 }
2257                 if($name == 'simpleType'){
2258                         $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
2259                         $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
2260                         $this->currentSimpleType = array_pop($this->simpleTypeStack);
2261                 }
2262         }
2263
2264         /**
2265         * element content handler
2266         *
2267         * @param    string $parser XML parser object
2268         * @param    string $data element content
2269         * @access   private
2270         */
2271         function schemaCharacterData($parser, $data){
2272                 $pos = $this->depth_array[$this->depth - 1];
2273                 $this->message[$pos]['cdata'] .= $data;
2274         }
2275
2276         /**
2277         * serialize the schema
2278         *
2279         * @access   public
2280         */
2281         function serializeSchema(){
2282
2283                 $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
2284                 $xml = '';
2285                 // imports
2286                 $schemaLocationCount = 0;
2287                 if (sizeof($this->imports) > 0) {
2288                         foreach($this->imports as $ns => $list) {
2289                                 foreach ($list as $ii) {
2290                                         if ($ii['location'] != '') {
2291                                                 $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
2292                                         } else {
2293                                                 if ($schemaLocationCount == 0) {
2294                                                         $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" schemaLocation=\"" . $ns . "\"/>\n";
2295                                                 } else {
2296                                                         $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
2297                                                 }
2298                                         }
2299                                 }
2300                         }
2301                 }
2302                 // complex types
2303                 foreach($this->complexTypes as $typeName => $attrs){
2304                         $contentStr = '';
2305                         // serialize child elements
2306                         if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){
2307                                 foreach($attrs['elements'] as $element => $eParts){
2308                                         if(isset($eParts['ref'])){
2309                                                 $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
2310                                         } else {
2311                                                 $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
2312                                                 foreach ($eParts as $aName => $aValue) {
2313                                                         // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
2314                                                         if ($aName != 'name' && $aName != 'type') {
2315                                                                 $contentStr .= " $aName=\"$aValue\"";
2316                                                         }
2317                                                 }
2318                                                 $contentStr .= "/>\n";
2319                                         }
2320                                 }
2321                                 // compositor wraps elements
2322                                 if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
2323                                         $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n".$contentStr."  </$schemaPrefix:$attrs[compositor]>\n";
2324                                 }
2325                         }
2326                         // attributes
2327                         if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){
2328                                 foreach($attrs['attrs'] as $attr => $aParts){
2329                                         $contentStr .= "    <$schemaPrefix:attribute";
2330                                         foreach ($aParts as $a => $v) {
2331                                                 if ($a == 'ref' || $a == 'type') {
2332                                                         $contentStr .= " $a=\"".$this->contractQName($v).'"';
2333                                                 } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
2334                                                         $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
2335                                                         $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"';
2336                                                 } else {
2337                                                         $contentStr .= " $a=\"$v\"";
2338                                                 }
2339                                         }
2340                                         $contentStr .= "/>\n";
2341                                 }
2342                         }
2343                         // if restriction
2344                         if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){
2345                                 $contentStr = "   <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr."   </$schemaPrefix:restriction>\n";
2346                                 // complex or simple content
2347                                 if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){
2348                                         $contentStr = "  <$schemaPrefix:complexContent>\n".$contentStr."  </$schemaPrefix:complexContent>\n";
2349                                 }
2350                         }
2351                         // finalize complex type
2352                         if($contentStr != ''){
2353                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." </$schemaPrefix:complexType>\n";
2354                         } else {
2355                                 $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
2356                         }
2357                         $xml .= $contentStr;
2358                 }
2359                 // simple types
2360                 if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){
2361                         foreach($this->simpleTypes as $typeName => $eParts){
2362                                 $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n";
2363                                 if (isset($eParts['enumeration'])) {
2364                                         foreach ($eParts['enumeration'] as $e) {
2365                                                 $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
2366                                         }
2367                                 }
2368                                 $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
2369                         }
2370                 }
2371                 // elements
2372                 if(isset($this->elements) && count($this->elements) > 0){
2373                         foreach($this->elements as $element => $eParts){
2374                                 $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n";
2375                         }
2376                 }
2377                 // attributes
2378                 if(isset($this->attributes) && count($this->attributes) > 0){
2379                         foreach($this->attributes as $attr => $aParts){
2380                                 $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>";
2381                         }
2382                 }
2383                 // finish 'er up
2384                 $attr = '';
2385                 foreach ($this->schemaInfo as $k => $v) {
2386                         if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
2387                                 $attr .= " $k=\"$v\"";
2388                         }
2389                 }
2390                 $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
2391                 foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
2392                         $el .= " xmlns:$nsp=\"$ns\"";
2393                 }
2394                 $xml = $el . ">\n".$xml."</$schemaPrefix:schema>\n";
2395                 return $xml;
2396         }
2397
2398         /**
2399         * adds debug data to the clas level debug string
2400         *
2401         * @param    string $string debug data
2402         * @access   private
2403         */
2404         function xdebug($string){
2405             if($this->debugLevel > 0) {
2406                     $this->debug('<' . $this->schemaTargetNamespace . '> '.$string);
2407             }
2408         }
2409
2410     /**
2411     * get the PHP type of a user defined type in the schema
2412     * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
2413     * returns false if no type exists, or not w/ the given namespace
2414     * else returns a string that is either a native php type, or 'struct'
2415     *
2416     * @param string $type name of defined type
2417     * @param string $ns namespace of type
2418     * @return mixed
2419     * @access public
2420     * @deprecated
2421     */
2422         function getPHPType($type,$ns){
2423                 if(isset($this->typemap[$ns][$type])){
2424                         //print "found type '$type' and ns $ns in typemap<br>";
2425                         return $this->typemap[$ns][$type];
2426                 } elseif(isset($this->complexTypes[$type])){
2427                         //print "getting type '$type' and ns $ns from complexTypes array<br>";
2428                         return $this->complexTypes[$type]['phpType'];
2429                 }
2430                 return false;
2431         }
2432
2433         /**
2434     * returns an associative array of information about a given type
2435     * returns false if no type exists by the given name
2436     *
2437         *       For a complexType typeDef = array(
2438         *       'restrictionBase' => '',
2439         *       'phpType' => '',
2440         *       'compositor' => '(sequence|all)',
2441         *       'elements' => array(), // refs to elements array
2442         *       'attrs' => array() // refs to attributes array
2443         *       ... and so on (see addComplexType)
2444         *       )
2445         *
2446         *   For simpleType or element, the array has different keys.
2447     *
2448     * @param string $type
2449     * @return mixed
2450     * @access public
2451     * @see addComplexType
2452     * @see addSimpleType
2453     * @see addElement
2454     */
2455         function getTypeDef($type){
2456                 //$this->debug("in getTypeDef for type $type");
2457                 if (substr($type, -1) == '^') {
2458                         $is_element = 1;
2459                         $type = substr($type, 0, -1);
2460                 } else {
2461                         $is_element = 0;
2462                 }
2463
2464                 if((! $is_element) && isset($this->complexTypes[$type])){
2465                         $this->xdebug("in getTypeDef, found complexType $type");
2466                         return $this->complexTypes[$type];
2467                 } elseif((! $is_element) && isset($this->simpleTypes[$type])){
2468                         $this->xdebug("in getTypeDef, found simpleType $type");
2469                         if (!isset($this->simpleTypes[$type]['phpType'])) {
2470                                 // get info for type to tack onto the simple type
2471                                 // TODO: can this ever really apply (i.e. what is a simpleType really?)
2472                                 $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
2473                                 $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
2474                                 $etype = $this->getTypeDef($uqType);
2475                                 if ($etype) {
2476                                         $this->xdebug("in getTypeDef, found type for simpleType $type:");
2477                                         $this->xdebug($this->varDump($etype));
2478                                         if (isset($etype['phpType'])) {
2479                                                 $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
2480                                         }
2481                                         if (isset($etype['elements'])) {
2482                                                 $this->simpleTypes[$type]['elements'] = $etype['elements'];
2483                                         }
2484                                 }
2485                         }
2486                         return $this->simpleTypes[$type];
2487                 } elseif(isset($this->elements[$type])){
2488                         $this->xdebug("in getTypeDef, found element $type");
2489                         if (!isset($this->elements[$type]['phpType'])) {
2490                                 // get info for type to tack onto the element
2491                                 $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
2492                                 $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
2493                                 $etype = $this->getTypeDef($uqType);
2494                                 if ($etype) {
2495                                         $this->xdebug("in getTypeDef, found type for element $type:");
2496                                         $this->xdebug($this->varDump($etype));
2497                                         if (isset($etype['phpType'])) {
2498                                                 $this->elements[$type]['phpType'] = $etype['phpType'];
2499                                         }
2500                                         if (isset($etype['elements'])) {
2501                                                 $this->elements[$type]['elements'] = $etype['elements'];
2502                                         }
2503                                         if (isset($etype['extensionBase'])) {
2504                                                 $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
2505                                         }
2506                                 } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
2507                                         $this->xdebug("in getTypeDef, element $type is an XSD type");
2508                                         $this->elements[$type]['phpType'] = 'scalar';
2509                                 }
2510                         }
2511                         return $this->elements[$type];
2512                 } elseif(isset($this->attributes[$type])){
2513                         $this->xdebug("in getTypeDef, found attribute $type");
2514                         return $this->attributes[$type];
2515                 } elseif (preg_match('/_ContainedType$/', $type)) {
2516                         $this->xdebug("in getTypeDef, have an untyped element $type");
2517                         $typeDef['typeClass'] = 'simpleType';
2518                         $typeDef['phpType'] = 'scalar';
2519                         $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
2520                         return $typeDef;
2521                 }
2522                 $this->xdebug("in getTypeDef, did not find $type");
2523                 return false;
2524         }
2525
2526         /**
2527     * returns a sample serialization of a given type, or false if no type by the given name
2528     *
2529     * @param string $type name of type
2530     * @return mixed
2531     * @access public
2532     * @deprecated
2533     */
2534     function serializeTypeDef($type){
2535         //print "in sTD() for type $type<br>";
2536         if($typeDef = $this->getTypeDef($type)){
2537                 $str .= '<'.$type;
2538             if(is_array($typeDef['attrs'])){
2539                 foreach($typeDef['attrs'] as $attName => $data){
2540                     $str .= " $attName=\"{type = ".$data['type']."}\"";
2541                 }
2542             }
2543             $str .= " xmlns=\"".$this->schema['targetNamespace']."\"";
2544             if(count($typeDef['elements']) > 0){
2545                 $str .= ">";
2546                 foreach($typeDef['elements'] as $element => $eData){
2547                     $str .= $this->serializeTypeDef($element);
2548                 }
2549                 $str .= "</$type>";
2550             } elseif($typeDef['typeClass'] == 'element') {
2551                 $str .= "></$type>";
2552             } else {
2553                 $str .= "/>";
2554             }
2555                         return $str;
2556         }
2557         return false;
2558     }
2559
2560     /**
2561     * returns HTML form elements that allow a user
2562     * to enter values for creating an instance of the given type.
2563     *
2564     * @param string $name name for type instance
2565     * @param string $type name of type
2566     * @return string
2567     * @access public
2568     * @deprecated
2569         */
2570         function typeToForm($name,$type){
2571                 // get typedef
2572                 if($typeDef = $this->getTypeDef($type)){
2573                         // if struct
2574                         if($typeDef['phpType'] == 'struct'){
2575                                 $buffer .= '<table>';
2576                                 foreach($typeDef['elements'] as $child => $childDef){
2577                                         $buffer .= "
2578                                         <tr><td align='right'>$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):</td>
2579                                         <td><input type='text' name='parameters[".$name."][$childDef[name]]'></td></tr>";
2580                                 }
2581                                 $buffer .= '</table>';
2582                         // if array
2583                         } elseif($typeDef['phpType'] == 'array'){
2584                                 $buffer .= '<table>';
2585                                 for($i=0;$i < 3; $i++){
2586                                         $buffer .= "
2587                                         <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
2588                                         <td><input type='text' name='parameters[".$name."][]'></td></tr>";
2589                                 }
2590                                 $buffer .= '</table>';
2591                         // if scalar
2592                         } else {
2593                                 $buffer .= "<input type='text' name='parameters[$name]'>";
2594                         }
2595                 } else {
2596                         $buffer .= "<input type='text' name='parameters[$name]'>";
2597                 }
2598                 return $buffer;
2599         }
2600
2601         /**
2602         * adds a complex type to the schema
2603         *
2604         * example: array
2605         *
2606         * addType(
2607         *       'ArrayOfstring',
2608         *       'complexType',
2609         *       'array',
2610         *       '',
2611         *       'SOAP-ENC:Array',
2612         *       array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
2613         *       'xsd:string'
2614         * );
2615         *
2616         * example: PHP associative array ( SOAP Struct )
2617         *
2618         * addType(
2619         *       'SOAPStruct',
2620         *       'complexType',
2621         *       'struct',
2622         *       'all',
2623         *       array('myVar'=> array('name'=>'myVar','type'=>'string')
2624         * );
2625         *
2626         * @param name
2627         * @param typeClass (complexType|simpleType|attribute)
2628         * @param phpType: currently supported are array and struct (php assoc array)
2629         * @param compositor (all|sequence|choice)
2630         * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2631         * @param elements = array ( name = array(name=>'',type=>'') )
2632         * @param attrs = array(
2633         *       array(
2634         *               'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
2635         *               "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
2636         *       )
2637         * )
2638         * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string)
2639         * @access public
2640         * @see getTypeDef
2641         */
2642         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){
2643                 $this->complexTypes[$name] = array(
2644             'name'              => $name,
2645             'typeClass' => $typeClass,
2646             'phpType'   => $phpType,
2647                 'compositor'=> $compositor,
2648             'restrictionBase' => $restrictionBase,
2649                 'elements'      => $elements,
2650             'attrs'             => $attrs,
2651             'arrayType' => $arrayType
2652                 );
2653
2654                 $this->xdebug("addComplexType $name:");
2655                 $this->appendDebug($this->varDump($this->complexTypes[$name]));
2656         }
2657
2658         /**
2659         * adds a simple type to the schema
2660         *
2661         * @param string $name
2662         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2663         * @param string $typeClass (should always be simpleType)
2664         * @param string $phpType (should always be scalar)
2665         * @param array $enumeration array of values
2666         * @access public
2667         * @see nusoap_xmlschema
2668         * @see getTypeDef
2669         */
2670         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
2671                 $this->simpleTypes[$name] = array(
2672             'name'                      => $name,
2673             'typeClass'         => $typeClass,
2674             'phpType'           => $phpType,
2675             'type'                      => $restrictionBase,
2676             'enumeration'       => $enumeration
2677                 );
2678
2679                 $this->xdebug("addSimpleType $name:");
2680                 $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2681         }
2682
2683         /**
2684         * adds an element to the schema
2685         *
2686         * @param array $attrs attributes that must include name and type
2687         * @see nusoap_xmlschema
2688         * @access public
2689         */
2690         function addElement($attrs) {
2691                 if (! $this->getPrefix($attrs['type'])) {
2692                         $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2693                 }
2694                 $this->elements[ $attrs['name'] ] = $attrs;
2695                 $this->elements[ $attrs['name'] ]['typeClass'] = 'element';
2696
2697                 $this->xdebug("addElement " . $attrs['name']);
2698                 $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ]));
2699         }
2700 }
2701
2702 /**
2703  * Backward compatibility
2704  */
2705 class XMLSchema extends nusoap_xmlschema {
2706 }
2707
2708 ?><?php
2709
2710 /*
2711
2712 Modification information for LGPL compliance
2713
2714 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
2715     bug 40066
2716
2717 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
2718     Merging with maint_6_0_1 (svn merge -r 58250:58342)
2719
2720 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
2721     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.
2722
2723 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
2724     fix SOAP calls with no parameters
2725
2726 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
2727
2728 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
2729
2730 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
2731
2732 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
2733
2734 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
2735
2736 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.
2737
2738 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.
2739
2740 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:
2741 - Changing all ereg function to either preg or simple string based ones
2742 - No more references to magic quotes.
2743 - Change all the session_unregister() functions to just unset() the correct session variable instead.
2744
2745 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
2746
2747 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
2748
2749 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
2750
2751 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
2752
2753 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
2754
2755 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
2756
2757 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
2758
2759 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
2760
2761 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.
2762 Touched:
2763 - data/SugarBean.php
2764 - include/domit/php_http_client_generic.php
2765 - include/domit/php_http_connector.php
2766 - include/domit/testing_domit.php
2767 - include/domit/xml_domit_getelementsbypath.php
2768 - include/domit/xml_domit_lite_parser.php
2769 - include/domit/xml_domit_nodemaps.php
2770 - include/domit/xml_domit_parser.php
2771 - include/domit/xml_domit_shared.php
2772 - include/generic/SugarWidgets/SugarWidgetField.php
2773 - include/generic/SugarWidgets/SugarWidgetReportField.php
2774 - include/ListView/ProcessView.php
2775 - include/nusoap/class.soapclient.php
2776 - include/nusoap/nusoap.php
2777 - include/nusoap/nusoapmime.php
2778 - include/Pear/HTML_Safe/Safe.php
2779 - include/Pear/XML_HTMLSax3/HTMLSax3.php
2780 - modules/Administration/RebuildWorkFlow.php
2781 - modules/Expressions/RelateSelector.php
2782 - modules/Reports/templates/templates_reports.php
2783 - modules/WorkFlow/Delete.php
2784 - modules/WorkFlow/Save.php
2785 - modules/WorkFlow/SaveSequence.php
2786 - modules/WorkFlow/WorkFlow.php
2787 - modules/WorkFlowActionShells/CreateStep1.php
2788 - modules/WorkFlowActionShells/CreateStep2.php
2789 - modules/WorkFlowActionShells/Save.php
2790 - modules/WorkFlowActionShells/WorkFlowActionShell.php
2791 - modules/WorkFlowAlerts/Save.php
2792 - modules/WorkFlowAlerts/WorkFlowAlert.php
2793 - modules/WorkFlowAlertShells/DetailView.php
2794 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
2795 - modules/WorkFlowTriggerShells/CreateStep1.php
2796 - modules/WorkFlowTriggerShells/CreateStepFilter.php
2797 - modules/WorkFlowTriggerShells/SaveFilter.php
2798 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
2799 - soap/SoapHelperFunctions.php
2800 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
2801 - test/simpletest/browser.php
2802 - test/simpletest/default_reporter.php
2803 - test/simpletest/detached.php
2804 - test/simpletest/eclipse.php
2805 - test/simpletest/expectation.php
2806 - test/simpletest/extensions/pear_test_case.php
2807 - test/simpletest/form.php
2808 - test/simpletest/http.php
2809 - test/simpletest/mock_objects.php
2810 - test/simpletest/page.php
2811 - test/simpletest/parser.php
2812 - test/simpletest/remote.php
2813 - test/simpletest/shell_tester.php
2814 - test/simpletest/simple_test.php
2815 - test/simpletest/simpletest.php
2816 - test/simpletest/test/acceptance_test.php
2817 - test/simpletest/test/adapter_test.php
2818 - test/simpletest/test/authentication_test.php
2819 - test/simpletest/test/browser_test.php
2820 - test/simpletest/test/collector_test.php
2821 - test/simpletest/test/compatibility_test.php
2822 - test/simpletest/test/detached_test.php
2823 - test/simpletest/test/eclipse_test.php
2824 - test/simpletest/test/encoding_test.php
2825 - test/simpletest/test/errors_test.php
2826 - test/simpletest/test/expectation_test.php
2827 - test/simpletest/test/form_test.php
2828 - test/simpletest/test/frames_test.php
2829 - test/simpletest/test/http_test.php
2830 - test/simpletest/test/live_test.php
2831 - test/simpletest/test/mock_objects_test.php
2832 - test/simpletest/test/page_test.php
2833 - test/simpletest/test/parse_error_test.php
2834 - test/simpletest/test/parser_test.php
2835 - test/simpletest/test/remote_test.php
2836 - test/simpletest/test/shell_test.php
2837 - test/simpletest/test/shell_tester_test.php
2838 - test/simpletest/test/simpletest_test.php
2839 - test/simpletest/test/site/page_request.php
2840 - test/simpletest/test/tag_test.php
2841 - test/simpletest/test/unit_tester_test.php
2842 - test/simpletest/test/user_agent_test.php
2843 - test/simpletest/test/visual_test.php
2844 - test/simpletest/test/xml_test.php
2845 - test/simpletest/test_case.php
2846 - test/simpletest/ui/array_reporter/test.php
2847 - test/simpletest/ui/recorder/test.php
2848 - test/simpletest/unit_tester.php
2849 - test/simpletest/url.php
2850 - test/simpletest/user_agent.php
2851 - test/simpletest/web_tester.php
2852 - test/spikephpcoverage/src/PEAR.php
2853 - test/spikephpcoverage/src/util/Utility.php
2854 - test/spikephpcoverage/src/XML/Parser.php
2855 - test/spikephpcoverage/src/XML/Parser/Simple.php
2856 - test/test_utilities/SugarTest_SimpleBrowser.php
2857
2858 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.
2859
2860 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
2861
2862 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
2863
2864 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
2865
2866 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
2867
2868 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
2869
2870 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
2871
2872 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
2873
2874 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
2875
2876 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
2877
2878 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
2879
2880 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
2881
2882 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.
2883
2884 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
2885
2886 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
2887
2888 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
2889
2890 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
2891
2892 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
2893
2894 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
2895
2896 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
2897
2898 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
2899
2900 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
2901
2902 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
2903
2904 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
2905
2906
2907 */
2908
2909
2910
2911
2912
2913 /**
2914 * For creating serializable abstractions of native PHP types.  This class
2915 * allows element name/namespace, XSD type, and XML attributes to be
2916 * associated with a value.  This is extremely useful when WSDL is not
2917 * used, but is also useful when WSDL is used with polymorphic types, including
2918 * xsd:anyType and user-defined types.
2919 *
2920 * @author   Dietrich Ayala <dietrich@ganx4.com>
2921
2922 * @access   public
2923 */
2924 class soapval extends nusoap_base {
2925         /**
2926          * The XML element name
2927          *
2928          * @var string
2929          * @access private
2930          */
2931         var $name;
2932         /**
2933          * The XML type name (string or false)
2934          *
2935          * @var mixed
2936          * @access private
2937          */
2938         var $type;
2939         /**
2940          * The PHP value
2941          *
2942          * @var mixed
2943          * @access private
2944          */
2945         var $value;
2946         /**
2947          * The XML element namespace (string or false)
2948          *
2949          * @var mixed
2950          * @access private
2951          */
2952         var $element_ns;
2953         /**
2954          * The XML type namespace (string or false)
2955          *
2956          * @var mixed
2957          * @access private
2958          */
2959         var $type_ns;
2960         /**
2961          * The XML element attributes (array or false)
2962          *
2963          * @var mixed
2964          * @access private
2965          */
2966         var $attributes;
2967
2968         /**
2969         * constructor
2970         *
2971         * @param    string $name optional name
2972         * @param    mixed $type optional type name
2973         * @param        mixed $value optional value
2974         * @param        mixed $element_ns optional namespace of value
2975         * @param        mixed $type_ns optional namespace of type
2976         * @param        mixed $attributes associative array of attributes to add to element serialization
2977         * @access   public
2978         */
2979         function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) {
2980                 parent::nusoap_base();
2981                 $this->name = $name;
2982                 $this->type = $type;
2983                 $this->value = $value;
2984                 $this->element_ns = $element_ns;
2985                 $this->type_ns = $type_ns;
2986                 $this->attributes = $attributes;
2987     }
2988
2989         /**
2990         * return serialized value
2991         *
2992         * @param        string $use The WSDL use value (encoded|literal)
2993         * @return       string XML data
2994         * @access   public
2995         */
2996         function serialize($use='encoded') {
2997                 return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2998     }
2999
3000         /**
3001         * decodes a soapval object into a PHP native type
3002         *
3003         * @return       mixed
3004         * @access   public
3005         */
3006         function decode(){
3007                 return $this->value;
3008         }
3009 }
3010
3011
3012
3013 ?><?php
3014
3015 /*
3016
3017 Modification information for LGPL compliance
3018
3019 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
3020     bug 40066
3021
3022 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
3023     Merging with maint_6_0_1 (svn merge -r 58250:58342)
3024
3025 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
3026     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.
3027
3028 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
3029     fix SOAP calls with no parameters
3030
3031 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
3032
3033 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
3034
3035 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
3036
3037 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
3038
3039 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
3040
3041 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.
3042
3043 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.
3044
3045 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:
3046 - Changing all ereg function to either preg or simple string based ones
3047 - No more references to magic quotes.
3048 - Change all the session_unregister() functions to just unset() the correct session variable instead.
3049
3050 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
3051
3052 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
3053
3054 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
3055
3056 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
3057
3058 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
3059
3060 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
3061
3062 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
3063
3064 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
3065
3066 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.
3067 Touched:
3068 - data/SugarBean.php
3069 - include/domit/php_http_client_generic.php
3070 - include/domit/php_http_connector.php
3071 - include/domit/testing_domit.php
3072 - include/domit/xml_domit_getelementsbypath.php
3073 - include/domit/xml_domit_lite_parser.php
3074 - include/domit/xml_domit_nodemaps.php
3075 - include/domit/xml_domit_parser.php
3076 - include/domit/xml_domit_shared.php
3077 - include/generic/SugarWidgets/SugarWidgetField.php
3078 - include/generic/SugarWidgets/SugarWidgetReportField.php
3079 - include/ListView/ProcessView.php
3080 - include/nusoap/class.soapclient.php
3081 - include/nusoap/nusoap.php
3082 - include/nusoap/nusoapmime.php
3083 - include/Pear/HTML_Safe/Safe.php
3084 - include/Pear/XML_HTMLSax3/HTMLSax3.php
3085 - modules/Administration/RebuildWorkFlow.php
3086 - modules/Expressions/RelateSelector.php
3087 - modules/Reports/templates/templates_reports.php
3088 - modules/WorkFlow/Delete.php
3089 - modules/WorkFlow/Save.php
3090 - modules/WorkFlow/SaveSequence.php
3091 - modules/WorkFlow/WorkFlow.php
3092 - modules/WorkFlowActionShells/CreateStep1.php
3093 - modules/WorkFlowActionShells/CreateStep2.php
3094 - modules/WorkFlowActionShells/Save.php
3095 - modules/WorkFlowActionShells/WorkFlowActionShell.php
3096 - modules/WorkFlowAlerts/Save.php
3097 - modules/WorkFlowAlerts/WorkFlowAlert.php
3098 - modules/WorkFlowAlertShells/DetailView.php
3099 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
3100 - modules/WorkFlowTriggerShells/CreateStep1.php
3101 - modules/WorkFlowTriggerShells/CreateStepFilter.php
3102 - modules/WorkFlowTriggerShells/SaveFilter.php
3103 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
3104 - soap/SoapHelperFunctions.php
3105 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
3106 - test/simpletest/browser.php
3107 - test/simpletest/default_reporter.php
3108 - test/simpletest/detached.php
3109 - test/simpletest/eclipse.php
3110 - test/simpletest/expectation.php
3111 - test/simpletest/extensions/pear_test_case.php
3112 - test/simpletest/form.php
3113 - test/simpletest/http.php
3114 - test/simpletest/mock_objects.php
3115 - test/simpletest/page.php
3116 - test/simpletest/parser.php
3117 - test/simpletest/remote.php
3118 - test/simpletest/shell_tester.php
3119 - test/simpletest/simple_test.php
3120 - test/simpletest/simpletest.php
3121 - test/simpletest/test/acceptance_test.php
3122 - test/simpletest/test/adapter_test.php
3123 - test/simpletest/test/authentication_test.php
3124 - test/simpletest/test/browser_test.php
3125 - test/simpletest/test/collector_test.php
3126 - test/simpletest/test/compatibility_test.php
3127 - test/simpletest/test/detached_test.php
3128 - test/simpletest/test/eclipse_test.php
3129 - test/simpletest/test/encoding_test.php
3130 - test/simpletest/test/errors_test.php
3131 - test/simpletest/test/expectation_test.php
3132 - test/simpletest/test/form_test.php
3133 - test/simpletest/test/frames_test.php
3134 - test/simpletest/test/http_test.php
3135 - test/simpletest/test/live_test.php
3136 - test/simpletest/test/mock_objects_test.php
3137 - test/simpletest/test/page_test.php
3138 - test/simpletest/test/parse_error_test.php
3139 - test/simpletest/test/parser_test.php
3140 - test/simpletest/test/remote_test.php
3141 - test/simpletest/test/shell_test.php
3142 - test/simpletest/test/shell_tester_test.php
3143 - test/simpletest/test/simpletest_test.php
3144 - test/simpletest/test/site/page_request.php
3145 - test/simpletest/test/tag_test.php
3146 - test/simpletest/test/unit_tester_test.php
3147 - test/simpletest/test/user_agent_test.php
3148 - test/simpletest/test/visual_test.php
3149 - test/simpletest/test/xml_test.php
3150 - test/simpletest/test_case.php
3151 - test/simpletest/ui/array_reporter/test.php
3152 - test/simpletest/ui/recorder/test.php
3153 - test/simpletest/unit_tester.php
3154 - test/simpletest/url.php
3155 - test/simpletest/user_agent.php
3156 - test/simpletest/web_tester.php
3157 - test/spikephpcoverage/src/PEAR.php
3158 - test/spikephpcoverage/src/util/Utility.php
3159 - test/spikephpcoverage/src/XML/Parser.php
3160 - test/spikephpcoverage/src/XML/Parser/Simple.php
3161 - test/test_utilities/SugarTest_SimpleBrowser.php
3162
3163 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.
3164
3165 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
3166
3167 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
3168
3169 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
3170
3171 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
3172
3173 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
3174
3175 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
3176
3177 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
3178
3179 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
3180
3181 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
3182
3183 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
3184
3185 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
3186
3187 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.
3188
3189 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
3190
3191 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
3192
3193 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
3194
3195 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
3196
3197 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
3198
3199 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
3200
3201 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
3202
3203 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
3204
3205 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
3206
3207 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
3208
3209 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
3210
3211
3212 */
3213
3214
3215
3216
3217
3218 /**
3219 * transport class for sending/receiving data via HTTP and HTTPS
3220 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
3221 *
3222 * @author   Dietrich Ayala <dietrich@ganx4.com>
3223 * @author   Scott Nichol <snichol@users.sourceforge.net>
3224
3225 * @access public
3226 */
3227 class soap_transport_http extends nusoap_base {
3228
3229         var $url = '';
3230         var $uri = '';
3231         var $digest_uri = '';
3232         var $scheme = '';
3233         var $host = '';
3234         var $port = '';
3235         var $path = '';
3236         var $request_method = 'POST';
3237         var $protocol_version = '1.0';
3238         var $encoding = '';
3239         var $outgoing_headers = array();
3240         var $incoming_headers = array();
3241         var $incoming_cookies = array();
3242         var $outgoing_payload = '';
3243         var $incoming_payload = '';
3244         var $response_status_line;      // HTTP response status line
3245         var $useSOAPAction = true;
3246         var $persistentConnection = false;
3247         var $ch = false;        // cURL handle
3248         var $ch_options = array();      // cURL custom options
3249         var $use_curl = false;          // force cURL use
3250         var $proxy = null;                      // proxy information (associative array)
3251         var $username = '';
3252         var $password = '';
3253         var $authtype = '';
3254         var $digestRequest = array();
3255         var $certRequest = array();     // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
3256                                                                 // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
3257                                                                 // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
3258                                                                 // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
3259                                                                 // passphrase: SSL key password/passphrase
3260                                                                 // certpassword: SSL certificate password
3261                                                                 // verifypeer: default is 1
3262                                                                 // verifyhost: default is 1
3263
3264         /**
3265         * constructor
3266         *
3267         * @param string $url The URL to which to connect
3268         * @param array $curl_options User-specified cURL options
3269         * @param boolean $use_curl Whether to try to force cURL use
3270         * @access public
3271         */
3272         function soap_transport_http($url, $curl_options = NULL, $use_curl = false){
3273                 parent::nusoap_base();
3274                 $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
3275                 $this->appendDebug($this->varDump($curl_options));
3276                 $this->setURL($url);
3277                 if (is_array($curl_options)) {
3278                         $this->ch_options = $curl_options;
3279                 }
3280                 $this->use_curl = $use_curl;
3281                 preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
3282                 $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')');
3283         }
3284
3285         /**
3286         * sets a cURL option
3287         *
3288         * @param        mixed $option The cURL option (always integer?)
3289         * @param        mixed $value The cURL option value
3290         * @access   private
3291         */
3292         function setCurlOption($option, $value) {
3293                 $this->debug("setCurlOption option=$option, value=");
3294                 $this->appendDebug($this->varDump($value));
3295                 curl_setopt($this->ch, $option, $value);
3296         }
3297
3298         /**
3299         * sets an HTTP header
3300         *
3301         * @param string $name The name of the header
3302         * @param string $value The value of the header
3303         * @access private
3304         */
3305         function setHeader($name, $value) {
3306                 $this->outgoing_headers[$name] = $value;
3307                 $this->debug("set header $name: $value");
3308         }
3309
3310         /**
3311         * unsets an HTTP header
3312         *
3313         * @param string $name The name of the header
3314         * @access private
3315         */
3316         function unsetHeader($name) {
3317                 if (isset($this->outgoing_headers[$name])) {
3318                         $this->debug("unset header $name");
3319                         unset($this->outgoing_headers[$name]);
3320                 }
3321         }
3322
3323         /**
3324         * sets the URL to which to connect
3325         *
3326         * @param string $url The URL to which to connect
3327         * @access private
3328         */
3329         function setURL($url) {
3330                 $this->url = $url;
3331
3332                 $u = parse_url($url);
3333                 foreach($u as $k => $v){
3334                         $this->debug("parsed URL $k = $v");
3335                         $this->$k = $v;
3336                 }
3337
3338                 // add any GET params to path
3339                 if(isset($u['query']) && $u['query'] != ''){
3340             $this->path .= '?' . $u['query'];
3341                 }
3342
3343                 // set default port
3344                 if(!isset($u['port'])){
3345                         if($u['scheme'] == 'https'){
3346                                 $this->port = 443;
3347                         } else {
3348                                 $this->port = 80;
3349                         }
3350                 }
3351
3352                 $this->uri = $this->path;
3353                 $this->digest_uri = $this->uri;
3354
3355                 // build headers
3356                 if (!isset($u['port'])) {
3357                         $this->setHeader('Host', $this->host);
3358                 } else {
3359                         $this->setHeader('Host', $this->host.':'.$this->port);
3360                 }
3361
3362                 if (isset($u['user']) && $u['user'] != '') {
3363                         $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
3364                 }
3365         }
3366
3367         /**
3368         * gets the I/O method to use
3369         *
3370         * @return       string  I/O method to use (socket|curl|unknown)
3371         * @access       private
3372         */
3373         function io_method() {
3374                 if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm'))
3375                         return 'curl';
3376                 if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm'))
3377                         return 'socket';
3378                 return 'unknown';
3379         }
3380
3381         /**
3382         * establish an HTTP connection
3383         *
3384         * @param    integer $timeout set connection timeout in seconds
3385         * @param        integer $response_timeout set response timeout in seconds
3386         * @return       boolean true if connected, false if not
3387         * @access   private
3388         */
3389         function connect($connection_timeout=0,$response_timeout=30){
3390                 // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
3391                 // "regular" socket.
3392                 // TODO: disabled for now because OpenSSL must be *compiled* in (not just
3393                 //       loaded), and until PHP5 stream_get_wrappers is not available.
3394 //              if ($this->scheme == 'https') {
3395 //                      if (version_compare(phpversion(), '4.3.0') >= 0) {
3396 //                              if (extension_loaded('openssl')) {
3397 //                                      $this->scheme = 'ssl';
3398 //                                      $this->debug('Using SSL over OpenSSL');
3399 //                              }
3400 //                      }
3401 //              }
3402                 $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
3403           if ($this->io_method() == 'socket') {
3404                 if (!is_array($this->proxy)) {
3405                         $host = $this->host;
3406                         $port = $this->port;
3407                 } else {
3408                         $host = $this->proxy['host'];
3409                         $port = $this->proxy['port'];
3410                 }
3411
3412                 // use persistent connection
3413                 if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){
3414                         if (!feof($this->fp)) {
3415                                 $this->debug('Re-use persistent connection');
3416                                 return true;
3417                         }
3418                         fclose($this->fp);
3419                         $this->debug('Closed persistent connection at EOF');
3420                 }
3421
3422                 // munge host if using OpenSSL
3423                 if ($this->scheme == 'ssl') {
3424                         $host = 'ssl://' . $host;
3425                 }
3426                 $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
3427
3428                 // open socket
3429                 if($connection_timeout > 0){
3430                         $this->fp = @fsockopen( $host, $port, $this->errno, $this->error_str, $connection_timeout);
3431                 } else {
3432                         $this->fp = @fsockopen( $host, $port, $this->errno, $this->error_str);
3433                 }
3434
3435                 // test pointer
3436                 if(!$this->fp) {
3437                         $msg = 'Couldn\'t open socket connection to server ' . $this->url;
3438                         if ($this->errno) {
3439                                 $msg .= ', Error ('.$this->errno.'): '.$this->error_str;
3440                         } else {
3441                                 $msg .= ' prior to connect().  This is often a problem looking up the host name.';
3442                         }
3443                         $this->debug($msg);
3444                         $this->setError($msg);
3445                         return false;
3446                 }
3447
3448                 // set response timeout
3449                 $this->debug('set response timeout to ' . $response_timeout);
3450                 socket_set_timeout( $this->fp, $response_timeout);
3451
3452                 $this->debug('socket connected');
3453                 return true;
3454           } else if ($this->io_method() == 'curl') {
3455                 if (!extension_loaded('curl')) {
3456 //                      $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
3457                         $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.');
3458                         return false;
3459                 }
3460                 // Avoid warnings when PHP does not have these options
3461                 if (defined('CURLOPT_CONNECTIONTIMEOUT'))
3462                         $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
3463                 else
3464                         $CURLOPT_CONNECTIONTIMEOUT = 78;
3465                 if (defined('CURLOPT_HTTPAUTH'))
3466                         $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
3467                 else
3468                         $CURLOPT_HTTPAUTH = 107;
3469                 if (defined('CURLOPT_PROXYAUTH'))
3470                         $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
3471                 else
3472                         $CURLOPT_PROXYAUTH = 111;
3473                 if (defined('CURLAUTH_BASIC'))
3474                         $CURLAUTH_BASIC = CURLAUTH_BASIC;
3475                 else
3476                         $CURLAUTH_BASIC = 1;
3477                 if (defined('CURLAUTH_DIGEST'))
3478                         $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
3479                 else
3480                         $CURLAUTH_DIGEST = 2;
3481                 if (defined('CURLAUTH_NTLM'))
3482                         $CURLAUTH_NTLM = CURLAUTH_NTLM;
3483                 else
3484                         $CURLAUTH_NTLM = 8;
3485
3486                 $this->debug('connect using cURL');
3487                 // init CURL
3488                 $this->ch = curl_init();
3489                 // set url
3490                 $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
3491                 // add path
3492                 $hostURL .= $this->path;
3493                 $this->setCurlOption(CURLOPT_URL, $hostURL);
3494                 // follow location headers (re-directs)
3495                 if (ini_get('safe_mode') || ini_get('open_basedir')) {
3496                         $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
3497                         $this->debug('safe_mode = ');
3498                         $this->appendDebug($this->varDump(ini_get('safe_mode')));
3499                         $this->debug('open_basedir = ');
3500                         $this->appendDebug($this->varDump(ini_get('open_basedir')));
3501                 } else {
3502                         $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
3503                 }
3504                 // ask for headers in the response output
3505                 $this->setCurlOption(CURLOPT_HEADER, 1);
3506                 // ask for the response output as the return value
3507                 $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
3508                 // encode
3509                 // We manage this ourselves through headers and encoding
3510 //              if(function_exists('gzuncompress')){
3511 //                      $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
3512 //              }
3513                 // persistent connection
3514                 if ($this->persistentConnection) {
3515                         // I believe the following comment is now bogus, having applied to
3516                         // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
3517                         // The way we send data, we cannot use persistent connections, since
3518                         // there will be some "junk" at the end of our request.
3519                         //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
3520                         $this->persistentConnection = false;
3521                         $this->setHeader('Connection', 'close');
3522                 }
3523                 // set timeouts
3524                 if ($connection_timeout != 0) {
3525                         $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
3526                 }
3527                 if ($response_timeout != 0) {
3528                         $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
3529                 }
3530
3531                 if ($this->scheme == 'https') {
3532                         $this->debug('set cURL SSL verify options');
3533                         // recent versions of cURL turn on peer/host checking by default,
3534                         // while PHP binaries are not compiled with a default location for the
3535                         // CA cert bundle, so disable peer/host checking.
3536                         //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
3537                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
3538                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
3539
3540                         // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
3541                         if ($this->authtype == 'certificate') {
3542                                 $this->debug('set cURL certificate options');
3543                                 if (isset($this->certRequest['cainfofile'])) {
3544                                         $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
3545                                 }
3546                                 if (isset($this->certRequest['verifypeer'])) {
3547                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
3548                                 } else {
3549                                         $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
3550                                 }
3551                                 if (isset($this->certRequest['verifyhost'])) {
3552                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
3553                                 } else {
3554                                         $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
3555                                 }
3556                                 if (isset($this->certRequest['sslcertfile'])) {
3557                                         $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
3558                                 }
3559                                 if (isset($this->certRequest['sslkeyfile'])) {
3560                                         $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
3561                                 }
3562                                 if (isset($this->certRequest['passphrase'])) {
3563                                         $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
3564                                 }
3565                                 if (isset($this->certRequest['certpassword'])) {
3566                                         $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
3567                                 }
3568                         }
3569                 }
3570                 if ($this->authtype && ($this->authtype != 'certificate')) {
3571                         if ($this->username) {
3572                                 $this->debug('set cURL username/password');
3573                                 $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
3574                         }
3575                         if ($this->authtype == 'basic') {
3576                                 $this->debug('set cURL for Basic authentication');
3577                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
3578                         }
3579                         if ($this->authtype == 'digest') {
3580                                 $this->debug('set cURL for digest authentication');
3581                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
3582                         }
3583                         if ($this->authtype == 'ntlm') {
3584                                 $this->debug('set cURL for NTLM authentication');
3585                                 $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
3586                         }
3587                 }
3588                 if (is_array($this->proxy)) {
3589                         $this->debug('set cURL proxy options');
3590                         if ($this->proxy['port'] != '') {
3591                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']);
3592                         } else {
3593                                 $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
3594                         }
3595                         if ($this->proxy['username'] || $this->proxy['password']) {
3596                                 $this->debug('set cURL proxy authentication options');
3597                                 $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']);
3598                                 if ($this->proxy['authtype'] == 'basic') {
3599                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
3600                                 }
3601                                 if ($this->proxy['authtype'] == 'ntlm') {
3602                                         $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
3603                                 }
3604                         }
3605                 }
3606                 $this->debug('cURL connection set up');
3607                 return true;
3608           } else {
3609                 $this->setError('Unknown scheme ' . $this->scheme);
3610                 $this->debug('Unknown scheme ' . $this->scheme);
3611                 return false;
3612           }
3613         }
3614
3615         /**
3616         * sends the SOAP request and gets the SOAP response via HTTP[S]
3617         *
3618         * @param    string $data message data
3619         * @param    integer $timeout set connection timeout in seconds
3620         * @param        integer $response_timeout set response timeout in seconds
3621         * @param        array $cookies cookies to send
3622         * @return       string data
3623         * @access   public
3624         */
3625         function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) {
3626
3627                 $this->debug('entered send() with data of length: '.strlen($data));
3628
3629                 $this->tryagain = true;
3630                 $tries = 0;
3631                 while ($this->tryagain) {
3632                         $this->tryagain = false;
3633                         if ($tries++ < 2) {
3634                                 // make connnection
3635                                 if (!$this->connect($timeout, $response_timeout)){
3636                                         return false;
3637                                 }
3638
3639                                 // send request
3640                                 if (!$this->sendRequest($data, $cookies)){
3641                                         return false;
3642                                 }
3643
3644                                 // get response
3645                                 $respdata = $this->getResponse();
3646                         } else {
3647                                 $this->setError("Too many tries to get an OK response ($this->response_status_line)");
3648                         }
3649                 }
3650                 $this->debug('end of send()');
3651                 return $respdata;
3652         }
3653
3654
3655         /**
3656         * sends the SOAP request and gets the SOAP response via HTTPS using CURL
3657         *
3658         * @param    string $data message data
3659         * @param    integer $timeout set connection timeout in seconds
3660         * @param        integer $response_timeout set response timeout in seconds
3661         * @param        array $cookies cookies to send
3662         * @return       string data
3663         * @access   public
3664         * @deprecated
3665         */
3666         function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) {
3667                 return $this->send($data, $timeout, $response_timeout, $cookies);
3668         }
3669
3670         /**
3671         * if authenticating, set user credentials here
3672         *
3673         * @param    string $username
3674         * @param    string $password
3675         * @param        string $authtype (basic|digest|certificate|ntlm)
3676         * @param        array $digestRequest (keys must be nonce, nc, realm, qop)
3677         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
3678         * @access   public
3679         */
3680         function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) {
3681                 $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
3682                 $this->appendDebug($this->varDump($digestRequest));
3683                 $this->debug("certRequest=");
3684                 $this->appendDebug($this->varDump($certRequest));
3685                 // cf. RFC 2617
3686                 if ($authtype == 'basic') {
3687                         $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password));
3688                 } elseif ($authtype == 'digest') {
3689                         if (isset($digestRequest['nonce'])) {
3690                                 $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
3691
3692                                 // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
3693
3694                                 // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
3695                                 $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
3696
3697                                 // H(A1) = MD5(A1)
3698                                 $HA1 = md5($A1);
3699
3700                                 // A2 = Method ":" digest-uri-value
3701                                 $A2 = $this->request_method . ':' . $this->digest_uri;
3702
3703                                 // H(A2)
3704                                 $HA2 =  md5($A2);
3705
3706                                 // KD(secret, data) = H(concat(secret, ":", data))
3707                                 // if qop == auth:
3708                                 // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
3709                                 //                              ":" nc-value
3710                                 //                              ":" unq(cnonce-value)
3711                                 //                              ":" unq(qop-value)
3712                                 //                              ":" H(A2)
3713                                 //                            ) <">
3714                                 // if qop is missing,
3715                                 // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
3716
3717                                 $unhashedDigest = '';
3718                                 $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
3719                                 $cnonce = $nonce;
3720                                 if ($digestRequest['qop'] != '') {
3721                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
3722                                 } else {
3723                                         $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
3724                                 }
3725
3726                                 $hashedDigest = md5($unhashedDigest);
3727
3728                                 $opaque = '';
3729                                 if (isset($digestRequest['opaque'])) {
3730                                         $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
3731                                 }
3732
3733                                 $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 . '"');
3734                         }
3735                 } elseif ($authtype == 'certificate') {
3736                         $this->certRequest = $certRequest;
3737                         $this->debug('Authorization header not set for certificate');
3738                 } elseif ($authtype == 'ntlm') {
3739                         // do nothing
3740                         $this->debug('Authorization header not set for ntlm');
3741                 }
3742                 $this->username = $username;
3743                 $this->password = $password;
3744                 $this->authtype = $authtype;
3745                 $this->digestRequest = $digestRequest;
3746         }
3747
3748         /**
3749         * set the soapaction value
3750         *
3751         * @param    string $soapaction
3752         * @access   public
3753         */
3754         function setSOAPAction($soapaction) {
3755                 $this->setHeader('SOAPAction', '"' . $soapaction . '"');
3756         }
3757
3758         /**
3759         * use http encoding
3760         *
3761         * @param    string $enc encoding style. supported values: gzip, deflate, or both
3762         * @access   public
3763         */
3764         function setEncoding($enc='gzip, deflate') {
3765                 if (function_exists('gzdeflate')) {
3766                         $this->protocol_version = '1.1';
3767                         $this->setHeader('Accept-Encoding', $enc);
3768                         if (!isset($this->outgoing_headers['Connection'])) {
3769                                 $this->setHeader('Connection', 'close');
3770                                 $this->persistentConnection = false;
3771                         }
3772                         // deprecated as of PHP 5.3.0
3773                         //set_magic_quotes_runtime(0);
3774                         $this->encoding = $enc;
3775                 }
3776         }
3777
3778         /**
3779         * set proxy info here
3780         *
3781         * @param    string $proxyhost use an empty string to remove proxy
3782         * @param    string $proxyport
3783         * @param        string $proxyusername
3784         * @param        string $proxypassword
3785         * @param        string $proxyauthtype (basic|ntlm)
3786         * @access   public
3787         */
3788         function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') {
3789                 if ($proxyhost) {
3790                         $this->proxy = array(
3791                                 'host' => $proxyhost,
3792                                 'port' => $proxyport,
3793                                 'username' => $proxyusername,
3794                                 'password' => $proxypassword,
3795                                 'authtype' => $proxyauthtype
3796                         );
3797                         if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
3798                                 $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword));
3799                         }
3800                 } else {
3801                         $this->debug('remove proxy');
3802                         $proxy = null;
3803                         unsetHeader('Proxy-Authorization');
3804                 }
3805         }
3806
3807
3808         /**
3809          * Test if the given string starts with a header that is to be skipped.
3810          * Skippable headers result from chunked transfer and proxy requests.
3811          *
3812          * @param       string $data The string to check.
3813          * @returns     boolean Whether a skippable header was found.
3814          * @access      private
3815          */
3816         function isSkippableCurlHeader(&$data) {
3817                 $skipHeaders = array(   'HTTP/1.1 100',
3818                                                                 'HTTP/1.0 301',
3819                                                                 'HTTP/1.1 301',
3820                                                                 'HTTP/1.0 302',
3821                                                                 'HTTP/1.1 302',
3822                                                                 'HTTP/1.0 401',
3823                                                                 'HTTP/1.1 401',
3824                                                                 'HTTP/1.0 200 Connection established');
3825                 foreach ($skipHeaders as $hd) {
3826                         $prefix = substr($data, 0, strlen($hd));
3827                         if ($prefix == $hd) return true;
3828                 }
3829
3830                 return false;
3831         }
3832
3833         /**
3834         * decode a string that is encoded w/ "chunked' transfer encoding
3835         * as defined in RFC2068 19.4.6
3836         *
3837         * @param    string $buffer
3838         * @param    string $lb
3839         * @returns      string
3840         * @access   public
3841         * @deprecated
3842         */
3843         function decodeChunked($buffer, $lb){
3844                 // length := 0
3845                 $length = 0;
3846                 $new = '';
3847
3848                 // read chunk-size, chunk-extension (if any) and CRLF
3849                 // get the position of the linebreak
3850                 $chunkend = strpos($buffer, $lb);
3851                 if ($chunkend == FALSE) {
3852                         $this->debug('no linebreak found in decodeChunked');
3853                         return $new;
3854                 }
3855                 $temp = substr($buffer,0,$chunkend);
3856                 $chunk_size = hexdec( trim($temp) );
3857                 $chunkstart = $chunkend + strlen($lb);
3858                 // while (chunk-size > 0) {
3859                 while ($chunk_size > 0) {
3860                         $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
3861                         $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size);
3862
3863                         // Just in case we got a broken connection
3864                         if ($chunkend == FALSE) {
3865                             $chunk = substr($buffer,$chunkstart);
3866                                 // append chunk-data to entity-body
3867                         $new .= $chunk;
3868                             $length += strlen($chunk);
3869                             break;
3870                         }
3871
3872                         // read chunk-data and CRLF
3873                         $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart);
3874                         // append chunk-data to entity-body
3875                         $new .= $chunk;
3876                         // length := length + chunk-size
3877                         $length += strlen($chunk);
3878                         // read chunk-size and CRLF
3879                         $chunkstart = $chunkend + strlen($lb);
3880
3881                         $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
3882                         if ($chunkend == FALSE) {
3883                                 break; //Just in case we got a broken connection
3884                         }
3885                         $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart);
3886                         $chunk_size = hexdec( trim($temp) );
3887                         $chunkstart = $chunkend;
3888                 }
3889                 return $new;
3890         }
3891
3892         /**
3893          * Writes the payload, including HTTP headers, to $this->outgoing_payload.
3894          *
3895          * @param       string $data HTTP body
3896          * @param       string $cookie_str data for HTTP Cookie header
3897          * @return      void
3898          * @access      private
3899          */
3900         function buildPayload($data, $cookie_str = '') {
3901                 // Note: for cURL connections, $this->outgoing_payload is ignored,
3902                 // as is the Content-Length header, but these are still created as
3903                 // debugging guides.
3904
3905                 // add content-length header
3906                 if ($this->request_method != 'GET') {
3907                         $this->setHeader('Content-Length', strlen($data));
3908                 }
3909
3910                 // start building outgoing payload:
3911                 if ($this->proxy) {
3912                         $uri = $this->url;
3913                 } else {
3914                         $uri = $this->uri;
3915                 }
3916                 $req = "$this->request_method $uri HTTP/$this->protocol_version";
3917                 $this->debug("HTTP request: $req");
3918                 $this->outgoing_payload = "$req\r\n";
3919
3920                 // loop thru headers, serializing
3921                 foreach($this->outgoing_headers as $k => $v){
3922                         $hdr = $k.': '.$v;
3923                         $this->debug("HTTP header: $hdr");
3924                         $this->outgoing_payload .= "$hdr\r\n";
3925                 }
3926
3927                 // add any cookies
3928                 if ($cookie_str != '') {
3929                         $hdr = 'Cookie: '.$cookie_str;
3930                         $this->debug("HTTP header: $hdr");
3931                         $this->outgoing_payload .= "$hdr\r\n";
3932                 }
3933
3934                 // header/body separator
3935                 $this->outgoing_payload .= "\r\n";
3936
3937                 // add data
3938                 $this->outgoing_payload .= $data;
3939         }
3940
3941         /**
3942         * sends the SOAP request via HTTP[S]
3943         *
3944         * @param    string $data message data
3945         * @param        array $cookies cookies to send
3946         * @return       boolean true if OK, false if problem
3947         * @access   private
3948         */
3949         function sendRequest($data, $cookies = NULL) {
3950                 // build cookie string
3951                 $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
3952
3953                 // build payload
3954                 $this->buildPayload($data, $cookie_str);
3955
3956           if ($this->io_method() == 'socket') {
3957                 // send payload
3958                 if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
3959                         $this->setError('couldn\'t write message data to socket');
3960                         $this->debug('couldn\'t write message data to socket');
3961                         return false;
3962                 }
3963                 $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
3964                 return true;
3965           } else if ($this->io_method() == 'curl') {
3966                 // set payload
3967                 // cURL does say this should only be the verb, and in fact it
3968                 // turns out that the URI and HTTP version are appended to this, which
3969                 // some servers refuse to work with (so we no longer use this method!)
3970                 //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
3971                 $curl_headers = array();
3972                 foreach($this->outgoing_headers as $k => $v){
3973                         if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
3974                                 $this->debug("Skip cURL header $k: $v");
3975                         } else {
3976                                 $curl_headers[] = "$k: $v";
3977                         }
3978                 }
3979                 if ($cookie_str != '') {
3980                         $curl_headers[] = 'Cookie: ' . $cookie_str;
3981                 }
3982                 $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
3983                 $this->debug('set cURL HTTP headers');
3984                 if ($this->request_method == "POST") {
3985                         $this->setCurlOption(CURLOPT_POST, 1);
3986                         $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
3987                         $this->debug('set cURL POST data');
3988                 } else {
3989                 }
3990                 // insert custom user-set cURL options
3991                 foreach ($this->ch_options as $key => $val) {
3992                         $this->setCurlOption($key, $val);
3993                 }
3994
3995                 $this->debug('set cURL payload');
3996                 return true;
3997           }
3998         }
3999
4000         /**
4001         * gets the SOAP response via HTTP[S]
4002         *
4003         * @return       string the response (also sets member variables like incoming_payload)
4004         * @access   private
4005         */
4006         function getResponse(){
4007                 $this->incoming_payload = '';
4008
4009           if ($this->io_method() == 'socket') {
4010             // loop until headers have been retrieved
4011             $data = '';
4012             while (!isset($lb)){
4013
4014                         // We might EOF during header read.
4015                         if(feof($this->fp)) {
4016                                 $this->incoming_payload = $data;
4017                                 $this->debug('found no headers before EOF after length ' . strlen($data));
4018                                 $this->debug("received before EOF:\n" . $data);
4019                                 $this->setError('server failed to send headers');
4020                                 return false;
4021                         }
4022
4023                         $tmp = fgets($this->fp, 256);
4024                         $tmplen = strlen($tmp);
4025                         $this->debug("read line of $tmplen bytes: " . trim($tmp));
4026
4027                         if ($tmplen == 0) {
4028                                 $this->incoming_payload = $data;
4029                                 $this->debug('socket read of headers timed out after length ' . strlen($data));
4030                                 $this->debug("read before timeout: " . $data);
4031                                 $this->setError('socket read of headers timed out');
4032                                 return false;
4033                         }
4034
4035                         $data .= $tmp;
4036                         $pos = strpos($data,"\r\n\r\n");
4037                         if($pos > 1){
4038                                 $lb = "\r\n";
4039                         } else {
4040                                 $pos = strpos($data,"\n\n");
4041                                 if($pos > 1){
4042                                         $lb = "\n";
4043                                 }
4044                         }
4045                         // remove 100 headers
4046                         if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) {
4047                                 unset($lb);
4048                                 $data = '';
4049                         }//
4050                 }
4051                 // store header data
4052                 $this->incoming_payload .= $data;
4053                 $this->debug('found end of headers after length ' . strlen($data));
4054                 // process headers
4055                 $header_data = trim(substr($data,0,$pos));
4056                 $header_array = explode($lb,$header_data);
4057                 $this->incoming_headers = array();
4058                 $this->incoming_cookies = array();
4059                 foreach($header_array as $header_line){
4060                         $arr = explode(':',$header_line, 2);
4061                         if(count($arr) > 1){
4062                                 $header_name = strtolower(trim($arr[0]));
4063                                 $this->incoming_headers[$header_name] = trim($arr[1]);
4064                                 if ($header_name == 'set-cookie') {
4065                                         // TODO: allow multiple cookies from parseCookie
4066                                         $cookie = $this->parseCookie(trim($arr[1]));
4067                                         if ($cookie) {
4068                                                 $this->incoming_cookies[] = $cookie;
4069                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
4070                                         } else {
4071                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
4072                                         }
4073                         }
4074                         } else if (isset($header_name)) {
4075                                 // append continuation line to previous header
4076                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
4077                         }
4078                 }
4079
4080                 // loop until msg has been received
4081                 if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
4082                         $content_length =  2147483647;  // ignore any content-length header
4083                         $chunked = true;
4084                         $this->debug("want to read chunked content");
4085                 } elseif (isset($this->incoming_headers['content-length'])) {
4086                         $content_length = $this->incoming_headers['content-length'];
4087                         $chunked = false;
4088                         $this->debug("want to read content of length $content_length");
4089                 } else {
4090                         $content_length =  2147483647;
4091                         $chunked = false;
4092                         $this->debug("want to read content to EOF");
4093                 }
4094                 $data = '';
4095                 do {
4096                         if ($chunked) {
4097                                 $tmp = fgets($this->fp, 256);
4098                                 $tmplen = strlen($tmp);
4099                                 $this->debug("read chunk line of $tmplen bytes");
4100                                 if ($tmplen == 0) {
4101                                         $this->incoming_payload = $data;
4102                                         $this->debug('socket read of chunk length timed out after length ' . strlen($data));
4103                                         $this->debug("read before timeout:\n" . $data);
4104                                         $this->setError('socket read of chunk length timed out');
4105                                         return false;
4106                                 }
4107                                 $content_length = hexdec(trim($tmp));
4108                                 $this->debug("chunk length $content_length");
4109                         }
4110                         $strlen = 0;
4111                     while (($strlen < $content_length) && (!feof($this->fp))) {
4112                         $readlen = min(8192, $content_length - $strlen);
4113                                 $tmp = fread($this->fp, $readlen);
4114                                 $tmplen = strlen($tmp);
4115                                 $this->debug("read buffer of $tmplen bytes");
4116                                 if (($tmplen == 0) && (!feof($this->fp))) {
4117                                         $this->incoming_payload = $data;
4118                                         $this->debug('socket read of body timed out after length ' . strlen($data));
4119                                         $this->debug("read before timeout:\n" . $data);
4120                                         $this->setError('socket read of body timed out');
4121                                         return false;
4122                                 }
4123                                 $strlen += $tmplen;
4124                                 $data .= $tmp;
4125                         }
4126                         if ($chunked && ($content_length > 0)) {
4127                                 $tmp = fgets($this->fp, 256);
4128                                 $tmplen = strlen($tmp);
4129                                 $this->debug("read chunk terminator of $tmplen bytes");
4130                                 if ($tmplen == 0) {
4131                                         $this->incoming_payload = $data;
4132                                         $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
4133                                         $this->debug("read before timeout:\n" . $data);
4134                                         $this->setError('socket read of chunk terminator timed out');
4135                                         return false;
4136                                 }
4137                         }
4138                 } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
4139                 if (feof($this->fp)) {
4140                         $this->debug('read to EOF');
4141                 }
4142                 $this->debug('read body of length ' . strlen($data));
4143                 $this->incoming_payload .= $data;
4144                 $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server');
4145
4146                 // close filepointer
4147                 if(
4148                         (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
4149                         (! $this->persistentConnection) || feof($this->fp)){
4150                         fclose($this->fp);
4151                         $this->fp = false;
4152                         $this->debug('closed socket');
4153                 }
4154
4155                 // connection was closed unexpectedly
4156                 if($this->incoming_payload == ''){
4157                         $this->setError('no response from server');
4158                         return false;
4159                 }
4160
4161                 // decode transfer-encoding
4162 //              if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
4163 //                      if(!$data = $this->decodeChunked($data, $lb)){
4164 //                              $this->setError('Decoding of chunked data failed');
4165 //                              return false;
4166 //                      }
4167                         //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
4168                         // set decoded payload
4169 //                      $this->incoming_payload = $header_data.$lb.$lb.$data;
4170 //              }
4171
4172           } else if ($this->io_method() == 'curl') {
4173                 // send and receive
4174                 $this->debug('send and receive with cURL');
4175                 $this->incoming_payload = curl_exec($this->ch);
4176                 $data = $this->incoming_payload;
4177
4178         $cErr = curl_error($this->ch);
4179                 if ($cErr != '') {
4180                 $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'<br>';
4181                 // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
4182                         foreach(curl_getinfo($this->ch) as $k => $v){
4183                                 $err .= "$k: $v<br>";
4184                         }
4185                         $this->debug($err);
4186                         $this->setError($err);
4187                         curl_close($this->ch);
4188                 return false;
4189                 } else {
4190                         //echo '<pre>';
4191                         //var_dump(curl_getinfo($this->ch));
4192                         //echo '</pre>';
4193                 }
4194                 // close curl
4195                 $this->debug('No cURL error, closing cURL');
4196                 curl_close($this->ch);
4197
4198                 // try removing skippable headers
4199                 $savedata = $data;
4200                 while ($this->isSkippableCurlHeader($data)) {
4201                         $this->debug("Found HTTP header to skip");
4202                         if ($pos = strpos($data,"\r\n\r\n")) {
4203                                 $data = ltrim(substr($data,$pos));
4204                         } elseif($pos = strpos($data,"\n\n") ) {
4205                                 $data = ltrim(substr($data,$pos));
4206                         }
4207                 }
4208
4209                 if ($data == '') {
4210                         // have nothing left; just remove 100 header(s)
4211                         $data = $savedata;
4212                         while (preg_match('/^HTTP\/1.1 100/',$data)) {
4213                                 if ($pos = strpos($data,"\r\n\r\n")) {
4214                                         $data = ltrim(substr($data,$pos));
4215                                 } elseif($pos = strpos($data,"\n\n") ) {
4216                                         $data = ltrim(substr($data,$pos));
4217                                 }
4218                         }
4219                 }
4220
4221                 // separate content from HTTP headers
4222                 if ($pos = strpos($data,"\r\n\r\n")) {
4223                         $lb = "\r\n";
4224                 } elseif( $pos = strpos($data,"\n\n")) {
4225                         $lb = "\n";
4226                 } else {
4227                         $this->debug('no proper separation of headers and document');
4228                         $this->setError('no proper separation of headers and document');
4229                         return false;
4230                 }
4231                 $header_data = trim(substr($data,0,$pos));
4232                 $header_array = explode($lb,$header_data);
4233                 $data = ltrim(substr($data,$pos));
4234                 $this->debug('found proper separation of headers and document');
4235                 $this->debug('cleaned data, stringlen: '.strlen($data));
4236                 // clean headers
4237                 foreach ($header_array as $header_line) {
4238                         $arr = explode(':',$header_line,2);
4239                         if(count($arr) > 1){
4240                                 $header_name = strtolower(trim($arr[0]));
4241                                 $this->incoming_headers[$header_name] = trim($arr[1]);
4242                                 if ($header_name == 'set-cookie') {
4243                                         // TODO: allow multiple cookies from parseCookie
4244                                         $cookie = $this->parseCookie(trim($arr[1]));
4245                                         if ($cookie) {
4246                                                 $this->incoming_cookies[] = $cookie;
4247                                                 $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
4248                                         } else {
4249                                                 $this->debug('did not find cookie in ' . trim($arr[1]));
4250                                         }
4251                         }
4252                         } else if (isset($header_name)) {
4253                                 // append continuation line to previous header
4254                                 $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
4255                         }
4256                 }
4257           }
4258
4259                 $this->response_status_line = $header_array[0];
4260                 $arr = explode(' ', $this->response_status_line, 3);
4261                 $http_version = $arr[0];
4262                 $http_status = intval($arr[1]);
4263                 $http_reason = count($arr) > 2 ? $arr[2] : '';
4264
4265                 // see if we need to resend the request with http digest authentication
4266                 if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
4267                         $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
4268                         $this->setURL($this->incoming_headers['location']);
4269                         $this->tryagain = true;
4270                         return false;
4271                 }
4272
4273                 // see if we need to resend the request with http digest authentication
4274                 if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
4275                         $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
4276                         if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
4277                                 $this->debug('Server wants digest authentication');
4278                                 // remove "Digest " from our elements
4279                                 $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
4280
4281                                 // parse elements into array
4282                                 $digestElements = explode(',', $digestString);
4283                                 foreach ($digestElements as $val) {
4284                                         $tempElement = explode('=', trim($val), 2);
4285                                         $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
4286                                 }
4287
4288                                 // should have (at least) qop, realm, nonce
4289                                 if (isset($digestRequest['nonce'])) {
4290                                         $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
4291                                         $this->tryagain = true;
4292                                         return false;
4293                                 }
4294                         }
4295                         $this->debug('HTTP authentication failed');
4296                         $this->setError('HTTP authentication failed');
4297                         return false;
4298                 }
4299
4300                 if (
4301                         ($http_status >= 300 && $http_status <= 307) ||
4302                         ($http_status >= 400 && $http_status <= 417) ||
4303                         ($http_status >= 501 && $http_status <= 505)
4304                    ) {
4305                         $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
4306                         return false;
4307                 }
4308
4309                 // decode content-encoding
4310                 if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){
4311                         if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){
4312                         // if decoding works, use it. else assume data wasn't gzencoded
4313                         if(function_exists('gzinflate')){
4314                                         //$timer->setMarker('starting decoding of gzip/deflated content');
4315                                         // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
4316                                         // this means there are no Zlib headers, although there should be
4317                                         $this->debug('The gzinflate function exists');
4318                                         $datalen = strlen($data);
4319                                         if ($this->incoming_headers['content-encoding'] == 'deflate') {
4320                                                 if ($degzdata = @gzinflate($data)) {
4321                                                 $data = $degzdata;
4322                                                 $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
4323                                                 if (strlen($data) < $datalen) {
4324                                                         // test for the case that the payload has been compressed twice
4325                                                         $this->debug('The inflated payload is smaller than the gzipped one; try again');
4326                                                                 if ($degzdata = @gzinflate($data)) {
4327                                                                 $data = $degzdata;
4328                                                                 $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
4329                                                                 }
4330                                                 }
4331                                         } else {
4332                                                 $this->debug('Error using gzinflate to inflate the payload');
4333                                                 $this->setError('Error using gzinflate to inflate the payload');
4334                                         }
4335                                         } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
4336                                                 if ($degzdata = @gzinflate(substr($data, 10))) {        // do our best
4337                                                         $data = $degzdata;
4338                                                 $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
4339                                                 if (strlen($data) < $datalen) {
4340                                                         // test for the case that the payload has been compressed twice
4341                                                         $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
4342                                                                 if ($degzdata = @gzinflate(substr($data, 10))) {
4343                                                                 $data = $degzdata;
4344                                                                 $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
4345                                                                 }
4346                                                 }
4347                                         } else {
4348                                                 $this->debug('Error using gzinflate to un-gzip the payload');
4349                                                         $this->setError('Error using gzinflate to un-gzip the payload');
4350                                         }
4351                                         }
4352                                         //$timer->setMarker('finished decoding of gzip/deflated content');
4353                                         //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
4354                                         // set decoded payload
4355                                         $this->incoming_payload = $header_data.$lb.$lb.$data;
4356                         } else {
4357                                         $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
4358                                         $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
4359                                 }
4360                         } else {
4361                                 $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
4362                                 $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
4363                         }
4364                 } else {
4365                         $this->debug('No Content-Encoding header');
4366                 }
4367
4368                 if(strlen($data) == 0){
4369                         $this->debug('no data after headers!');
4370                         $this->setError('no data present after HTTP headers');
4371                         return false;
4372                 }
4373
4374                 return $data;
4375         }
4376
4377         /**
4378          * sets the content-type for the SOAP message to be sent
4379          *
4380          * @param       string $type the content type, MIME style
4381          * @param       mixed $charset character set used for encoding (or false)
4382          * @access      public
4383          */
4384         function setContentType($type, $charset = false) {
4385                 $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
4386         }
4387
4388         /**
4389          * specifies that an HTTP persistent connection should be used
4390          *
4391          * @return      boolean whether the request was honored by this method.
4392          * @access      public
4393          */
4394         function usePersistentConnection(){
4395                 if (isset($this->outgoing_headers['Accept-Encoding'])) {
4396                         return false;
4397                 }
4398                 $this->protocol_version = '1.1';
4399                 $this->persistentConnection = true;
4400                 $this->setHeader('Connection', 'Keep-Alive');
4401                 return true;
4402         }
4403
4404         /**
4405          * parse an incoming Cookie into it's parts
4406          *
4407          * @param       string $cookie_str content of cookie
4408          * @return      array with data of that cookie
4409          * @access      private
4410          */
4411         /*
4412          * TODO: allow a Set-Cookie string to be parsed into multiple cookies
4413          */
4414         function parseCookie($cookie_str) {
4415                 $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
4416                 $data = preg_split('/;/', $cookie_str);
4417                 $value_str = $data[0];
4418
4419                 $cookie_param = 'domain=';
4420                 $start = strpos($cookie_str, $cookie_param);
4421                 if ($start > 0) {
4422                         $domain = substr($cookie_str, $start + strlen($cookie_param));
4423                         $domain = substr($domain, 0, strpos($domain, ';'));
4424                 } else {
4425                         $domain = '';
4426                 }
4427
4428                 $cookie_param = 'expires=';
4429                 $start = strpos($cookie_str, $cookie_param);
4430                 if ($start > 0) {
4431                         $expires = substr($cookie_str, $start + strlen($cookie_param));
4432                         $expires = substr($expires, 0, strpos($expires, ';'));
4433                 } else {
4434                         $expires = '';
4435                 }
4436
4437                 $cookie_param = 'path=';
4438                 $start = strpos($cookie_str, $cookie_param);
4439                 if ( $start > 0 ) {
4440                         $path = substr($cookie_str, $start + strlen($cookie_param));
4441                         $path = substr($path, 0, strpos($path, ';'));
4442                 } else {
4443                         $path = '/';
4444                 }
4445
4446                 $cookie_param = ';secure;';
4447                 if (strpos($cookie_str, $cookie_param) !== FALSE) {
4448                         $secure = true;
4449                 } else {
4450                         $secure = false;
4451                 }
4452
4453                 $sep_pos = strpos($value_str, '=');
4454
4455                 if ($sep_pos) {
4456                         $name = substr($value_str, 0, $sep_pos);
4457                         $value = substr($value_str, $sep_pos + 1);
4458                         $cookie= array( 'name' => $name,
4459                                         'value' => $value,
4460                                                         'domain' => $domain,
4461                                                         'path' => $path,
4462                                                         'expires' => $expires,
4463                                                         'secure' => $secure
4464                                                         );
4465                         return $cookie;
4466                 }
4467                 return false;
4468         }
4469
4470         /**
4471          * sort out cookies for the current request
4472          *
4473          * @param       array $cookies array with all cookies
4474          * @param       boolean $secure is the send-content secure or not?
4475          * @return      string for Cookie-HTTP-Header
4476          * @access      private
4477          */
4478         function getCookiesForRequest($cookies, $secure=false) {
4479                 $cookie_str = '';
4480                 if ((! is_null($cookies)) && (is_array($cookies))) {
4481                         foreach ($cookies as $cookie) {
4482                                 if (! is_array($cookie)) {
4483                                         continue;
4484                                 }
4485                         $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']);
4486                                 if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
4487                                         if (strtotime($cookie['expires']) <= time()) {
4488                                                 $this->debug('cookie has expired');
4489                                                 continue;
4490                                         }
4491                                 }
4492                                 if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) {
4493                                         $domain = preg_quote($cookie['domain']);
4494                                         if (! preg_match("'.*$domain$'i", $this->host)) {
4495                                                 $this->debug('cookie has different domain');
4496                                                 continue;
4497                                         }
4498                                 }
4499                                 if ((isset($cookie['path'])) && (! empty($cookie['path']))) {
4500                                         $path = preg_quote($cookie['path']);
4501                                         if (! preg_match("'^$path.*'i", $this->path)) {
4502                                                 $this->debug('cookie is for a different path');
4503                                                 continue;
4504                                         }
4505                                 }
4506                                 if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
4507                                         $this->debug('cookie is secure, transport is not');
4508                                         continue;
4509                                 }
4510                                 $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
4511                         $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
4512                         }
4513                 }
4514                 return $cookie_str;
4515   }
4516 }
4517
4518 ?><?php
4519
4520 /*
4521
4522 Modification information for LGPL compliance
4523
4524 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
4525     bug 40066
4526
4527 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
4528     Merging with maint_6_0_1 (svn merge -r 58250:58342)
4529
4530 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
4531     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.
4532
4533 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
4534     fix SOAP calls with no parameters
4535
4536 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
4537
4538 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
4539
4540 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
4541
4542 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
4543
4544 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
4545
4546 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.
4547
4548 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.
4549
4550 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:
4551 - Changing all ereg function to either preg or simple string based ones
4552 - No more references to magic quotes.
4553 - Change all the session_unregister() functions to just unset() the correct session variable instead.
4554
4555 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
4556
4557 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
4558
4559 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
4560
4561 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
4562
4563 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
4564
4565 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
4566
4567 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
4568
4569 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
4570
4571 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.
4572 Touched:
4573 - data/SugarBean.php
4574 - include/domit/php_http_client_generic.php
4575 - include/domit/php_http_connector.php
4576 - include/domit/testing_domit.php
4577 - include/domit/xml_domit_getelementsbypath.php
4578 - include/domit/xml_domit_lite_parser.php
4579 - include/domit/xml_domit_nodemaps.php
4580 - include/domit/xml_domit_parser.php
4581 - include/domit/xml_domit_shared.php
4582 - include/generic/SugarWidgets/SugarWidgetField.php
4583 - include/generic/SugarWidgets/SugarWidgetReportField.php
4584 - include/ListView/ProcessView.php
4585 - include/nusoap/class.soapclient.php
4586 - include/nusoap/nusoap.php
4587 - include/nusoap/nusoapmime.php
4588 - include/Pear/HTML_Safe/Safe.php
4589 - include/Pear/XML_HTMLSax3/HTMLSax3.php
4590 - modules/Administration/RebuildWorkFlow.php
4591 - modules/Expressions/RelateSelector.php
4592 - modules/Reports/templates/templates_reports.php
4593 - modules/WorkFlow/Delete.php
4594 - modules/WorkFlow/Save.php
4595 - modules/WorkFlow/SaveSequence.php
4596 - modules/WorkFlow/WorkFlow.php
4597 - modules/WorkFlowActionShells/CreateStep1.php
4598 - modules/WorkFlowActionShells/CreateStep2.php
4599 - modules/WorkFlowActionShells/Save.php
4600 - modules/WorkFlowActionShells/WorkFlowActionShell.php
4601 - modules/WorkFlowAlerts/Save.php
4602 - modules/WorkFlowAlerts/WorkFlowAlert.php
4603 - modules/WorkFlowAlertShells/DetailView.php
4604 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
4605 - modules/WorkFlowTriggerShells/CreateStep1.php
4606 - modules/WorkFlowTriggerShells/CreateStepFilter.php
4607 - modules/WorkFlowTriggerShells/SaveFilter.php
4608 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
4609 - soap/SoapHelperFunctions.php
4610 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
4611 - test/simpletest/browser.php
4612 - test/simpletest/default_reporter.php
4613 - test/simpletest/detached.php
4614 - test/simpletest/eclipse.php
4615 - test/simpletest/expectation.php
4616 - test/simpletest/extensions/pear_test_case.php
4617 - test/simpletest/form.php
4618 - test/simpletest/http.php
4619 - test/simpletest/mock_objects.php
4620 - test/simpletest/page.php
4621 - test/simpletest/parser.php
4622 - test/simpletest/remote.php
4623 - test/simpletest/shell_tester.php
4624 - test/simpletest/simple_test.php
4625 - test/simpletest/simpletest.php
4626 - test/simpletest/test/acceptance_test.php
4627 - test/simpletest/test/adapter_test.php
4628 - test/simpletest/test/authentication_test.php
4629 - test/simpletest/test/browser_test.php
4630 - test/simpletest/test/collector_test.php
4631 - test/simpletest/test/compatibility_test.php
4632 - test/simpletest/test/detached_test.php
4633 - test/simpletest/test/eclipse_test.php
4634 - test/simpletest/test/encoding_test.php
4635 - test/simpletest/test/errors_test.php
4636 - test/simpletest/test/expectation_test.php
4637 - test/simpletest/test/form_test.php
4638 - test/simpletest/test/frames_test.php
4639 - test/simpletest/test/http_test.php
4640 - test/simpletest/test/live_test.php
4641 - test/simpletest/test/mock_objects_test.php
4642 - test/simpletest/test/page_test.php
4643 - test/simpletest/test/parse_error_test.php
4644 - test/simpletest/test/parser_test.php
4645 - test/simpletest/test/remote_test.php
4646 - test/simpletest/test/shell_test.php
4647 - test/simpletest/test/shell_tester_test.php
4648 - test/simpletest/test/simpletest_test.php
4649 - test/simpletest/test/site/page_request.php
4650 - test/simpletest/test/tag_test.php
4651 - test/simpletest/test/unit_tester_test.php
4652 - test/simpletest/test/user_agent_test.php
4653 - test/simpletest/test/visual_test.php
4654 - test/simpletest/test/xml_test.php
4655 - test/simpletest/test_case.php
4656 - test/simpletest/ui/array_reporter/test.php
4657 - test/simpletest/ui/recorder/test.php
4658 - test/simpletest/unit_tester.php
4659 - test/simpletest/url.php
4660 - test/simpletest/user_agent.php
4661 - test/simpletest/web_tester.php
4662 - test/spikephpcoverage/src/PEAR.php
4663 - test/spikephpcoverage/src/util/Utility.php
4664 - test/spikephpcoverage/src/XML/Parser.php
4665 - test/spikephpcoverage/src/XML/Parser/Simple.php
4666 - test/test_utilities/SugarTest_SimpleBrowser.php
4667
4668 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.
4669
4670 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
4671
4672 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
4673
4674 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
4675
4676 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
4677
4678 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
4679
4680 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
4681
4682 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
4683
4684 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
4685
4686 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
4687
4688 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
4689
4690 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
4691
4692 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.
4693
4694 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
4695
4696 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
4697
4698 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
4699
4700 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
4701
4702 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
4703
4704 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
4705
4706 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
4707
4708 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
4709
4710 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
4711
4712 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
4713
4714 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
4715
4716
4717 */
4718
4719
4720
4721
4722
4723 /**
4724 *
4725 * nusoap_server allows the user to create a SOAP server
4726 * that is capable of receiving messages and returning responses
4727 *
4728 * @author   Dietrich Ayala <dietrich@ganx4.com>
4729 * @author   Scott Nichol <snichol@users.sourceforge.net>
4730
4731 * @access   public
4732 */
4733 class nusoap_server extends nusoap_base {
4734         /**
4735          * HTTP headers of request
4736          * @var array
4737          * @access private
4738          */
4739         var $headers = array();
4740         /**
4741          * HTTP request
4742          * @var string
4743          * @access private
4744          */
4745         var $request = '';
4746         /**
4747          * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
4748          * @var string
4749          * @access public
4750          */
4751         var $requestHeaders = '';
4752         /**
4753          * SOAP Headers from request (parsed)
4754          * @var mixed
4755          * @access public
4756          */
4757         var $requestHeader = NULL;
4758         /**
4759          * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
4760          * @var string
4761          * @access public
4762          */
4763         var $document = '';
4764         /**
4765          * SOAP payload for request (text)
4766          * @var string
4767          * @access public
4768          */
4769         var $requestSOAP = '';
4770         /**
4771          * requested method namespace URI
4772          * @var string
4773          * @access private
4774          */
4775         var $methodURI = '';
4776         /**
4777          * name of method requested
4778          * @var string
4779          * @access private
4780          */
4781         var $methodname = '';
4782         /**
4783          * method parameters from request
4784          * @var array
4785          * @access private
4786          */
4787         var $methodparams = array();
4788         /**
4789          * SOAP Action from request
4790          * @var string
4791          * @access private
4792          */
4793         var $SOAPAction = '';
4794         /**
4795          * character set encoding of incoming (request) messages
4796          * @var string
4797          * @access public
4798          */
4799         var $xml_encoding = '';
4800         /**
4801          * toggles whether the parser decodes element content w/ utf8_decode()
4802          * @var boolean
4803          * @access public
4804          */
4805     var $decode_utf8 = false;
4806
4807         /**
4808          * HTTP headers of response
4809          * @var array
4810          * @access public
4811          */
4812         var $outgoing_headers = array();
4813         /**
4814          * HTTP response
4815          * @var string
4816          * @access private
4817          */
4818         var $response = '';
4819         /**
4820          * SOAP headers for response (text or array of soapval or associative array)
4821          * @var mixed
4822          * @access public
4823          */
4824         var $responseHeaders = '';
4825         /**
4826          * SOAP payload for response (text)
4827          * @var string
4828          * @access private
4829          */
4830         var $responseSOAP = '';
4831         /**
4832          * method return value to place in response
4833          * @var mixed
4834          * @access private
4835          */
4836         var $methodreturn = false;
4837         /**
4838          * whether $methodreturn is a string of literal XML
4839          * @var boolean
4840          * @access public
4841          */
4842         var $methodreturnisliteralxml = false;
4843         /**
4844          * SOAP fault for response (or false)
4845          * @var mixed
4846          * @access private
4847          */
4848         var $fault = false;
4849         /**
4850          * text indication of result (for debugging)
4851          * @var string
4852          * @access private
4853          */
4854         var $result = 'successful';
4855
4856         /**
4857          * assoc array of operations => opData; operations are added by the register()
4858          * method or by parsing an external WSDL definition
4859          * @var array
4860          * @access private
4861          */
4862         var $operations = array();
4863         /**
4864          * wsdl instance (if one)
4865          * @var mixed
4866          * @access private
4867          */
4868         var $wsdl = false;
4869         /**
4870          * URL for WSDL (if one)
4871          * @var mixed
4872          * @access private
4873          */
4874         var $externalWSDLURL = false;
4875         /**
4876          * whether to append debug to response as XML comment
4877          * @var boolean
4878          * @access public
4879          */
4880         var $debug_flag = false;
4881
4882
4883         /**
4884         * constructor
4885     * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
4886         *
4887     * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
4888         * @access   public
4889         */
4890         function nusoap_server($wsdl=false){
4891                 parent::nusoap_base();
4892                 // turn on debugging?
4893                 global $debug;
4894                 global $HTTP_SERVER_VARS;
4895
4896                 if (isset($_SERVER)) {
4897                         $this->debug("_SERVER is defined:");
4898                         $this->appendDebug($this->varDump($_SERVER));
4899                 } elseif (isset($HTTP_SERVER_VARS)) {
4900                         $this->debug("HTTP_SERVER_VARS is defined:");
4901                         $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
4902                 } else {
4903                         $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
4904                 }
4905
4906                 if (isset($debug)) {
4907                         $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
4908                         $this->debug_flag = $debug;
4909                 } elseif (isset($_SERVER['QUERY_STRING'])) {
4910                         $qs = explode('&', $_SERVER['QUERY_STRING']);
4911                         foreach ($qs as $v) {
4912                                 if (substr($v, 0, 6) == 'debug=') {
4913                                         $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
4914                                         $this->debug_flag = substr($v, 6);
4915                                 }
4916                         }
4917                 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
4918                         $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
4919                         foreach ($qs as $v) {
4920                                 if (substr($v, 0, 6) == 'debug=') {
4921                                         $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
4922                                         $this->debug_flag = substr($v, 6);
4923                                 }
4924                         }
4925                 }
4926
4927                 // wsdl
4928                 if($wsdl){
4929                         $this->debug("In nusoap_server, WSDL is specified");
4930                         if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
4931                                 $this->wsdl = $wsdl;
4932                                 $this->externalWSDLURL = $this->wsdl->wsdl;
4933                                 $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
4934                         } else {
4935                                 $this->debug('Create wsdl from ' . $wsdl);
4936                                 $this->wsdl = new wsdl($wsdl);
4937                                 $this->externalWSDLURL = $wsdl;
4938                         }
4939                         $this->appendDebug($this->wsdl->getDebug());
4940                         $this->wsdl->clearDebug();
4941                         if($err = $this->wsdl->getError()){
4942                                 die('WSDL ERROR: '.$err);
4943                         }
4944                 }
4945         }
4946
4947         /**
4948         * processes request and returns response
4949         *
4950         * @param    string $data usually is the value of $HTTP_RAW_POST_DATA
4951         * @access   public
4952         */
4953         function service($data){
4954                 global $HTTP_SERVER_VARS;
4955
4956                 if (isset($_SERVER['REQUEST_METHOD'])) {
4957                         $rm = $_SERVER['REQUEST_METHOD'];
4958                 } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
4959                         $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
4960                 } else {
4961                         $rm = '';
4962                 }
4963
4964                 if (isset($_SERVER['QUERY_STRING'])) {
4965                         $qs = $_SERVER['QUERY_STRING'];
4966                 } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
4967                         $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
4968                 } else {
4969                         $qs = '';
4970                 }
4971                 $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
4972
4973                 if ($rm == 'POST') {
4974                         $this->debug("In service, invoke the request");
4975                         $this->parse_request($data);
4976                         if (! $this->fault) {
4977                                 $this->invoke_method();
4978                         }
4979                         if (! $this->fault) {
4980                                 $this->serialize_return();
4981                         }
4982                         $this->send_response();
4983                 } elseif (preg_match('/wsdl/', $qs) ){
4984                         $this->debug("In service, this is a request for WSDL");
4985                         if ($this->externalWSDLURL){
4986               if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
4987                                 $this->debug("In service, re-direct for WSDL");
4988                                 header('Location: '.$this->externalWSDLURL);
4989               } else { // assume file
4990                                 $this->debug("In service, use file passthru for WSDL");
4991                 header("Content-Type: text/xml\r\n");
4992                                 $pos = strpos($this->externalWSDLURL, "file://");
4993                                 if ($pos === false) {
4994                                         $filename = $this->externalWSDLURL;
4995                                 } else {
4996                                         $filename = substr($this->externalWSDLURL, $pos + 7);
4997                                 }
4998                 $fp = fopen($this->externalWSDLURL, 'r');
4999                 fpassthru($fp);
5000               }
5001                         } elseif ($this->wsdl) {
5002                                 $this->debug("In service, serialize WSDL");
5003                                 header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
5004                                 print $this->wsdl->serialize($this->debug_flag);
5005                                 if ($this->debug_flag) {
5006                                         $this->debug('wsdl:');
5007                                         $this->appendDebug($this->varDump($this->wsdl));
5008                                         print $this->getDebugAsXMLComment();
5009                                 }
5010                         } else {
5011                                 $this->debug("In service, there is no WSDL");
5012                                 header("Content-Type: text/html; charset=ISO-8859-1\r\n");
5013                                 print "This service does not provide WSDL";
5014                         }
5015                 } elseif ($this->wsdl) {
5016                         $this->debug("In service, return Web description");
5017                         print $this->wsdl->webDescription();
5018                 } else {
5019                         $this->debug("In service, no Web description");
5020                         header("Content-Type: text/html; charset=ISO-8859-1\r\n");
5021                         print "This service does not provide a Web description";
5022                 }
5023         }
5024
5025         /**
5026         * parses HTTP request headers.
5027         *
5028         * The following fields are set by this function (when successful)
5029         *
5030         * headers
5031         * request
5032         * xml_encoding
5033         * SOAPAction
5034         *
5035         * @access   private
5036         */
5037         function parse_http_headers() {
5038                 global $HTTP_SERVER_VARS;
5039
5040                 $this->request = '';
5041                 $this->SOAPAction = '';
5042                 if(function_exists('getallheaders')){
5043                         $this->debug("In parse_http_headers, use getallheaders");
5044                         $headers = getallheaders();
5045                         foreach($headers as $k=>$v){
5046                                 $k = strtolower($k);
5047                                 $this->headers[$k] = $v;
5048                                 $this->request .= "$k: $v\r\n";
5049                                 $this->debug("$k: $v");
5050                         }
5051                         // get SOAPAction header
5052                         if(isset($this->headers['soapaction'])){
5053                                 $this->SOAPAction = str_replace('"','',$this->headers['soapaction']);
5054                         }
5055                         // get the character encoding of the incoming request
5056                         if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){
5057                                 $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1));
5058                                 if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
5059                                         $this->xml_encoding = strtoupper($enc);
5060                                 } else {
5061                                         $this->xml_encoding = 'US-ASCII';
5062                                 }
5063                         } else {
5064                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5065                                 $this->xml_encoding = 'ISO-8859-1';
5066                         }
5067                 } elseif(isset($_SERVER) && is_array($_SERVER)){
5068                         $this->debug("In parse_http_headers, use _SERVER");
5069                         foreach ($_SERVER as $k => $v) {
5070                                 if (substr($k, 0, 5) == 'HTTP_') {
5071                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
5072                                 } else {
5073                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
5074                                 }
5075                                 if ($k == 'soapaction') {
5076                                         // get SOAPAction header
5077                                         $k = 'SOAPAction';
5078                                         $v = str_replace('"', '', $v);
5079                                         $v = str_replace('\\', '', $v);
5080                                         $this->SOAPAction = $v;
5081                                 } else if ($k == 'content-type') {
5082                                         // get the character encoding of the incoming request
5083                                         if (strpos($v, '=')) {
5084                                                 $enc = substr(strstr($v, '='), 1);
5085                                                 $enc = str_replace('"', '', $enc);
5086                                                 $enc = str_replace('\\', '', $enc);
5087                                                 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
5088                                                         $this->xml_encoding = strtoupper($enc);
5089                                                 } else {
5090                                                         $this->xml_encoding = 'US-ASCII';
5091                                                 }
5092                                         } else {
5093                                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5094                                                 $this->xml_encoding = 'ISO-8859-1';
5095                                         }
5096                                 }
5097                                 $this->headers[$k] = $v;
5098                                 $this->request .= "$k: $v\r\n";
5099                                 $this->debug("$k: $v");
5100                         }
5101                 } elseif (is_array($HTTP_SERVER_VARS)) {
5102                         $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
5103                         foreach ($HTTP_SERVER_VARS as $k => $v) {
5104                                 if (substr($k, 0, 5) == 'HTTP_') {
5105                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));                                            $k = strtolower(substr($k, 5));
5106                                 } else {
5107                                         $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));                                               $k = strtolower($k);
5108                                 }
5109                                 if ($k == 'soapaction') {
5110                                         // get SOAPAction header
5111                                         $k = 'SOAPAction';
5112                                         $v = str_replace('"', '', $v);
5113                                         $v = str_replace('\\', '', $v);
5114                                         $this->SOAPAction = $v;
5115                                 } else if ($k == 'content-type') {
5116                                         // get the character encoding of the incoming request
5117                                         if (strpos($v, '=')) {
5118                                                 $enc = substr(strstr($v, '='), 1);
5119                                                 $enc = str_replace('"', '', $enc);
5120                                                 $enc = str_replace('\\', '', $enc);
5121                                                 if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) {
5122                                                         $this->xml_encoding = strtoupper($enc);
5123                                                 } else {
5124                                                         $this->xml_encoding = 'US-ASCII';
5125                                                 }
5126                                         } else {
5127                                                 // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5128                                                 $this->xml_encoding = 'ISO-8859-1';
5129                                         }
5130                                 }
5131                                 $this->headers[$k] = $v;
5132                                 $this->request .= "$k: $v\r\n";
5133                                 $this->debug("$k: $v");
5134                         }
5135                 } else {
5136                         $this->debug("In parse_http_headers, HTTP headers not accessible");
5137                         $this->setError("HTTP headers not accessible");
5138                 }
5139         }
5140
5141         /**
5142         * parses a request
5143         *
5144         * The following fields are set by this function (when successful)
5145         *
5146         * headers
5147         * request
5148         * xml_encoding
5149         * SOAPAction
5150         * request
5151         * requestSOAP
5152         * methodURI
5153         * methodname
5154         * methodparams
5155         * requestHeaders
5156         * document
5157         *
5158         * This sets the fault field on error
5159         *
5160         * @param    string $data XML string
5161         * @access   private
5162         */
5163         function parse_request($data='') {
5164                 $this->debug('entering parse_request()');
5165                 $this->parse_http_headers();
5166                 $this->debug('got character encoding: '.$this->xml_encoding);
5167                 // uncompress if necessary
5168                 if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
5169                         $this->debug('got content encoding: ' . $this->headers['content-encoding']);
5170                         if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
5171                         // if decoding works, use it. else assume data wasn't gzencoded
5172                                 if (function_exists('gzuncompress')) {
5173                                         if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
5174                                                 $data = $degzdata;
5175                                         } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
5176                                                 $data = $degzdata;
5177                                         } else {
5178                                                 $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
5179                                                 return;
5180                                         }
5181                                 } else {
5182                                         $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
5183                                         return;
5184                                 }
5185                         }
5186                 }
5187                 $this->request .= "\r\n".$data;
5188                 $data = $this->parseRequest($this->headers, $data);
5189                 $this->requestSOAP = $data;
5190                 $this->debug('leaving parse_request');
5191         }
5192
5193         function register_class($classname){
5194                 $this->registeredClass = $classname;
5195         }
5196         /**
5197         * invokes a PHP function for the requested SOAP method
5198         *
5199         * The following fields are set by this function (when successful)
5200         *
5201         * methodreturn
5202         *
5203         * Note that the PHP function that is called may also set the following
5204         * fields to affect the response sent to the client
5205         *
5206         * responseHeaders
5207         * outgoing_headers
5208         *
5209         * This sets the fault field on error
5210         *
5211         * @access   private
5212         */
5213         function invoke_method() {
5214                 $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
5215
5216                 //
5217                 // if you are debugging in this area of the code, your service uses a class to implement methods,
5218                 // you use SOAP RPC, and the client is .NET, please be aware of the following...
5219                 // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
5220                 // method name.  that is fine for naming the .NET methods.  it is not fine for properly constructing
5221                 // the XML request and reading the XML response.  you need to add the RequestElementName and
5222                 // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
5223                 // generates for the method.  these parameters are used to specify the correct XML element names
5224                 // for .NET to use, i.e. the names with the '.' in them.
5225                 //
5226                 $orig_methodname = $this->methodname;
5227                 if ($this->wsdl) {
5228                         if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
5229                                 $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
5230                                 $this->appendDebug('opData=' . $this->varDump($this->opData));
5231                         } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
5232                                 // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
5233                                 $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
5234                                 $this->appendDebug('opData=' . $this->varDump($this->opData));
5235                                 $this->methodname = $this->opData['name'];
5236                         } else {
5237                                 $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
5238                                 $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
5239                                 return;
5240                         }
5241                 } else {
5242                         $this->debug('in invoke_method, no WSDL to validate method');
5243                 }
5244
5245                 // if a . is present in $this->methodname, we see if there is a class in scope,
5246                 // which could be referred to. We will also distinguish between two deliminators,
5247                 // to allow methods to be called a the class or an instance
5248                 if (strpos($this->methodname, '..') > 0) {
5249                         $delim = '..';
5250                 } else if (strpos($this->methodname, '.') > 0) {
5251                         $delim = '.';
5252                 } else {
5253                         $delim = '';
5254                 }
5255                 $this->debug("in invoke_method, delim=$delim");
5256
5257                 $class = '';
5258                 $method = '';
5259                 if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
5260                         $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
5261                         if (class_exists($try_class)) {
5262                                 // get the class and method name
5263                                 $class = $try_class;
5264                                 $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
5265                                 $this->debug("in invoke_method, class=$class method=$method delim=$delim");
5266                         } else {
5267                                 $this->debug("in invoke_method, class=$try_class not found");
5268                         }
5269                 } else {
5270                         $try_class = '';
5271                         $this->debug("in invoke_method, no class to try");
5272                 }
5273                 if(empty($delim) && isset($this->registeredClass)){
5274                         $class  = $this->registeredClass;
5275                         $delim = '..';
5276                         $method = $this->methodname;
5277                 }
5278
5279                 // does method exist?
5280                 if ($class == '') {
5281                         if (!function_exists($this->methodname)) {
5282                                 $this->debug("in invoke_method, function '$this->methodname' not found!");
5283                                 $this->result = 'fault: method not found';
5284                                 $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
5285                                 return;
5286                         }
5287                 } else {
5288                         $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
5289                         if (!in_array($method_to_compare, get_class_methods($class))) {
5290                                 $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
5291                                 $this->result = 'fault: method not found';
5292                                 $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
5293                                 return;
5294                         }
5295                 }
5296
5297                 // evaluate message, getting back parameters
5298                 // verify that request parameters match the method's signature
5299                 if(! $this->verify_method($this->methodname,$this->methodparams)){
5300                         // debug
5301                         $this->debug('ERROR: request not verified against method signature');
5302                         $this->result = 'fault: request failed validation against method signature';
5303                         // return fault
5304                         $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service.");
5305                         return;
5306                 }
5307
5308                 // if there are parameters to pass
5309                 $this->debug('in invoke_method, params:');
5310                 $this->appendDebug($this->varDump($this->methodparams));
5311                 $this->debug("in invoke_method, calling '$this->methodname'");
5312                 if (!function_exists('call_user_func_array')) {
5313                         if ($class == '') {
5314                                 $this->debug('in invoke_method, calling function using eval()');
5315                                 $funcCall = "\$this->methodreturn = $this->methodname(";
5316                         } else {
5317                                 if ($delim == '..') {
5318                                         $this->debug('in invoke_method, calling class method using eval()');
5319                                         $funcCall = "\$this->methodreturn = ".$class."::".$method."(";
5320                                 } else {
5321                                         $this->debug('in invoke_method, calling instance method using eval()');
5322                                         // generate unique instance name
5323                                         $instname = "\$inst_".time();
5324                                         $funcCall = $instname." = new ".$class."(); ";
5325                                         $funcCall .= "\$this->methodreturn = ".$instname."->".$method."(";
5326                                 }
5327                         }
5328                         if ($this->methodparams) {
5329                                 foreach ($this->methodparams as $param) {
5330                                         if (is_array($param) || is_object($param)) {
5331                                                 $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
5332                                                 return;
5333                                         }
5334                                         $funcCall .= "\"$param\",";
5335                                 }
5336                                 $funcCall = substr($funcCall, 0, -1);
5337                         }
5338                         $funcCall .= ');';
5339                         $this->debug('in invoke_method, function call: '.$funcCall);
5340                         @eval($funcCall);
5341                 } else {
5342                         if ($class == '') {
5343                                 $this->debug('in invoke_method, calling function using call_user_func_array()');
5344                                 $call_arg = "$this->methodname";        // straight assignment changes $this->methodname to lower case after call_user_func_array()
5345                         } elseif ($delim == '..') {
5346                                 $this->debug('in invoke_method, calling class method using call_user_func_array()');
5347                                 $call_arg = array ($class, $method);
5348                         } else {
5349                                 $this->debug('in invoke_method, calling instance method using call_user_func_array()');
5350                                 $instance = new $class ();
5351                                 $call_arg = array(&$instance, $method);
5352                         }
5353                         if (is_array($this->methodparams)) {
5354                                 $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
5355                         } else {
5356                                 $this->methodreturn = call_user_func_array($call_arg, array());
5357                         }
5358                 }
5359         $this->debug('in invoke_method, methodreturn:');
5360         $this->appendDebug($this->varDump($this->methodreturn));
5361                 $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn));
5362         }
5363
5364         /**
5365         * serializes the return value from a PHP function into a full SOAP Envelope
5366         *
5367         * The following fields are set by this function (when successful)
5368         *
5369         * responseSOAP
5370         *
5371         * This sets the fault field on error
5372         *
5373         * @access   private
5374         */
5375         function serialize_return() {
5376                 $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
5377                 // if fault
5378                 if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
5379                         $this->debug('got a fault object from method');
5380                         $this->fault = $this->methodreturn;
5381                         return;
5382                 } elseif ($this->methodreturnisliteralxml) {
5383                         $return_val = $this->methodreturn;
5384                 // returned value(s)
5385                 } else {
5386                         $this->debug('got a(n) '.gettype($this->methodreturn).' from method');
5387                         $this->debug('serializing return value');
5388                         if($this->wsdl){
5389                                 if (sizeof($this->opData['output']['parts']) > 1) {
5390                                         $this->debug('more than one output part, so use the method return unchanged');
5391                                 $opParams = $this->methodreturn;
5392                             } elseif (sizeof($this->opData['output']['parts']) == 1) {
5393                                         $this->debug('exactly one output part, so wrap the method return in a simple array');
5394                                         // TODO: verify that it is not already wrapped!
5395                                 //foreach ($this->opData['output']['parts'] as $name => $type) {
5396                                         //      $this->debug('wrap in element named ' . $name);
5397                                 //}
5398                                 $opParams = array($this->methodreturn);
5399                             }
5400                             $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams);
5401                             $this->appendDebug($this->wsdl->getDebug());
5402                             $this->wsdl->clearDebug();
5403                                 if($errstr = $this->wsdl->getError()){
5404                                         $this->debug('got wsdl error: '.$errstr);
5405                                         $this->fault('SOAP-ENV:Server', 'unable to serialize result');
5406                                         return;
5407                                 }
5408                         } else {
5409                                 if (isset($this->methodreturn)) {
5410                                         $return_val = $this->serialize_val($this->methodreturn, 'return');
5411                                 } else {
5412                                         $return_val = '';
5413                                         $this->debug('in absence of WSDL, assume void return for backward compatibility');
5414                                 }
5415                         }
5416                 }
5417                 $this->debug('return value:');
5418                 $this->appendDebug($this->varDump($return_val));
5419
5420                 $this->debug('serializing response');
5421                 if ($this->wsdl) {
5422                         $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
5423                         if ($this->opData['style'] == 'rpc') {
5424                                 $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
5425                                 if ($this->opData['output']['use'] == 'literal') {
5426                                         // 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
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                                 } else {
5433                                         if ($this->methodURI) {
5434                                                 $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
5435                                         } else {
5436                                                 $payload = '<'.$this->methodname.'Response>'.$return_val.'</'.$this->methodname.'Response>';
5437                                         }
5438                                 }
5439                         } else {
5440                                 $this->debug('style is not rpc for serialization: assume document');
5441                                 $payload = $return_val;
5442                         }
5443                 } else {
5444                         $this->debug('do not have WSDL for serialization: assume rpc/encoded');
5445                         $payload = '<ns1:'.$this->methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'</ns1:'.$this->methodname."Response>";
5446                 }
5447                 $this->result = 'successful';
5448                 if($this->wsdl){
5449                         //if($this->debug_flag){
5450                 $this->appendDebug($this->wsdl->getDebug());
5451             //  }
5452                         if (isset($this->opData['output']['encodingStyle'])) {
5453                                 $encodingStyle = $this->opData['output']['encodingStyle'];
5454                         } else {
5455                                 $encodingStyle = '';
5456                         }
5457                         // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
5458                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle);
5459                 } else {
5460                         $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders);
5461                 }
5462                 $this->debug("Leaving serialize_return");
5463         }
5464
5465         /**
5466         * sends an HTTP response
5467         *
5468         * The following fields are set by this function (when successful)
5469         *
5470         * outgoing_headers
5471         * response
5472         *
5473         * @access   private
5474         */
5475         function send_response() {
5476                 $this->debug('Enter send_response');
5477                 if ($this->fault) {
5478                         $payload = $this->fault->serialize();
5479                         $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
5480                         $this->outgoing_headers[] = "Status: 500 Internal Server Error";
5481                 } else {
5482                         $payload = $this->responseSOAP;
5483                         // Some combinations of PHP+Web server allow the Status
5484                         // to come through as a header.  Since OK is the default
5485                         // just do nothing.
5486                         // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
5487                         // $this->outgoing_headers[] = "Status: 200 OK";
5488                 }
5489         // add debug data if in debug mode
5490                 if(isset($this->debug_flag) && $this->debug_flag){
5491                 $payload .= $this->getDebugAsXMLComment();
5492         }
5493                 $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
5494                 preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
5495                 $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")";
5496                 // Let the Web server decide about this
5497                 //$this->outgoing_headers[] = "Connection: Close\r\n";
5498                 $payload = $this->getHTTPBody($payload);
5499                 $type = $this->getHTTPContentType();
5500                 $charset = $this->getHTTPContentTypeCharset();
5501                 $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
5502                 //begin code to compress payload - by John
5503                 // NOTE: there is no way to know whether the Web server will also compress
5504                 // this data.
5505                 if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
5506                         if (strstr($this->headers['accept-encoding'], 'gzip')) {
5507                                 if (function_exists('gzencode')) {
5508                                         if (isset($this->debug_flag) && $this->debug_flag) {
5509                                                 $payload .= "<!-- Content being gzipped -->";
5510                                         }
5511                                         $this->outgoing_headers[] = "Content-Encoding: gzip";
5512                                         $payload = gzencode($payload);
5513                                 } else {
5514                                         if (isset($this->debug_flag) && $this->debug_flag) {
5515                                                 $payload .= "<!-- Content will not be gzipped: no gzencode -->";
5516                                         }
5517                                 }
5518                         } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
5519                                 // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
5520                                 // instead of gzcompress output,
5521                                 // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
5522                                 if (function_exists('gzdeflate')) {
5523                                         if (isset($this->debug_flag) && $this->debug_flag) {
5524                                                 $payload .= "<!-- Content being deflated -->";
5525                                         }
5526                                         $this->outgoing_headers[] = "Content-Encoding: deflate";
5527                                         $payload = gzdeflate($payload);
5528                                 } else {
5529                                         if (isset($this->debug_flag) && $this->debug_flag) {
5530                                                 $payload .= "<!-- Content will not be deflated: no gzcompress -->";
5531                                         }
5532                                 }
5533                         }
5534                 }
5535                 //end code
5536                 ob_end_clean();
5537                 ob_start();
5538                 $this->outgoing_headers[] = "Content-Length: ".strlen($payload);
5539                 reset($this->outgoing_headers);
5540                 foreach($this->outgoing_headers as $hdr){
5541                         header($hdr, false);
5542                 }
5543                 print $payload;
5544                 ob_flush();
5545
5546                 $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload;
5547         }
5548
5549         /**
5550         * takes the value that was created by parsing the request
5551         * and compares to the method's signature, if available.
5552         *
5553         * @param        string  $operation      The operation to be invoked
5554         * @param        array   $request        The array of parameter values
5555         * @return       boolean Whether the operation was found
5556         * @access   private
5557         */
5558         function verify_method($operation,$request){
5559                 if(isset($this->wsdl) && is_object($this->wsdl)){
5560                         if($this->wsdl->getOperationData($operation)){
5561                                 return true;
5562                         }
5563             } elseif(isset($this->operations[$operation])){
5564                         return true;
5565                 }
5566                 return false;
5567         }
5568
5569         /**
5570         * processes SOAP message received from client
5571         *
5572         * @param        array   $headers        The HTTP headers
5573         * @param        string  $data           unprocessed request data from client
5574         * @return       mixed   value of the message, decoded into a PHP type
5575         * @access   private
5576         */
5577     function parseRequest($headers, $data) {
5578                 $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
5579                 $this->appendDebug($this->varDump($headers));
5580         if (!isset($headers['content-type'])) {
5581                         $this->setError('Request not of type text/xml (no content-type header)');
5582                         return false;
5583         }
5584                 if (!strstr($headers['content-type'], 'text/xml')) {
5585                         $this->setError('Request not of type text/xml');
5586                         return false;
5587                 }
5588                 if (strpos($headers['content-type'], '=')) {
5589                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
5590                         $this->debug('Got response encoding: ' . $enc);
5591                         if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
5592                                 $this->xml_encoding = strtoupper($enc);
5593                         } else {
5594                                 $this->xml_encoding = 'US-ASCII';
5595                         }
5596                 } else {
5597                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
5598                         $this->xml_encoding = 'ISO-8859-1';
5599                 }
5600                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
5601                 // parse response, get soap parser obj
5602                 $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8);
5603                 // parser debug
5604                 $this->debug("parser debug: \n".$parser->getDebug());
5605                 // if fault occurred during message parsing
5606                 if($err = $parser->getError()){
5607                         $this->result = 'fault: error in msg parsing: '.$err;
5608                         $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err);
5609                 // else successfully parsed request into soapval object
5610                 } else {
5611                         // get/set methodname
5612                         $this->methodURI = $parser->root_struct_namespace;
5613                         $this->methodname = $parser->root_struct_name;
5614                         $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI);
5615                         $this->debug('calling parser->get_soapbody()');
5616                         $this->methodparams = $parser->get_soapbody();
5617                         // get SOAP headers
5618                         $this->requestHeaders = $parser->getHeaders();
5619                         // get SOAP Header
5620                         $this->requestHeader = $parser->get_soapheader();
5621             // add document for doclit support
5622             $this->document = $parser->document;
5623                 }
5624          }
5625
5626         /**
5627         * gets the HTTP body for the current response.
5628         *
5629         * @param string $soapmsg The SOAP payload
5630         * @return string The HTTP body, which includes the SOAP payload
5631         * @access private
5632         */
5633         function getHTTPBody($soapmsg) {
5634                 return $soapmsg;
5635         }
5636
5637         /**
5638         * gets the HTTP content type for the current response.
5639         *
5640         * Note: getHTTPBody must be called before this.
5641         *
5642         * @return string the HTTP content type for the current response.
5643         * @access private
5644         */
5645         function getHTTPContentType() {
5646                 return 'text/xml';
5647         }
5648
5649         /**
5650         * gets the HTTP content type charset for the current response.
5651         * returns false for non-text content types.
5652         *
5653         * Note: getHTTPBody must be called before this.
5654         *
5655         * @return string the HTTP content type charset for the current response.
5656         * @access private
5657         */
5658         function getHTTPContentTypeCharset() {
5659                 return $this->soap_defencoding;
5660         }
5661
5662         /**
5663         * add a method to the dispatch map (this has been replaced by the register method)
5664         *
5665         * @param    string $methodname
5666         * @param    string $in array of input values
5667         * @param    string $out array of output values
5668         * @access   public
5669         * @deprecated
5670         */
5671         function add_to_map($methodname,$in,$out){
5672                         $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out);
5673         }
5674
5675         /**
5676         * register a service function with the server
5677         *
5678         * @param    string $name the name of the PHP function, class.method or class..method
5679         * @param    array $in assoc array of input values: key = param name, value = param type
5680         * @param    array $out assoc array of output values: key = param name, value = param type
5681         * @param        mixed $namespace the element namespace for the method or false
5682         * @param        mixed $soapaction the soapaction for the method or false
5683         * @param        mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
5684         * @param        mixed $use optional (encoded|literal) or false
5685         * @param        string $documentation optional Description to include in WSDL
5686         * @param        string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
5687         * @access   public
5688         */
5689         function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){
5690                 global $HTTP_SERVER_VARS;
5691
5692                 if($this->externalWSDLURL){
5693                         die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
5694                 }
5695                 if (! $name) {
5696                         die('You must specify a name when you register an operation');
5697                 }
5698                 if (!is_array($in)) {
5699                         die('You must provide an array for operation inputs');
5700                 }
5701                 if (!is_array($out)) {
5702                         die('You must provide an array for operation outputs');
5703                 }
5704                 if(false == $namespace) {
5705                 }
5706                 if(false == $soapaction) {
5707                         if (isset($_SERVER)) {
5708                                 $SERVER_NAME = $_SERVER['SERVER_NAME'];
5709                                 $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
5710                                 $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
5711                         } elseif (isset($HTTP_SERVER_VARS)) {
5712                                 $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
5713                                 $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
5714                                 $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
5715                         } else {
5716                                 $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5717                         }
5718                 if ($HTTPS == '1' || $HTTPS == 'on') {
5719                         $SCHEME = 'https';
5720                 } else {
5721                         $SCHEME = 'http';
5722                 }
5723                         $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
5724                 }
5725                 if(false == $style) {
5726                         $style = "rpc";
5727                 }
5728                 if(false == $use) {
5729                         $use = "encoded";
5730                 }
5731                 if ($use == 'encoded' && $encodingStyle == '') {
5732                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
5733                 }
5734
5735                 $this->operations[$name] = array(
5736             'name' => $name,
5737             'in' => $in,
5738             'out' => $out,
5739             'namespace' => $namespace,
5740             'soapaction' => $soapaction,
5741             'style' => $style);
5742         if($this->wsdl){
5743                 $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle);
5744             }
5745                 return true;
5746         }
5747
5748         /**
5749         * Specify a fault to be returned to the client.
5750         * This also acts as a flag to the server that a fault has occured.
5751         *
5752         * @param        string $faultcode
5753         * @param        string $faultstring
5754         * @param        string $faultactor
5755         * @param        string $faultdetail
5756         * @access   public
5757         */
5758         function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){
5759                 if ($faultdetail == '' && $this->debug_flag) {
5760                         $faultdetail = $this->getDebug();
5761                 }
5762                 $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail);
5763                 $this->fault->soap_defencoding = $this->soap_defencoding;
5764         }
5765
5766     /**
5767     * Sets up wsdl object.
5768     * Acts as a flag to enable internal WSDL generation
5769     *
5770     * @param string $serviceName, name of the service
5771     * @param mixed $namespace optional 'tns' service namespace or false
5772     * @param mixed $endpoint optional URL of service endpoint or false
5773     * @param string $style optional (rpc|document) WSDL style (also specified by operation)
5774     * @param string $transport optional SOAP transport
5775     * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
5776     */
5777     function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
5778     {
5779         global $HTTP_SERVER_VARS;
5780
5781                 if (isset($_SERVER)) {
5782                         $SERVER_NAME = $_SERVER['SERVER_NAME'];
5783                         $SERVER_PORT = $_SERVER['SERVER_PORT'];
5784                         $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
5785                         $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
5786                 } elseif (isset($HTTP_SERVER_VARS)) {
5787                         $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
5788                         $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
5789                         $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
5790                         $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
5791                 } else {
5792                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
5793                 }
5794                 // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
5795                 $colon = strpos($SERVER_NAME,":");
5796                 if ($colon) {
5797                     $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
5798                 }
5799                 if ($SERVER_PORT == 80) {
5800                         $SERVER_PORT = '';
5801                 } else {
5802                         $SERVER_PORT = ':' . $SERVER_PORT;
5803                 }
5804         if(false == $namespace) {
5805             $namespace = "http://$SERVER_NAME/soap/$serviceName";
5806         }
5807
5808         if(false == $endpoint) {
5809                 if ($HTTPS == '1' || $HTTPS == 'on') {
5810                         $SCHEME = 'https';
5811                 } else {
5812                         $SCHEME = 'http';
5813                 }
5814             $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
5815         }
5816
5817         if(false == $schemaTargetNamespace) {
5818             $schemaTargetNamespace = $namespace;
5819         }
5820
5821                 $this->wsdl = new wsdl;
5822                 $this->wsdl->serviceName = $serviceName;
5823         $this->wsdl->endpoint = $endpoint;
5824                 $this->wsdl->namespaces['tns'] = $namespace;
5825                 $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
5826                 $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
5827                 if ($schemaTargetNamespace != $namespace) {
5828                         $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
5829                 }
5830         $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
5831         if ($style == 'document') {
5832                 $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
5833         }
5834         $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
5835         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
5836         $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
5837         $this->wsdl->bindings[$serviceName.'Binding'] = array(
5838                 'name'=>$serviceName.'Binding',
5839             'style'=>$style,
5840             'transport'=>$transport,
5841             'portType'=>$serviceName.'PortType');
5842         $this->wsdl->ports[$serviceName.'Port'] = array(
5843                 'binding'=>$serviceName.'Binding',
5844             'location'=>$endpoint,
5845             'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/');
5846     }
5847 }
5848
5849 /**
5850  * Backward compatibility
5851  */
5852 class soap_server extends nusoap_server {
5853 }
5854
5855 ?><?php
5856
5857 /*
5858
5859 Modification information for LGPL compliance
5860
5861 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
5862     bug 40066
5863
5864 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
5865     Merging with maint_6_0_1 (svn merge -r 58250:58342)
5866
5867 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
5868     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.
5869
5870 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
5871     fix SOAP calls with no parameters
5872
5873 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
5874
5875 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
5876
5877 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
5878
5879 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
5880
5881 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
5882
5883 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.
5884
5885 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.
5886
5887 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:
5888 - Changing all ereg function to either preg or simple string based ones
5889 - No more references to magic quotes.
5890 - Change all the session_unregister() functions to just unset() the correct session variable instead.
5891
5892 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
5893
5894 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
5895
5896 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
5897
5898 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
5899
5900 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
5901
5902 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
5903
5904 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
5905
5906 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
5907
5908 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.
5909 Touched:
5910 - data/SugarBean.php
5911 - include/domit/php_http_client_generic.php
5912 - include/domit/php_http_connector.php
5913 - include/domit/testing_domit.php
5914 - include/domit/xml_domit_getelementsbypath.php
5915 - include/domit/xml_domit_lite_parser.php
5916 - include/domit/xml_domit_nodemaps.php
5917 - include/domit/xml_domit_parser.php
5918 - include/domit/xml_domit_shared.php
5919 - include/generic/SugarWidgets/SugarWidgetField.php
5920 - include/generic/SugarWidgets/SugarWidgetReportField.php
5921 - include/ListView/ProcessView.php
5922 - include/nusoap/class.soapclient.php
5923 - include/nusoap/nusoap.php
5924 - include/nusoap/nusoapmime.php
5925 - include/Pear/HTML_Safe/Safe.php
5926 - include/Pear/XML_HTMLSax3/HTMLSax3.php
5927 - modules/Administration/RebuildWorkFlow.php
5928 - modules/Expressions/RelateSelector.php
5929 - modules/Reports/templates/templates_reports.php
5930 - modules/WorkFlow/Delete.php
5931 - modules/WorkFlow/Save.php
5932 - modules/WorkFlow/SaveSequence.php
5933 - modules/WorkFlow/WorkFlow.php
5934 - modules/WorkFlowActionShells/CreateStep1.php
5935 - modules/WorkFlowActionShells/CreateStep2.php
5936 - modules/WorkFlowActionShells/Save.php
5937 - modules/WorkFlowActionShells/WorkFlowActionShell.php
5938 - modules/WorkFlowAlerts/Save.php
5939 - modules/WorkFlowAlerts/WorkFlowAlert.php
5940 - modules/WorkFlowAlertShells/DetailView.php
5941 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
5942 - modules/WorkFlowTriggerShells/CreateStep1.php
5943 - modules/WorkFlowTriggerShells/CreateStepFilter.php
5944 - modules/WorkFlowTriggerShells/SaveFilter.php
5945 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
5946 - soap/SoapHelperFunctions.php
5947 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
5948 - test/simpletest/browser.php
5949 - test/simpletest/default_reporter.php
5950 - test/simpletest/detached.php
5951 - test/simpletest/eclipse.php
5952 - test/simpletest/expectation.php
5953 - test/simpletest/extensions/pear_test_case.php
5954 - test/simpletest/form.php
5955 - test/simpletest/http.php
5956 - test/simpletest/mock_objects.php
5957 - test/simpletest/page.php
5958 - test/simpletest/parser.php
5959 - test/simpletest/remote.php
5960 - test/simpletest/shell_tester.php
5961 - test/simpletest/simple_test.php
5962 - test/simpletest/simpletest.php
5963 - test/simpletest/test/acceptance_test.php
5964 - test/simpletest/test/adapter_test.php
5965 - test/simpletest/test/authentication_test.php
5966 - test/simpletest/test/browser_test.php
5967 - test/simpletest/test/collector_test.php
5968 - test/simpletest/test/compatibility_test.php
5969 - test/simpletest/test/detached_test.php
5970 - test/simpletest/test/eclipse_test.php
5971 - test/simpletest/test/encoding_test.php
5972 - test/simpletest/test/errors_test.php
5973 - test/simpletest/test/expectation_test.php
5974 - test/simpletest/test/form_test.php
5975 - test/simpletest/test/frames_test.php
5976 - test/simpletest/test/http_test.php
5977 - test/simpletest/test/live_test.php
5978 - test/simpletest/test/mock_objects_test.php
5979 - test/simpletest/test/page_test.php
5980 - test/simpletest/test/parse_error_test.php
5981 - test/simpletest/test/parser_test.php
5982 - test/simpletest/test/remote_test.php
5983 - test/simpletest/test/shell_test.php
5984 - test/simpletest/test/shell_tester_test.php
5985 - test/simpletest/test/simpletest_test.php
5986 - test/simpletest/test/site/page_request.php
5987 - test/simpletest/test/tag_test.php
5988 - test/simpletest/test/unit_tester_test.php
5989 - test/simpletest/test/user_agent_test.php
5990 - test/simpletest/test/visual_test.php
5991 - test/simpletest/test/xml_test.php
5992 - test/simpletest/test_case.php
5993 - test/simpletest/ui/array_reporter/test.php
5994 - test/simpletest/ui/recorder/test.php
5995 - test/simpletest/unit_tester.php
5996 - test/simpletest/url.php
5997 - test/simpletest/user_agent.php
5998 - test/simpletest/web_tester.php
5999 - test/spikephpcoverage/src/PEAR.php
6000 - test/spikephpcoverage/src/util/Utility.php
6001 - test/spikephpcoverage/src/XML/Parser.php
6002 - test/spikephpcoverage/src/XML/Parser/Simple.php
6003 - test/test_utilities/SugarTest_SimpleBrowser.php
6004
6005 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.
6006
6007 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
6008
6009 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
6010
6011 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
6012
6013 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
6014
6015 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
6016
6017 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
6018
6019 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
6020
6021 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
6022
6023 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
6024
6025 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
6026
6027 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
6028
6029 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.
6030
6031 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
6032
6033 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
6034
6035 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
6036
6037 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
6038
6039 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
6040
6041 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
6042
6043 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
6044
6045 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
6046
6047 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
6048
6049 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
6050
6051 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
6052
6053
6054 */
6055
6056
6057
6058
6059
6060 /**
6061 * parses a WSDL file, allows access to it's data, other utility methods.
6062 * also builds WSDL structures programmatically.
6063 *
6064 * @author   Dietrich Ayala <dietrich@ganx4.com>
6065 * @author   Scott Nichol <snichol@users.sourceforge.net>
6066
6067 * @access public
6068 */
6069 class wsdl extends nusoap_base {
6070         // URL or filename of the root of this WSDL
6071     var $wsdl;
6072     // define internal arrays of bindings, ports, operations, messages, etc.
6073     var $schemas = array();
6074     var $currentSchema;
6075     var $message = array();
6076     var $complexTypes = array();
6077     var $messages = array();
6078     var $currentMessage;
6079     var $currentOperation;
6080     var $portTypes = array();
6081     var $currentPortType;
6082     var $bindings = array();
6083     var $currentBinding;
6084     var $ports = array();
6085     var $currentPort;
6086     var $opData = array();
6087     var $status = '';
6088     var $documentation = false;
6089     var $endpoint = '';
6090     // array of wsdl docs to import
6091     var $import = array();
6092     // parser vars
6093     var $parser;
6094     var $position = 0;
6095     var $depth = 0;
6096     var $depth_array = array();
6097         // for getting wsdl
6098         var $proxyhost = '';
6099     var $proxyport = '';
6100         var $proxyusername = '';
6101         var $proxypassword = '';
6102         var $timeout = 0;
6103         var $response_timeout = 30;
6104         var $curl_options = array();    // User-specified cURL options
6105         var $use_curl = false;                  // whether to always try to use cURL
6106         // for HTTP authentication
6107         var $username = '';                             // Username for HTTP authentication
6108         var $password = '';                             // Password for HTTP authentication
6109         var $authtype = '';                             // Type of HTTP authentication
6110         var $certRequest = array();             // Certificate for HTTP SSL authentication
6111
6112     /**
6113      * constructor
6114      *
6115      * @param string $wsdl WSDL document URL
6116          * @param string $proxyhost
6117          * @param string $proxyport
6118          * @param string $proxyusername
6119          * @param string $proxypassword
6120          * @param integer $timeout set the connection timeout
6121          * @param integer $response_timeout set the response timeout
6122          * @param array $curl_options user-specified cURL options
6123          * @param boolean $use_curl try to use cURL
6124      * @access public
6125      */
6126     function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
6127                 parent::nusoap_base();
6128                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
6129         $this->proxyhost = $proxyhost;
6130         $this->proxyport = $proxyport;
6131                 $this->proxyusername = $proxyusername;
6132                 $this->proxypassword = $proxypassword;
6133                 $this->timeout = $timeout;
6134                 $this->response_timeout = $response_timeout;
6135                 if (is_array($curl_options))
6136                         $this->curl_options = $curl_options;
6137                 $this->use_curl = $use_curl;
6138                 $this->fetchWSDL($wsdl);
6139     }
6140
6141         /**
6142          * fetches the WSDL document and parses it
6143          *
6144          * @access public
6145          */
6146         function fetchWSDL($wsdl) {
6147                 $this->debug("parse and process WSDL path=$wsdl");
6148                 $this->wsdl = $wsdl;
6149         // parse wsdl file
6150         if ($this->wsdl != "") {
6151             $this->parseWSDL($this->wsdl);
6152         }
6153         // imports
6154         // TODO: handle imports more properly, grabbing them in-line and nesting them
6155         $imported_urls = array();
6156         $imported = 1;
6157         while ($imported > 0) {
6158                 $imported = 0;
6159                 // Schema imports
6160                 foreach ($this->schemas as $ns => $list) {
6161                         foreach ($list as $xs) {
6162                                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
6163                             foreach ($xs->imports as $ns2 => $list2) {
6164                                 for ($ii = 0; $ii < count($list2); $ii++) {
6165                                         if (! $list2[$ii]['loaded']) {
6166                                                 $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
6167                                                 $url = $list2[$ii]['location'];
6168                                                                 if ($url != '') {
6169                                                                         $urlparts = parse_url($url);
6170                                                                         if (!isset($urlparts['host'])) {
6171                                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
6172                                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
6173                                                                         }
6174                                                                         if (! in_array($url, $imported_urls)) {
6175                                                                 $this->parseWSDL($url);
6176                                                                 $imported++;
6177                                                                 $imported_urls[] = $url;
6178                                                         }
6179                                                                 } else {
6180                                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");
6181                                                                 }
6182                                                         }
6183                                                 }
6184                             }
6185                         }
6186                 }
6187                 // WSDL imports
6188                         $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
6189             foreach ($this->import as $ns => $list) {
6190                 for ($ii = 0; $ii < count($list); $ii++) {
6191                         if (! $list[$ii]['loaded']) {
6192                                 $this->import[$ns][$ii]['loaded'] = true;
6193                                 $url = $list[$ii]['location'];
6194                                                 if ($url != '') {
6195                                                         $urlparts = parse_url($url);
6196                                                         if (!isset($urlparts['host'])) {
6197                                                                 $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
6198                                                                                 substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
6199                                                         }
6200                                                         if (! in_array($url, $imported_urls)) {
6201                                                 $this->parseWSDL($url);
6202                                                 $imported++;
6203                                                 $imported_urls[] = $url;
6204                                         }
6205                                                 } else {
6206                                                         $this->debug("Unexpected scenario: empty URL for unloaded import");
6207                                                 }
6208                                         }
6209                                 }
6210             }
6211                 }
6212         // add new data to operation data
6213         foreach($this->bindings as $binding => $bindingData) {
6214             if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
6215                 foreach($bindingData['operations'] as $operation => $data) {
6216                     $this->debug('post-parse data gathering for ' . $operation);
6217                     $this->bindings[$binding]['operations'][$operation]['input'] =
6218                                                 isset($this->bindings[$binding]['operations'][$operation]['input']) ?
6219                                                 array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
6220                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['input'];
6221                     $this->bindings[$binding]['operations'][$operation]['output'] =
6222                                                 isset($this->bindings[$binding]['operations'][$operation]['output']) ?
6223                                                 array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
6224                                                 $this->portTypes[ $bindingData['portType'] ][$operation]['output'];
6225                     if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
6226                                                 $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
6227                                         }
6228                                         if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
6229                                 $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
6230                     }
6231                     // Set operation style if necessary, but do not override one already provided
6232                                         if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
6233                         $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
6234                     }
6235                     $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
6236                     $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
6237                     $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
6238                 }
6239             }
6240         }
6241         }
6242
6243     /**
6244      * parses the wsdl document
6245      *
6246      * @param string $wsdl path or URL
6247      * @access private
6248      */
6249     function parseWSDL($wsdl = '') {
6250                 $this->debug("parse WSDL at path=$wsdl");
6251
6252         if ($wsdl == '') {
6253             $this->debug('no wsdl passed to parseWSDL()!!');
6254             $this->setError('no wsdl passed to parseWSDL()!!');
6255             return false;
6256         }
6257
6258         // parse $wsdl for url format
6259         $wsdl_props = parse_url($wsdl);
6260
6261         if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
6262             $this->debug('getting WSDL http(s) URL ' . $wsdl);
6263                 // get wsdl
6264                 $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
6265                         $tr->request_method = 'GET';
6266                         $tr->useSOAPAction = false;
6267                         if($this->proxyhost && $this->proxyport){
6268                                 $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
6269                         }
6270                         if ($this->authtype != '') {
6271                                 $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
6272                         }
6273                         $tr->setEncoding('gzip, deflate');
6274                         $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
6275                         //$this->debug("WSDL request\n" . $tr->outgoing_payload);
6276                         //$this->debug("WSDL response\n" . $tr->incoming_payload);
6277                         $this->appendDebug($tr->getDebug());
6278                         // catch errors
6279                         if($err = $tr->getError() ){
6280                                 $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err;
6281                                 $this->debug($errstr);
6282                     $this->setError($errstr);
6283                                 unset($tr);
6284                     return false;
6285                         }
6286                         unset($tr);
6287                         $this->debug("got WSDL URL");
6288         } else {
6289             // $wsdl is not http(s), so treat it as a file URL or plain file path
6290                 if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
6291                         $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
6292                 } else {
6293                         $path = $wsdl;
6294                 }
6295             $this->debug('getting WSDL file ' . $path);
6296             if ($fp = @fopen($path, 'r')) {
6297                 $wsdl_string = '';
6298                 while ($data = fread($fp, 32768)) {
6299                     $wsdl_string .= $data;
6300                 }
6301                 fclose($fp);
6302             } else {
6303                 $errstr = "Bad path to WSDL file $path";
6304                 $this->debug($errstr);
6305                 $this->setError($errstr);
6306                 return false;
6307             }
6308         }
6309         $this->debug('Parse WSDL');
6310         // end new code added
6311         // Create an XML parser.
6312         $this->parser = xml_parser_create();
6313         // Set the options for parsing the XML data.
6314         // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
6315         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
6316         // Set the object for the parser.
6317         xml_set_object($this->parser, $this);
6318         // Set the element handlers for the parser.
6319         xml_set_element_handler($this->parser, 'start_element', 'end_element');
6320         xml_set_character_data_handler($this->parser, 'character_data');
6321         // Parse the XML file.
6322         if (!xml_parse($this->parser, $wsdl_string, true)) {
6323             // Display an error message.
6324             $errstr = sprintf(
6325                                 'XML error parsing WSDL from %s on line %d: %s',
6326                                 $wsdl,
6327                 xml_get_current_line_number($this->parser),
6328                 xml_error_string(xml_get_error_code($this->parser))
6329                 );
6330             $this->debug($errstr);
6331                         $this->debug("XML payload:\n" . $wsdl_string);
6332             $this->setError($errstr);
6333             return false;
6334         }
6335                 // free the parser
6336         xml_parser_free($this->parser);
6337         $this->debug('Parsing WSDL done');
6338                 // catch wsdl parse errors
6339                 if($this->getError()){
6340                         return false;
6341                 }
6342         return true;
6343     }
6344
6345     /**
6346      * start-element handler
6347      *
6348      * @param string $parser XML parser object
6349      * @param string $name element name
6350      * @param string $attrs associative array of attributes
6351      * @access private
6352      */
6353     function start_element($parser, $name, $attrs)
6354     {
6355         if ($this->status == 'schema') {
6356             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
6357             $this->appendDebug($this->currentSchema->getDebug());
6358             $this->currentSchema->clearDebug();
6359         } elseif (preg_match('/schema$/', $name)) {
6360                 $this->debug('Parsing WSDL schema');
6361             // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
6362             $this->status = 'schema';
6363             $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
6364             $this->currentSchema->schemaStartElement($parser, $name, $attrs);
6365             $this->appendDebug($this->currentSchema->getDebug());
6366             $this->currentSchema->clearDebug();
6367         } else {
6368             // position in the total number of elements, starting from 0
6369             $pos = $this->position++;
6370             $depth = $this->depth++;
6371             // set self as current value for this depth
6372             $this->depth_array[$depth] = $pos;
6373             $this->message[$pos] = array('cdata' => '');
6374             // process attributes
6375             if (count($attrs) > 0) {
6376                                 // register namespace declarations
6377                 foreach($attrs as $k => $v) {
6378                     if (preg_match('/^xmlns/',$k)) {
6379                         if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
6380                             $this->namespaces[$ns_prefix] = $v;
6381                         } else {
6382                             $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
6383                         }
6384                         if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
6385                             $this->XMLSchemaVersion = $v;
6386                             $this->namespaces['xsi'] = $v . '-instance';
6387                         }
6388                     }
6389                 }
6390                 // expand each attribute prefix to its namespace
6391                 foreach($attrs as $k => $v) {
6392                     $k = strpos($k, ':') ? $this->expandQname($k) : $k;
6393                     if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
6394                         $v = strpos($v, ':') ? $this->expandQname($v) : $v;
6395                     }
6396                     $eAttrs[$k] = $v;
6397                 }
6398                 $attrs = $eAttrs;
6399             } else {
6400                 $attrs = array();
6401             }
6402             // get element prefix, namespace and name
6403             if (preg_match('/:/', $name)) {
6404                 // get ns prefix
6405                 $prefix = substr($name, 0, strpos($name, ':'));
6406                 // get ns
6407                 $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
6408                 // get unqualified name
6409                 $name = substr(strstr($name, ':'), 1);
6410             }
6411                         // process attributes, expanding any prefixes to namespaces
6412             // find status, register data
6413             switch ($this->status) {
6414                 case 'message':
6415                     if ($name == 'part') {
6416                                     if (isset($attrs['type'])) {
6417                                     $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
6418                                     $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
6419                                 }
6420                                     if (isset($attrs['element'])) {
6421                                     $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
6422                                         $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
6423                                     }
6424                                 }
6425                                 break;
6426                             case 'portType':
6427                                 switch ($name) {
6428                                     case 'operation':
6429                                         $this->currentPortOperation = $attrs['name'];
6430                                         $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
6431                                         if (isset($attrs['parameterOrder'])) {
6432                                                 $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
6433                                                 }
6434                                                 break;
6435                                             case 'documentation':
6436                                                 $this->documentation = true;
6437                                                 break;
6438                                             // merge input/output data
6439                                             default:
6440                                                 $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
6441                                                 $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
6442                                                 break;
6443                                         }
6444                                 break;
6445                                 case 'binding':
6446                                     switch ($name) {
6447                                         case 'binding':
6448                                             // get ns prefix
6449                                             if (isset($attrs['style'])) {
6450                                             $this->bindings[$this->currentBinding]['prefix'] = $prefix;
6451                                                 }
6452                                                 $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
6453                                                 break;
6454                                                 case 'header':
6455                                                     $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
6456                                                     break;
6457                                                 case 'operation':
6458                                                     if (isset($attrs['soapAction'])) {
6459                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
6460                                                     }
6461                                                     if (isset($attrs['style'])) {
6462                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
6463                                                     }
6464                                                     if (isset($attrs['name'])) {
6465                                                         $this->currentOperation = $attrs['name'];
6466                                                         $this->debug("current binding operation: $this->currentOperation");
6467                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
6468                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
6469                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
6470                                                     }
6471                                                     break;
6472                                                 case 'input':
6473                                                     $this->opStatus = 'input';
6474                                                     break;
6475                                                 case 'output':
6476                                                     $this->opStatus = 'output';
6477                                                     break;
6478                                                 case 'body':
6479                                                     if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
6480                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
6481                                                     } else {
6482                                                         $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
6483                                                     }
6484                                                     break;
6485                                         }
6486                                         break;
6487                                 case 'service':
6488                                         switch ($name) {
6489                                             case 'port':
6490                                                 $this->currentPort = $attrs['name'];
6491                                                 $this->debug('current port: ' . $this->currentPort);
6492                                                 $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
6493
6494                                                 break;
6495                                             case 'address':
6496                                                 $this->ports[$this->currentPort]['location'] = $attrs['location'];
6497                                                 $this->ports[$this->currentPort]['bindingType'] = $namespace;
6498                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
6499                                                 $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
6500                                                 break;
6501                                         }
6502                                         break;
6503                         }
6504                 // set status
6505                 switch ($name) {
6506                         case 'import':
6507                             if (isset($attrs['location'])) {
6508                     $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
6509                     $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
6510                                 } else {
6511                     $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
6512                                         if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
6513                                                 $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
6514                                         }
6515                     $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
6516                                 }
6517                                 break;
6518                         //wait for schema
6519                         //case 'types':
6520                         //      $this->status = 'schema';
6521                         //      break;
6522                         case 'message':
6523                                 $this->status = 'message';
6524                                 $this->messages[$attrs['name']] = array();
6525                                 $this->currentMessage = $attrs['name'];
6526                                 break;
6527                         case 'portType':
6528                                 $this->status = 'portType';
6529                                 $this->portTypes[$attrs['name']] = array();
6530                                 $this->currentPortType = $attrs['name'];
6531                                 break;
6532                         case "binding":
6533                                 if (isset($attrs['name'])) {
6534                                 // get binding name
6535                                         if (strpos($attrs['name'], ':')) {
6536                                         $this->currentBinding = $this->getLocalPart($attrs['name']);
6537                                         } else {
6538                                         $this->currentBinding = $attrs['name'];
6539                                         }
6540                                         $this->status = 'binding';
6541                                         $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
6542                                         $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
6543                                 }
6544                                 break;
6545                         case 'service':
6546                                 $this->serviceName = $attrs['name'];
6547                                 $this->status = 'service';
6548                                 $this->debug('current service: ' . $this->serviceName);
6549                                 break;
6550                         case 'definitions':
6551                                 foreach ($attrs as $name => $value) {
6552                                         $this->wsdl_info[$name] = $value;
6553                                 }
6554                                 break;
6555                         }
6556                 }
6557         }
6558
6559         /**
6560         * end-element handler
6561         *
6562         * @param string $parser XML parser object
6563         * @param string $name element name
6564         * @access private
6565         */
6566         function end_element($parser, $name){
6567                 // unset schema status
6568                 if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
6569                         $this->status = "";
6570             $this->appendDebug($this->currentSchema->getDebug());
6571             $this->currentSchema->clearDebug();
6572                         $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
6573                 $this->debug('Parsing WSDL schema done');
6574                 }
6575                 if ($this->status == 'schema') {
6576                         $this->currentSchema->schemaEndElement($parser, $name);
6577                 } else {
6578                         // bring depth down a notch
6579                         $this->depth--;
6580                 }
6581                 // end documentation
6582                 if ($this->documentation) {
6583                         //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
6584                         //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
6585                         $this->documentation = false;
6586                 }
6587         }
6588
6589         /**
6590          * element content handler
6591          *
6592          * @param string $parser XML parser object
6593          * @param string $data element content
6594          * @access private
6595          */
6596         function character_data($parser, $data)
6597         {
6598                 $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
6599                 if (isset($this->message[$pos]['cdata'])) {
6600                         $this->message[$pos]['cdata'] .= $data;
6601                 }
6602                 if ($this->documentation) {
6603                         $this->documentation .= $data;
6604                 }
6605         }
6606
6607         /**
6608         * if authenticating, set user credentials here
6609         *
6610         * @param    string $username
6611         * @param    string $password
6612         * @param        string $authtype (basic|digest|certificate|ntlm)
6613         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
6614         * @access   public
6615         */
6616         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
6617                 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
6618                 $this->appendDebug($this->varDump($certRequest));
6619                 $this->username = $username;
6620                 $this->password = $password;
6621                 $this->authtype = $authtype;
6622                 $this->certRequest = $certRequest;
6623         }
6624
6625         function getBindingData($binding)
6626         {
6627                 if (is_array($this->bindings[$binding])) {
6628                         return $this->bindings[$binding];
6629                 }
6630         }
6631
6632         /**
6633          * returns an assoc array of operation names => operation data
6634          *
6635          * @param string $portName WSDL port name
6636          * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
6637          * @return array
6638          * @access public
6639          */
6640         function getOperations($portName = '', $bindingType = 'soap') {
6641                 $ops = array();
6642                 if ($bindingType == 'soap') {
6643                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
6644                 } elseif ($bindingType == 'soap12') {
6645                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
6646                 } else {
6647                         $this->debug("getOperations bindingType $bindingType may not be supported");
6648                 }
6649                 $this->debug("getOperations for port '$portName' bindingType $bindingType");
6650                 // loop thru ports
6651                 foreach($this->ports as $port => $portData) {
6652                         $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
6653                         if ($portName == '' || $port == $portName) {
6654                                 // binding type of port matches parameter
6655                                 if ($portData['bindingType'] == $bindingType) {
6656                                         $this->debug("getOperations found port $port bindingType $bindingType");
6657                                         //$this->debug("port data: " . $this->varDump($portData));
6658                                         //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
6659                                         // merge bindings
6660                                         if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
6661                                                 $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
6662                                         }
6663                                 }
6664                         }
6665                 }
6666                 if (count($ops) == 0) {
6667                         $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
6668                 }
6669                 return $ops;
6670         }
6671
6672         /**
6673          * returns an associative array of data necessary for calling an operation
6674          *
6675          * @param string $operation name of operation
6676          * @param string $bindingType type of binding eg: soap, soap12
6677          * @return array
6678          * @access public
6679          */
6680         function getOperationData($operation, $bindingType = 'soap')
6681         {
6682                 if ($bindingType == 'soap') {
6683                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
6684                 } elseif ($bindingType == 'soap12') {
6685                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
6686                 }
6687                 // loop thru ports
6688                 foreach($this->ports as $port => $portData) {
6689                         // binding type of port matches parameter
6690                         if ($portData['bindingType'] == $bindingType) {
6691                                 // get binding
6692                                 //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
6693                                 foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
6694                                         // note that we could/should also check the namespace here
6695                                         if ($operation == $bOperation) {
6696                                                 $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
6697                                             return $opData;
6698                                         }
6699                                 }
6700                         }
6701                 }
6702         }
6703
6704         /**
6705          * returns an associative array of data necessary for calling an operation
6706          *
6707          * @param string $soapAction soapAction for operation
6708          * @param string $bindingType type of binding eg: soap, soap12
6709          * @return array
6710          * @access public
6711          */
6712         function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
6713                 if ($bindingType == 'soap') {
6714                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
6715                 } elseif ($bindingType == 'soap12') {
6716                         $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
6717                 }
6718                 // loop thru ports
6719                 foreach($this->ports as $port => $portData) {
6720                         // binding type of port matches parameter
6721                         if ($portData['bindingType'] == $bindingType) {
6722                                 // loop through operations for the binding
6723                                 foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
6724                                         if ($opData['soapAction'] == $soapAction) {
6725                                             return $opData;
6726                                         }
6727                                 }
6728                         }
6729                 }
6730         }
6731
6732         /**
6733     * returns an array of information about a given type
6734     * returns false if no type exists by the given name
6735     *
6736         *        typeDef = array(
6737         *        'elements' => array(), // refs to elements array
6738         *       'restrictionBase' => '',
6739         *       'phpType' => '',
6740         *       'order' => '(sequence|all)',
6741         *       'attrs' => array() // refs to attributes array
6742         *       )
6743     *
6744     * @param string $type the type
6745     * @param string $ns namespace (not prefix) of the type
6746     * @return mixed
6747     * @access public
6748     * @see nusoap_xmlschema
6749     */
6750         function getTypeDef($type, $ns) {
6751                 $this->debug("in getTypeDef: type=$type, ns=$ns");
6752                 if ((! $ns) && isset($this->namespaces['tns'])) {
6753                         $ns = $this->namespaces['tns'];
6754                         $this->debug("in getTypeDef: type namespace forced to $ns");
6755                 }
6756                 if (!isset($this->schemas[$ns])) {
6757                         foreach ($this->schemas as $ns0 => $schema0) {
6758                                 if (strcasecmp($ns, $ns0) == 0) {
6759                                         $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
6760                                         $ns = $ns0;
6761                                         break;
6762                                 }
6763                         }
6764                 }
6765                 if (isset($this->schemas[$ns])) {
6766                         $this->debug("in getTypeDef: have schema for namespace $ns");
6767                         for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
6768                                 $xs = &$this->schemas[$ns][$i];
6769                                 $t = $xs->getTypeDef($type);
6770                                 $this->appendDebug($xs->getDebug());
6771                                 $xs->clearDebug();
6772                                 if ($t) {
6773                                         $this->debug("in getTypeDef: found type $type");
6774                                         if (!isset($t['phpType'])) {
6775                                                 // get info for type to tack onto the element
6776                                                 $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
6777                                                 $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
6778                                                 $etype = $this->getTypeDef($uqType, $ns);
6779                                                 if ($etype) {
6780                                                         $this->debug("found type for [element] $type:");
6781                                                         $this->debug($this->varDump($etype));
6782                                                         if (isset($etype['phpType'])) {
6783                                                                 $t['phpType'] = $etype['phpType'];
6784                                                         }
6785                                                         if (isset($etype['elements'])) {
6786                                                                 $t['elements'] = $etype['elements'];
6787                                                         }
6788                                                         if (isset($etype['attrs'])) {
6789                                                                 $t['attrs'] = $etype['attrs'];
6790                                                         }
6791                                                 } else {
6792                                                         $this->debug("did not find type for [element] $type");
6793                                                 }
6794                                         }
6795                                         return $t;
6796                                 }
6797                         }
6798                         $this->debug("in getTypeDef: did not find type $type");
6799                 } else {
6800                         $this->debug("in getTypeDef: do not have schema for namespace $ns");
6801                 }
6802                 return false;
6803         }
6804
6805     /**
6806     * prints html description of services
6807     *
6808     * @access private
6809     */
6810     function webDescription(){
6811         global $HTTP_SERVER_VARS;
6812
6813                 if (isset($_SERVER)) {
6814                         $PHP_SELF = $_SERVER['PHP_SELF'];
6815                 } elseif (isset($HTTP_SERVER_VARS)) {
6816                         $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
6817                 } else {
6818                         $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
6819                 }
6820
6821                 $b = '
6822                 <html><head><title>NuSOAP: '.$this->serviceName.'</title>
6823                 <style type="text/css">
6824                     body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
6825                     p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
6826                     pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
6827                     ul      { margin-top: 10px; margin-left: 20px; }
6828                     li      { list-style-type: none; margin-top: 10px; color: #000000; }
6829                     .content{
6830                         margin-left: 0px; padding-bottom: 2em; }
6831                     .nav {
6832                         padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
6833                         margin-top: 10px; margin-left: 0px; color: #000000;
6834                         background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
6835                     .title {
6836                         font-family: arial; font-size: 26px; color: #ffffff;
6837                         background-color: #999999; width: 100%;
6838                         margin-left: 0px; margin-right: 0px;
6839                         padding-top: 10px; padding-bottom: 10px;}
6840                     .hidden {
6841                         position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
6842                         font-family: arial; overflow: hidden; width: 600;
6843                         padding: 20px; font-size: 10px; background-color: #999999;
6844                         layer-background-color:#FFFFFF; }
6845                     a,a:active  { color: charcoal; font-weight: bold; }
6846                     a:visited   { color: #666666; font-weight: bold; }
6847                     a:hover     { color: cc3300; font-weight: bold; }
6848                 </style>
6849                 <script language="JavaScript" type="text/javascript">
6850                 <!--
6851                 // POP-UP CAPTIONS...
6852                 function lib_bwcheck(){ //Browsercheck (needed)
6853                     this.ver=navigator.appVersion
6854                     this.agent=navigator.userAgent
6855                     this.dom=document.getElementById?1:0
6856                     this.opera5=this.agent.indexOf("Opera 5")>-1
6857                     this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
6858                     this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
6859                     this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
6860                     this.ie=this.ie4||this.ie5||this.ie6
6861                     this.mac=this.agent.indexOf("Mac")>-1
6862                     this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
6863                     this.ns4=(document.layers && !this.dom)?1:0;
6864                     this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
6865                     return this
6866                 }
6867                 var bw = new lib_bwcheck()
6868                 //Makes crossbrowser object.
6869                 function makeObj(obj){
6870                     this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
6871                     if(!this.evnt) return false
6872                     this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
6873                     this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
6874                     this.writeIt=b_writeIt;
6875                     return this
6876                 }
6877                 // A unit of measure that will be added when setting the position of a layer.
6878                 //var px = bw.ns4||window.opera?"":"px";
6879                 function b_writeIt(text){
6880                     if (bw.ns4){this.wref.write(text);this.wref.close()}
6881                     else this.wref.innerHTML = text
6882                 }
6883                 //Shows the messages
6884                 var oDesc;
6885                 function popup(divid){
6886                     if(oDesc = new makeObj(divid)){
6887                         oDesc.css.visibility = "visible"
6888                     }
6889                 }
6890                 function popout(){ // Hides message
6891                     if(oDesc) oDesc.css.visibility = "hidden"
6892                 }
6893                 //-->
6894                 </script>
6895                 </head>
6896                 <body>
6897                 <div class=content>
6898                         <br><br>
6899                         <div class=title>'.$this->serviceName.'</div>
6900                         <div class=nav>
6901                                 <p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
6902                                 Click on an operation name to view it&apos;s details.</p>
6903                                 <ul>';
6904                                 foreach($this->getOperations() as $op => $data){
6905                                     $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
6906                                     // create hidden div
6907                                     $b .= "<div id='$op' class='hidden'>
6908                                     <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
6909                                     foreach($data as $donnie => $marie){ // loop through opdata
6910                                                 if($donnie == 'input' || $donnie == 'output'){ // show input/output data
6911                                                     $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
6912                                                     foreach($marie as $captain => $tenille){ // loop through data
6913                                                                 if($captain == 'parts'){ // loop thru parts
6914                                                                     $b .= "&nbsp;&nbsp;$captain:<br>";
6915                                                         //if(is_array($tenille)){
6916                                                                         foreach($tenille as $joanie => $chachi){
6917                                                                                         $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
6918                                                                         }
6919                                                                 //}
6920                                                                 } else {
6921                                                                     $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
6922                                                                 }
6923                                                     }
6924                                                 } else {
6925                                                     $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
6926                                                 }
6927                                     }
6928                                         $b .= '</div>';
6929                                 }
6930                                 $b .= '
6931                                 <ul>
6932                         </div>
6933                 </div></body></html>';
6934                 return $b;
6935     }
6936
6937         /**
6938         * serialize the parsed wsdl
6939         *
6940         * @param mixed $debug whether to put debug=1 in endpoint URL
6941         * @return string serialization of WSDL
6942         * @access public
6943         */
6944         function serialize($debug = 0)
6945         {
6946                 $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
6947                 $xml .= "\n<definitions";
6948                 foreach($this->namespaces as $k => $v) {
6949                         $xml .= " xmlns:$k=\"$v\"";
6950                 }
6951                 // 10.9.02 - add poulter fix for wsdl and tns declarations
6952                 if (isset($this->namespaces['wsdl'])) {
6953                         $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
6954                 }
6955                 if (isset($this->namespaces['tns'])) {
6956                         $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
6957                 }
6958                 $xml .= '>';
6959                 // imports
6960                 if (sizeof($this->import) > 0) {
6961                         foreach($this->import as $ns => $list) {
6962                                 foreach ($list as $ii) {
6963                                         if ($ii['location'] != '') {
6964                                                 $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
6965                                         } else {
6966                                                 $xml .= '<import namespace="' . $ns . '" />';
6967                                         }
6968                                 }
6969                         }
6970                 }
6971                 // types
6972                 if (count($this->schemas)>=1) {
6973                         $xml .= "\n<types>\n";
6974                         foreach ($this->schemas as $ns => $list) {
6975                                 foreach ($list as $xs) {
6976                                         $xml .= $xs->serializeSchema();
6977                                 }
6978                         }
6979                         $xml .= '</types>';
6980                 }
6981                 // messages
6982                 if (count($this->messages) >= 1) {
6983                         foreach($this->messages as $msgName => $msgParts) {
6984                                 $xml .= "\n<message name=\"" . $msgName . '">';
6985                                 if(is_array($msgParts)){
6986                                         foreach($msgParts as $partName => $partType) {
6987                                                 // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
6988                                                 if (strpos($partType, ':')) {
6989                                                     $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
6990                                                 } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
6991                                                     // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
6992                                                     $typePrefix = 'xsd';
6993                                                 } else {
6994                                                     foreach($this->typemap as $ns => $types) {
6995                                                         if (isset($types[$partType])) {
6996                                                             $typePrefix = $this->getPrefixFromNamespace($ns);
6997                                                         }
6998                                                     }
6999                                                     if (!isset($typePrefix)) {
7000                                                         die("$partType has no namespace!");
7001                                                     }
7002                                                 }
7003                                                 $ns = $this->getNamespaceFromPrefix($typePrefix);
7004                                                 $localPart = $this->getLocalPart($partType);
7005                                                 $typeDef = $this->getTypeDef($localPart, $ns);
7006                                                 if ($typeDef['typeClass'] == 'element') {
7007                                                         $elementortype = 'element';
7008                                                         if (substr($localPart, -1) == '^') {
7009                                                                 $localPart = substr($localPart, 0, -1);
7010                                                         }
7011                                                 } else {
7012                                                         $elementortype = 'type';
7013                                                 }
7014                                                 $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
7015                                         }
7016                                 }
7017                                 $xml .= '</message>';
7018                         }
7019                 }
7020                 // bindings & porttypes
7021                 if (count($this->bindings) >= 1) {
7022                         $binding_xml = '';
7023                         $portType_xml = '';
7024                         foreach($this->bindings as $bindingName => $attrs) {
7025                                 $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
7026                                 $binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
7027                                 $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
7028                                 foreach($attrs['operations'] as $opName => $opParts) {
7029                                         $binding_xml .= "\n" . '  <operation name="' . $opName . '">';
7030                                         $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
7031                                         if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
7032                                                 $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
7033                                         } else {
7034                                                 $enc_style = '';
7035                                         }
7036                                         $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
7037                                         if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
7038                                                 $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
7039                                         } else {
7040                                                 $enc_style = '';
7041                                         }
7042                                         $binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
7043                                         $binding_xml .= "\n" . '  </operation>';
7044                                         $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
7045                                         if (isset($opParts['parameterOrder'])) {
7046                                             $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
7047                                         }
7048                                         $portType_xml .= '>';
7049                                         if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
7050                                                 $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
7051                                         }
7052                                         $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';
7053                                         $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';
7054                                         $portType_xml .= "\n" . '  </operation>';
7055                                 }
7056                                 $portType_xml .= "\n" . '</portType>';
7057                                 $binding_xml .= "\n" . '</binding>';
7058                         }
7059                         $xml .= $portType_xml . $binding_xml;
7060                 }
7061                 // services
7062                 $xml .= "\n<service name=\"" . $this->serviceName . '">';
7063                 if (count($this->ports) >= 1) {
7064                         foreach($this->ports as $pName => $attrs) {
7065                                 $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
7066                                 $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
7067                                 $xml .= "\n" . '  </port>';
7068                         }
7069                 }
7070                 $xml .= "\n" . '</service>';
7071                 return $xml . "\n</definitions>";
7072         }
7073
7074         /**
7075          * determine whether a set of parameters are unwrapped
7076          * when they are expect to be wrapped, Microsoft-style.
7077          *
7078          * @param string $type the type (element name) of the wrapper
7079          * @param array $parameters the parameter values for the SOAP call
7080          * @return boolean whether they parameters are unwrapped (and should be wrapped)
7081          * @access private
7082          */
7083         function parametersMatchWrapped($type, &$parameters) {
7084                 $this->debug("in parametersMatchWrapped type=$type, parameters=");
7085                 $this->appendDebug($this->varDump($parameters));
7086
7087                 // split type into namespace:unqualified-type
7088                 if (strpos($type, ':')) {
7089                         $uqType = substr($type, strrpos($type, ':') + 1);
7090                         $ns = substr($type, 0, strrpos($type, ':'));
7091                         $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
7092                         if ($this->getNamespaceFromPrefix($ns)) {
7093                                 $ns = $this->getNamespaceFromPrefix($ns);
7094                                 $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
7095                         }
7096                 } else {
7097                         // TODO: should the type be compared to types in XSD, and the namespace
7098                         // set to XSD if the type matches?
7099                         $this->debug("in parametersMatchWrapped: No namespace for type $type");
7100                         $ns = '';
7101                         $uqType = $type;
7102                 }
7103
7104                 // get the type information
7105                 if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
7106                         $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
7107                         return false;
7108                 }
7109                 $this->debug("in parametersMatchWrapped: found typeDef=");
7110                 $this->appendDebug($this->varDump($typeDef));
7111                 if (substr($uqType, -1) == '^') {
7112                         $uqType = substr($uqType, 0, -1);
7113                 }
7114                 $phpType = $typeDef['phpType'];
7115                 $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
7116                 $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
7117
7118                 // we expect a complexType or element of complexType
7119                 if ($phpType != 'struct') {
7120                         $this->debug("in parametersMatchWrapped: not a struct");
7121                         return false;
7122                 }
7123
7124                 // see whether the parameter names match the elements
7125                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
7126                         $elements = 0;
7127                         $matches = 0;
7128                         foreach ($typeDef['elements'] as $name => $attrs) {
7129                                 if (isset($parameters[$name])) {
7130                                         $this->debug("in parametersMatchWrapped: have parameter named $name");
7131                                         $matches++;
7132                                 } else {
7133                                         $this->debug("in parametersMatchWrapped: do not have parameter named $name");
7134                                 }
7135                                 $elements++;
7136                         }
7137
7138                         $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
7139                         if ($matches == 0) {
7140                                 return false;
7141                         }
7142                         return true;
7143                 }
7144
7145                 // since there are no elements for the type, if the user passed no
7146                 // parameters, the parameters match wrapped.
7147                 $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
7148                 return count($parameters) == 0;
7149         }
7150
7151         /**
7152          * serialize PHP values according to a WSDL message definition
7153          * contrary to the method name, this is not limited to RPC
7154          *
7155          * TODO
7156          * - multi-ref serialization
7157          * - validate PHP values against type definitions, return errors if invalid
7158          *
7159          * @param string $operation operation name
7160          * @param string $direction (input|output)
7161          * @param mixed $parameters parameter value(s)
7162          * @param string $bindingType (soap|soap12)
7163          * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
7164          * @access public
7165          */
7166         function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
7167                 $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
7168                 $this->appendDebug('parameters=' . $this->varDump($parameters));
7169
7170                 if ($direction != 'input' && $direction != 'output') {
7171                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
7172                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
7173                         return false;
7174                 }
7175                 if (!$opData = $this->getOperationData($operation, $bindingType)) {
7176                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
7177                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
7178                         return false;
7179                 }
7180                 $this->debug('in serializeRPCParameters: opData:');
7181                 $this->appendDebug($this->varDump($opData));
7182
7183                 // Get encoding style for output and set to current
7184                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7185                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
7186                         $encodingStyle = $opData['output']['encodingStyle'];
7187                         $enc_style = $encodingStyle;
7188                 }
7189
7190                 // set input params
7191                 $xml = '';
7192                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
7193                         $parts = &$opData[$direction]['parts'];
7194                         $part_count = sizeof($parts);
7195                         $style = $opData['style'];
7196                         $use = $opData[$direction]['use'];
7197                         $this->debug("have $part_count part(s) to serialize using $style/$use");
7198                         if (is_array($parameters)) {
7199                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
7200                                 $parameter_count = count($parameters);
7201                                 $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
7202                                 // check for Microsoft-style wrapped parameters
7203                                 if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
7204                                         $this->debug('check whether the caller has wrapped the parameters');
7205                                         if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) {
7206                                                 // TODO: consider checking here for double-wrapping, when
7207                                                 // service function wraps, then NuSOAP wraps again
7208                                                 $this->debug("change simple array to associative with 'parameters' element");
7209                                                 $parameters['parameters'] = $parameters[0];
7210                                                 unset($parameters[0]);
7211                                         }
7212                                         if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) {
7213                                                 $this->debug('check whether caller\'s parameters match the wrapped ones');
7214                                                 if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
7215                                                         $this->debug('wrap the parameters for the caller');
7216                                                         $parameters = array('parameters' => $parameters);
7217                                                         $parameter_count = 1;
7218                                                 }
7219                                         }
7220                                 }
7221                                 foreach ($parts as $name => $type) {
7222                                         $this->debug("serializing part $name of type $type");
7223                                         // Track encoding style
7224                                         if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
7225                                                 $encodingStyle = $opData[$direction]['encodingStyle'];
7226                                                 $enc_style = $encodingStyle;
7227                                         } else {
7228                                                 $enc_style = false;
7229                                         }
7230                                         // NOTE: add error handling here
7231                                         // if serializeType returns false, then catch global error and fault
7232                                         if ($parametersArrayType == 'arraySimple') {
7233                                                 $p = array_shift($parameters);
7234                                                 $this->debug('calling serializeType w/indexed param');
7235                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
7236                                         } elseif (isset($parameters[$name])) {
7237                                                 $this->debug('calling serializeType w/named param');
7238                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
7239                                         } else {
7240                                                 // TODO: only send nillable
7241                                                 $this->debug('calling serializeType w/null param');
7242                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
7243                                         }
7244                                 }
7245                         } else {
7246                                 $this->debug('no parameters passed.');
7247                         }
7248                 }
7249                 $this->debug("serializeRPCParameters returning: $xml");
7250                 return $xml;
7251         }
7252
7253         /**
7254          * serialize a PHP value according to a WSDL message definition
7255          *
7256          * TODO
7257          * - multi-ref serialization
7258          * - validate PHP values against type definitions, return errors if invalid
7259          *
7260          * @param string $operation operation name
7261          * @param string $direction (input|output)
7262          * @param mixed $parameters parameter value(s)
7263          * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
7264          * @access public
7265          * @deprecated
7266          */
7267         function serializeParameters($operation, $direction, $parameters)
7268         {
7269                 $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
7270                 $this->appendDebug('parameters=' . $this->varDump($parameters));
7271
7272                 if ($direction != 'input' && $direction != 'output') {
7273                         $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
7274                         $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
7275                         return false;
7276                 }
7277                 if (!$opData = $this->getOperationData($operation)) {
7278                         $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
7279                         $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
7280                         return false;
7281                 }
7282                 $this->debug('opData:');
7283                 $this->appendDebug($this->varDump($opData));
7284
7285                 // Get encoding style for output and set to current
7286                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7287                 if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
7288                         $encodingStyle = $opData['output']['encodingStyle'];
7289                         $enc_style = $encodingStyle;
7290                 }
7291
7292                 // set input params
7293                 $xml = '';
7294                 if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
7295
7296                         $use = $opData[$direction]['use'];
7297                         $this->debug("use=$use");
7298                         $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
7299                         if (is_array($parameters)) {
7300                                 $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
7301                                 $this->debug('have ' . $parametersArrayType . ' parameters');
7302                                 foreach($opData[$direction]['parts'] as $name => $type) {
7303                                         $this->debug('serializing part "'.$name.'" of type "'.$type.'"');
7304                                         // Track encoding style
7305                                         if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
7306                                                 $encodingStyle = $opData[$direction]['encodingStyle'];
7307                                                 $enc_style = $encodingStyle;
7308                                         } else {
7309                                                 $enc_style = false;
7310                                         }
7311                                         // NOTE: add error handling here
7312                                         // if serializeType returns false, then catch global error and fault
7313                                         if ($parametersArrayType == 'arraySimple') {
7314                                                 $p = array_shift($parameters);
7315                                                 $this->debug('calling serializeType w/indexed param');
7316                                                 $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
7317                                         } elseif (isset($parameters[$name])) {
7318                                                 $this->debug('calling serializeType w/named param');
7319                                                 $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
7320                                         } else {
7321                                                 // TODO: only send nillable
7322                                                 $this->debug('calling serializeType w/null param');
7323                                                 $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
7324                                         }
7325                                 }
7326                         } else {
7327                                 $this->debug('no parameters passed.');
7328                         }
7329                 }
7330                 $this->debug("serializeParameters returning: $xml");
7331                 return $xml;
7332         }
7333
7334         /**
7335          * serializes a PHP value according a given type definition
7336          *
7337          * @param string $name name of value (part or element)
7338          * @param string $type XML schema type of value (type or element)
7339          * @param mixed $value a native PHP value (parameter value)
7340          * @param string $use use for part (encoded|literal)
7341          * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
7342          * @param boolean $unqualified a kludge for what should be XML namespace form handling
7343          * @return string value serialized as an XML string
7344          * @access private
7345          */
7346         function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
7347         {
7348                 $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
7349                 $this->appendDebug("value=" . $this->varDump($value));
7350                 if($use == 'encoded' && $encodingStyle) {
7351                         $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
7352                 }
7353
7354                 // if a soapval has been supplied, let its type override the WSDL
7355         if (is_object($value) && get_class($value) == 'soapval') {
7356                 if ($value->type_ns) {
7357                         $type = $value->type_ns . ':' . $value->type;
7358                         $forceType = true;
7359                         $this->debug("in serializeType: soapval overrides type to $type");
7360                 } elseif ($value->type) {
7361                         $type = $value->type;
7362                         $forceType = true;
7363                         $this->debug("in serializeType: soapval overrides type to $type");
7364                 } else {
7365                         $forceType = false;
7366                         $this->debug("in serializeType: soapval does not override type");
7367                 }
7368                 $attrs = $value->attributes;
7369                 $value = $value->value;
7370                 $this->debug("in serializeType: soapval overrides value to $value");
7371                 if ($attrs) {
7372                         if (!is_array($value)) {
7373                                 $value['!'] = $value;
7374                         }
7375                         foreach ($attrs as $n => $v) {
7376                                 $value['!' . $n] = $v;
7377                         }
7378                         $this->debug("in serializeType: soapval provides attributes");
7379                     }
7380         } else {
7381                 $forceType = false;
7382         }
7383
7384                 $xml = '';
7385                 if (strpos($type, ':')) {
7386                         $uqType = substr($type, strrpos($type, ':') + 1);
7387                         $ns = substr($type, 0, strrpos($type, ':'));
7388                         $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
7389                         if ($this->getNamespaceFromPrefix($ns)) {
7390                                 $ns = $this->getNamespaceFromPrefix($ns);
7391                                 $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
7392                         }
7393
7394                         if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
7395                                 $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
7396                                 if ($unqualified && $use == 'literal') {
7397                                         $elementNS = " xmlns=\"\"";
7398                                 } else {
7399                                         $elementNS = '';
7400                                 }
7401                                 if (is_null($value)) {
7402                                         if ($use == 'literal') {
7403                                                 // TODO: depends on minOccurs
7404                                                 $xml = "<$name$elementNS/>";
7405                                         } else {
7406                                                 // TODO: depends on nillable, which should be checked before calling this method
7407                                                 $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
7408                                         }
7409                                         $this->debug("in serializeType: returning: $xml");
7410                                         return $xml;
7411                                 }
7412                                 if ($uqType == 'Array') {
7413                                         // JBoss/Axis does this sometimes
7414                                         return $this->serialize_val($value, $name, false, false, false, false, $use);
7415                                 }
7416                         if ($uqType == 'boolean') {
7417                                 if ((is_string($value) && $value == 'false') || (! $value)) {
7418                                                 $value = 'false';
7419                                         } else {
7420                                                 $value = 'true';
7421                                         }
7422                                 }
7423                                 if ($uqType == 'string' && gettype($value) == 'string') {
7424                                         $value = $this->expandEntities($value);
7425                                 }
7426                                 if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
7427                                         $value = sprintf("%.0lf", $value);
7428                                 }
7429                                 // it's a scalar
7430                                 // TODO: what about null/nil values?
7431                                 // check type isn't a custom type extending xmlschema namespace
7432                                 if (!$this->getTypeDef($uqType, $ns)) {
7433                                         if ($use == 'literal') {
7434                                                 if ($forceType) {
7435                                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
7436                                                 } else {
7437                                                         $xml = "<$name$elementNS>$value</$name>";
7438                                                 }
7439                                         } else {
7440                                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
7441                                         }
7442                                         $this->debug("in serializeType: returning: $xml");
7443                                         return $xml;
7444                                 }
7445                                 $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
7446                         } else if ($ns == 'http://xml.apache.org/xml-soap') {
7447                                 $this->debug('in serializeType: appears to be Apache SOAP type');
7448                                 if ($uqType == 'Map') {
7449                                         $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
7450                                         if (! $tt_prefix) {
7451                                                 $this->debug('in serializeType: Add namespace for Apache SOAP type');
7452                                                 $tt_prefix = 'ns' . rand(1000, 9999);
7453                                                 $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
7454                                                 // force this to be added to usedNamespaces
7455                                                 $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
7456                                         }
7457                                         $contents = '';
7458                                         foreach($value as $k => $v) {
7459                                                 $this->debug("serializing map element: key $k, value $v");
7460                                                 $contents .= '<item>';
7461                                                 $contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
7462                                                 $contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
7463                                                 $contents .= '</item>';
7464                                         }
7465                                         if ($use == 'literal') {
7466                                                 if ($forceType) {
7467                                                         $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
7468                                                 } else {
7469                                                         $xml = "<$name>$contents</$name>";
7470                                                 }
7471                                         } else {
7472                                                 $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
7473                                         }
7474                                         $this->debug("in serializeType: returning: $xml");
7475                                         return $xml;
7476                                 }
7477                                 $this->debug('in serializeType: Apache SOAP type, but only support Map');
7478                         }
7479                 } else {
7480                         // TODO: should the type be compared to types in XSD, and the namespace
7481                         // set to XSD if the type matches?
7482                         $this->debug("in serializeType: No namespace for type $type");
7483                         $ns = '';
7484                         $uqType = $type;
7485                 }
7486                 if(!$typeDef = $this->getTypeDef($uqType, $ns)){
7487                         $this->setError("$type ($uqType) is not a supported type.");
7488                         $this->debug("in serializeType: $type ($uqType) is not a supported type.");
7489                         return false;
7490                 } else {
7491                         $this->debug("in serializeType: found typeDef");
7492                         $this->appendDebug('typeDef=' . $this->varDump($typeDef));
7493                         if (substr($uqType, -1) == '^') {
7494                                 $uqType = substr($uqType, 0, -1);
7495                         }
7496                 }
7497                 if (!isset($typeDef['phpType'])) {
7498                         $this->setError("$type ($uqType) has no phpType.");
7499                         $this->debug("in serializeType: $type ($uqType) has no phpType.");
7500                         return false;
7501                 }
7502                 $phpType = $typeDef['phpType'];
7503                 $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
7504                 // if php type == struct, map value to the <all> element names
7505                 if ($phpType == 'struct') {
7506                         if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
7507                                 $elementName = $uqType;
7508                                 if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
7509                                         $elementNS = " xmlns=\"$ns\"";
7510                                 } else {
7511                                         $elementNS = " xmlns=\"\"";
7512                                 }
7513                         } else {
7514                                 $elementName = $name;
7515                                 if ($unqualified) {
7516                                         $elementNS = " xmlns=\"\"";
7517                                 } else {
7518                                         $elementNS = '';
7519                                 }
7520                         }
7521                         if (is_null($value)) {
7522                                 if ($use == 'literal') {
7523                                         // TODO: depends on minOccurs and nillable
7524                                         $xml = "<$elementName$elementNS/>";
7525                                 } else {
7526                                         $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
7527                                 }
7528                                 $this->debug("in serializeType: returning: $xml");
7529                                 return $xml;
7530                         }
7531                         if (is_object($value)) {
7532                                 $value = get_object_vars($value);
7533                         }
7534                         if (is_array($value)) {
7535                                 $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
7536                                 if ($use == 'literal') {
7537                                         if ($forceType) {
7538                                                 $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
7539                                         } else {
7540                                                 $xml = "<$elementName$elementNS$elementAttrs>";
7541                                         }
7542                                 } else {
7543                                         $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
7544                                 }
7545
7546                                 if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') {
7547                                         if (isset($value['!'])) {
7548                                                 $xml .= $value['!'];
7549                                                 $this->debug("in serializeType: serialized simpleContent for type $type");
7550                                         } else {
7551                                                 $this->debug("in serializeType: no simpleContent to serialize for type $type");
7552                                         }
7553                                 } else {
7554                                         // complexContent
7555                                         $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
7556                                 }
7557                                 $xml .= "</$elementName>";
7558                         } else {
7559                                 $this->debug("in serializeType: phpType is struct, but value is not an array");
7560                                 $this->setError("phpType is struct, but value is not an array: see debug output for details");
7561                                 $xml = '';
7562                         }
7563                 } elseif ($phpType == 'array') {
7564                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
7565                                 $elementNS = " xmlns=\"$ns\"";
7566                         } else {
7567                                 if ($unqualified) {
7568                                         $elementNS = " xmlns=\"\"";
7569                                 } else {
7570                                         $elementNS = '';
7571                                 }
7572                         }
7573                         if (is_null($value)) {
7574                                 if ($use == 'literal') {
7575                                         // TODO: depends on minOccurs
7576                                         $xml = "<$name$elementNS/>";
7577                                 } else {
7578                                         $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
7579                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
7580                                                 ":Array\" " .
7581                                                 $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
7582                                                 ':arrayType="' .
7583                                                 $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
7584                                                 ':' .
7585                                                 $this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
7586                                 }
7587                                 $this->debug("in serializeType: returning: $xml");
7588                                 return $xml;
7589                         }
7590                         if (isset($typeDef['multidimensional'])) {
7591                                 $nv = array();
7592                                 foreach($value as $v) {
7593                                         $cols = ',' . sizeof($v);
7594                                         $nv = array_merge($nv, $v);
7595                                 }
7596                                 $value = $nv;
7597                         } else {
7598                                 $cols = '';
7599                         }
7600                         if (is_array($value) && sizeof($value) >= 1) {
7601                                 $rows = sizeof($value);
7602                                 $contents = '';
7603                                 foreach($value as $k => $v) {
7604                                         $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
7605                                         //if (strpos($typeDef['arrayType'], ':') ) {
7606                                         if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
7607                                             $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
7608                                         } else {
7609                                             $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
7610                                         }
7611                                 }
7612                         } else {
7613                                 $rows = 0;
7614                                 $contents = null;
7615                         }
7616                         // TODO: for now, an empty value will be serialized as a zero element
7617                         // array.  Revisit this when coding the handling of null/nil values.
7618                         if ($use == 'literal') {
7619                                 $xml = "<$name$elementNS>"
7620                                         .$contents
7621                                         ."</$name>";
7622                         } else {
7623                                 $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
7624                                         $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
7625                                         .':arrayType="'
7626                                         .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
7627                                         .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
7628                                         .$contents
7629                                         ."</$name>";
7630                         }
7631                 } elseif ($phpType == 'scalar') {
7632                         if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
7633                                 $elementNS = " xmlns=\"$ns\"";
7634                         } else {
7635                                 if ($unqualified) {
7636                                         $elementNS = " xmlns=\"\"";
7637                                 } else {
7638                                         $elementNS = '';
7639                                 }
7640                         }
7641                         if ($use == 'literal') {
7642                                 if ($forceType) {
7643                                         $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
7644                                 } else {
7645                                         $xml = "<$name$elementNS>$value</$name>";
7646                                 }
7647                         } else {
7648                                 $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
7649                         }
7650                 }
7651                 $this->debug("in serializeType: returning: $xml");
7652                 return $xml;
7653         }
7654
7655         /**
7656          * serializes the attributes for a complexType
7657          *
7658          * @param array $typeDef our internal representation of an XML schema type (or element)
7659          * @param mixed $value a native PHP value (parameter value)
7660          * @param string $ns the namespace of the type
7661          * @param string $uqType the local part of the type
7662          * @return string value serialized as an XML string
7663          * @access private
7664          */
7665         function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
7666                 $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
7667                 $xml = '';
7668                 if (isset($typeDef['extensionBase'])) {
7669                         $nsx = $this->getPrefix($typeDef['extensionBase']);
7670                         $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
7671                         if ($this->getNamespaceFromPrefix($nsx)) {
7672                                 $nsx = $this->getNamespaceFromPrefix($nsx);
7673                         }
7674                         if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
7675                                 $this->debug("serialize attributes for extension base $nsx:$uqTypex");
7676                                 $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
7677                         } else {
7678                                 $this->debug("extension base $nsx:$uqTypex is not a supported type");
7679                         }
7680                 }
7681                 if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
7682                         $this->debug("serialize attributes for XML Schema type $ns:$uqType");
7683                         if (is_array($value)) {
7684                                 $xvalue = $value;
7685                         } elseif (is_object($value)) {
7686                                 $xvalue = get_object_vars($value);
7687                         } else {
7688                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
7689                                 $xvalue = array();
7690                         }
7691                         foreach ($typeDef['attrs'] as $aName => $attrs) {
7692                                 if (isset($xvalue['!' . $aName])) {
7693                                         $xname = '!' . $aName;
7694                                         $this->debug("value provided for attribute $aName with key $xname");
7695                                 } elseif (isset($xvalue[$aName])) {
7696                                         $xname = $aName;
7697                                         $this->debug("value provided for attribute $aName with key $xname");
7698                                 } elseif (isset($attrs['default'])) {
7699                                         $xname = '!' . $aName;
7700                                         $xvalue[$xname] = $attrs['default'];
7701                                         $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
7702                                 } else {
7703                                         $xname = '';
7704                                         $this->debug("no value provided for attribute $aName");
7705                                 }
7706                                 if ($xname) {
7707                                         $xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
7708                                 }
7709                         }
7710                 } else {
7711                         $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
7712                 }
7713                 return $xml;
7714         }
7715
7716         /**
7717          * serializes the elements for a complexType
7718          *
7719          * @param array $typeDef our internal representation of an XML schema type (or element)
7720          * @param mixed $value a native PHP value (parameter value)
7721          * @param string $ns the namespace of the type
7722          * @param string $uqType the local part of the type
7723          * @param string $use use for part (encoded|literal)
7724          * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
7725          * @return string value serialized as an XML string
7726          * @access private
7727          */
7728         function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
7729                 $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
7730                 $xml = '';
7731                 if (isset($typeDef['extensionBase'])) {
7732                         $nsx = $this->getPrefix($typeDef['extensionBase']);
7733                         $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
7734                         if ($this->getNamespaceFromPrefix($nsx)) {
7735                                 $nsx = $this->getNamespaceFromPrefix($nsx);
7736                         }
7737                         if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
7738                                 $this->debug("serialize elements for extension base $nsx:$uqTypex");
7739                                 $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
7740                         } else {
7741                                 $this->debug("extension base $nsx:$uqTypex is not a supported type");
7742                         }
7743                 }
7744                 if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
7745                         $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
7746                         if (is_array($value)) {
7747                                 $xvalue = $value;
7748                         } elseif (is_object($value)) {
7749                                 $xvalue = get_object_vars($value);
7750                         } else {
7751                                 $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
7752                                 $xvalue = array();
7753                         }
7754                         // toggle whether all elements are present - ideally should validate against schema
7755                         if (count($typeDef['elements']) != count($xvalue)){
7756                                 $optionals = true;
7757                         }
7758                         foreach ($typeDef['elements'] as $eName => $attrs) {
7759                                 if (!isset($xvalue[$eName])) {
7760                                         if (isset($attrs['default'])) {
7761                                                 $xvalue[$eName] = $attrs['default'];
7762                                                 $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
7763                                         }
7764                                 }
7765                                 // if user took advantage of a minOccurs=0, then only serialize named parameters
7766                                 if (isset($optionals)
7767                                     && (!isset($xvalue[$eName]))
7768                                         && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
7769                                         ){
7770                                         if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
7771                                                 $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
7772                                         }
7773                                         // do nothing
7774                                         $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
7775                                 } else {
7776                                         // get value
7777                                         if (isset($xvalue[$eName])) {
7778                                             $v = $xvalue[$eName];
7779                                         } else {
7780                                             $v = null;
7781                                         }
7782                                         if (isset($attrs['form'])) {
7783                                                 $unqualified = ($attrs['form'] == 'unqualified');
7784                                         } else {
7785                                                 $unqualified = false;
7786                                         }
7787                                         if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
7788                                                 $vv = $v;
7789                                                 foreach ($vv as $k => $v) {
7790                                                         if (isset($attrs['type']) || isset($attrs['ref'])) {
7791                                                                 // serialize schema-defined type
7792                                                             $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
7793                                                         } else {
7794                                                                 // serialize generic type (can this ever really happen?)
7795                                                             $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
7796                                                             $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
7797                                                         }
7798                                                 }
7799                                         } else {
7800                                                 if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') {
7801                                                         // do nothing
7802                                                 } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') {
7803                                                         // TODO: serialize a nil correctly, but for now serialize schema-defined type
7804                                                     $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
7805                                                 } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
7806                                                         // serialize schema-defined type
7807                                                     $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
7808                                                 } else {
7809                                                         // serialize generic type (can this ever really happen?)
7810                                                     $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
7811                                                     $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
7812                                                 }
7813                                         }
7814                                 }
7815                         }
7816                 } else {
7817                         $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
7818                 }
7819                 return $xml;
7820         }
7821
7822         /**
7823         * adds an XML Schema complex type to the WSDL types
7824         *
7825         * @param string $name
7826         * @param string $typeClass (complexType|simpleType|attribute)
7827         * @param string $phpType currently supported are array and struct (php assoc array)
7828         * @param string $compositor (all|sequence|choice)
7829         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
7830         * @param array $elements e.g. array ( name => array(name=>'',type=>'') )
7831         * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
7832         * @param string $arrayType as namespace:name (xsd:string)
7833         * @see nusoap_xmlschema
7834         * @access public
7835         */
7836         function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
7837                 if (count($elements) > 0) {
7838                         $eElements = array();
7839                 foreach($elements as $n => $e){
7840                     // expand each element
7841                     $ee = array();
7842                     foreach ($e as $k => $v) {
7843                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
7844                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
7845                             $ee[$k] = $v;
7846                         }
7847                         $eElements[$n] = $ee;
7848                 }
7849                 $elements = $eElements;
7850                 }
7851
7852                 if (count($attrs) > 0) {
7853                 foreach($attrs as $n => $a){
7854                     // expand each attribute
7855                     foreach ($a as $k => $v) {
7856                             $k = strpos($k,':') ? $this->expandQname($k) : $k;
7857                             $v = strpos($v,':') ? $this->expandQname($v) : $v;
7858                             $aa[$k] = $v;
7859                         }
7860                         $eAttrs[$n] = $aa;
7861                 }
7862                 $attrs = $eAttrs;
7863                 }
7864
7865                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
7866                 $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
7867
7868                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
7869                 $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
7870         }
7871
7872         /**
7873         * adds an XML Schema simple type to the WSDL types
7874         *
7875         * @param string $name
7876         * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
7877         * @param string $typeClass (should always be simpleType)
7878         * @param string $phpType (should always be scalar)
7879         * @param array $enumeration array of values
7880         * @see nusoap_xmlschema
7881         * @access public
7882         */
7883         function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
7884                 $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
7885
7886                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
7887                 $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
7888         }
7889
7890         /**
7891         * adds an element to the WSDL types
7892         *
7893         * @param array $attrs attributes that must include name and type
7894         * @see nusoap_xmlschema
7895         * @access public
7896         */
7897         function addElement($attrs) {
7898                 $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
7899                 $this->schemas[$typens][0]->addElement($attrs);
7900         }
7901
7902         /**
7903         * register an operation with the server
7904         *
7905         * @param string $name operation (method) name
7906         * @param array $in assoc array of input values: key = param name, value = param type
7907         * @param array $out assoc array of output values: key = param name, value = param type
7908         * @param string $namespace optional The namespace for the operation
7909         * @param string $soapaction optional The soapaction for the operation
7910         * @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
7911         * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
7912         * @param string $documentation optional The description to include in the WSDL
7913         * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
7914         * @access public
7915         */
7916         function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
7917                 if ($use == 'encoded' && $encodingStyle == '') {
7918                         $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7919                 }
7920
7921                 if ($style == 'document') {
7922                         $elements = array();
7923                         foreach ($in as $n => $t) {
7924                                 $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
7925                         }
7926                         $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
7927                         $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
7928                         $in = array('parameters' => 'tns:' . $name . '^');
7929
7930                         $elements = array();
7931                         foreach ($out as $n => $t) {
7932                                 $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
7933                         }
7934                         $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
7935                         $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
7936                         $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
7937                 }
7938
7939                 // get binding
7940                 $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
7941                 array(
7942                 'name' => $name,
7943                 'binding' => $this->serviceName . 'Binding',
7944                 'endpoint' => $this->endpoint,
7945                 'soapAction' => $soapaction,
7946                 'style' => $style,
7947                 'input' => array(
7948                         'use' => $use,
7949                         'namespace' => $namespace,
7950                         'encodingStyle' => $encodingStyle,
7951                         'message' => $name . 'Request',
7952                         'parts' => $in),
7953                 'output' => array(
7954                         'use' => $use,
7955                         'namespace' => $namespace,
7956                         'encodingStyle' => $encodingStyle,
7957                         'message' => $name . 'Response',
7958                         'parts' => $out),
7959                 'namespace' => $namespace,
7960                 'transport' => 'http://schemas.xmlsoap.org/soap/http',
7961                 'documentation' => $documentation);
7962                 // add portTypes
7963                 // add messages
7964                 if($in)
7965                 {
7966                         foreach($in as $pName => $pType)
7967                         {
7968                                 if(strpos($pType,':')) {
7969                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
7970                                 }
7971                                 $this->messages[$name.'Request'][$pName] = $pType;
7972                         }
7973                 } else {
7974             $this->messages[$name.'Request']= '0';
7975         }
7976                 if($out)
7977                 {
7978                         foreach($out as $pName => $pType)
7979                         {
7980                                 if(strpos($pType,':')) {
7981                                         $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
7982                                 }
7983                                 $this->messages[$name.'Response'][$pName] = $pType;
7984                         }
7985                 } else {
7986             $this->messages[$name.'Response']= '0';
7987         }
7988                 return true;
7989         }
7990 }
7991 ?><?php
7992
7993 /*
7994
7995 Modification information for LGPL compliance
7996
7997 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
7998     bug 40066
7999
8000 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
8001     Merging with maint_6_0_1 (svn merge -r 58250:58342)
8002
8003 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
8004     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.
8005
8006 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
8007     fix SOAP calls with no parameters
8008
8009 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
8010
8011 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
8012
8013 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
8014
8015 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
8016
8017 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
8018
8019 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.
8020
8021 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.
8022
8023 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:
8024 - Changing all ereg function to either preg or simple string based ones
8025 - No more references to magic quotes.
8026 - Change all the session_unregister() functions to just unset() the correct session variable instead.
8027
8028 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
8029
8030 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
8031
8032 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
8033
8034 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
8035
8036 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
8037
8038 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
8039
8040 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
8041
8042 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
8043
8044 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.
8045 Touched:
8046 - data/SugarBean.php
8047 - include/domit/php_http_client_generic.php
8048 - include/domit/php_http_connector.php
8049 - include/domit/testing_domit.php
8050 - include/domit/xml_domit_getelementsbypath.php
8051 - include/domit/xml_domit_lite_parser.php
8052 - include/domit/xml_domit_nodemaps.php
8053 - include/domit/xml_domit_parser.php
8054 - include/domit/xml_domit_shared.php
8055 - include/generic/SugarWidgets/SugarWidgetField.php
8056 - include/generic/SugarWidgets/SugarWidgetReportField.php
8057 - include/ListView/ProcessView.php
8058 - include/nusoap/class.soapclient.php
8059 - include/nusoap/nusoap.php
8060 - include/nusoap/nusoapmime.php
8061 - include/Pear/HTML_Safe/Safe.php
8062 - include/Pear/XML_HTMLSax3/HTMLSax3.php
8063 - modules/Administration/RebuildWorkFlow.php
8064 - modules/Expressions/RelateSelector.php
8065 - modules/Reports/templates/templates_reports.php
8066 - modules/WorkFlow/Delete.php
8067 - modules/WorkFlow/Save.php
8068 - modules/WorkFlow/SaveSequence.php
8069 - modules/WorkFlow/WorkFlow.php
8070 - modules/WorkFlowActionShells/CreateStep1.php
8071 - modules/WorkFlowActionShells/CreateStep2.php
8072 - modules/WorkFlowActionShells/Save.php
8073 - modules/WorkFlowActionShells/WorkFlowActionShell.php
8074 - modules/WorkFlowAlerts/Save.php
8075 - modules/WorkFlowAlerts/WorkFlowAlert.php
8076 - modules/WorkFlowAlertShells/DetailView.php
8077 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
8078 - modules/WorkFlowTriggerShells/CreateStep1.php
8079 - modules/WorkFlowTriggerShells/CreateStepFilter.php
8080 - modules/WorkFlowTriggerShells/SaveFilter.php
8081 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
8082 - soap/SoapHelperFunctions.php
8083 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
8084 - test/simpletest/browser.php
8085 - test/simpletest/default_reporter.php
8086 - test/simpletest/detached.php
8087 - test/simpletest/eclipse.php
8088 - test/simpletest/expectation.php
8089 - test/simpletest/extensions/pear_test_case.php
8090 - test/simpletest/form.php
8091 - test/simpletest/http.php
8092 - test/simpletest/mock_objects.php
8093 - test/simpletest/page.php
8094 - test/simpletest/parser.php
8095 - test/simpletest/remote.php
8096 - test/simpletest/shell_tester.php
8097 - test/simpletest/simple_test.php
8098 - test/simpletest/simpletest.php
8099 - test/simpletest/test/acceptance_test.php
8100 - test/simpletest/test/adapter_test.php
8101 - test/simpletest/test/authentication_test.php
8102 - test/simpletest/test/browser_test.php
8103 - test/simpletest/test/collector_test.php
8104 - test/simpletest/test/compatibility_test.php
8105 - test/simpletest/test/detached_test.php
8106 - test/simpletest/test/eclipse_test.php
8107 - test/simpletest/test/encoding_test.php
8108 - test/simpletest/test/errors_test.php
8109 - test/simpletest/test/expectation_test.php
8110 - test/simpletest/test/form_test.php
8111 - test/simpletest/test/frames_test.php
8112 - test/simpletest/test/http_test.php
8113 - test/simpletest/test/live_test.php
8114 - test/simpletest/test/mock_objects_test.php
8115 - test/simpletest/test/page_test.php
8116 - test/simpletest/test/parse_error_test.php
8117 - test/simpletest/test/parser_test.php
8118 - test/simpletest/test/remote_test.php
8119 - test/simpletest/test/shell_test.php
8120 - test/simpletest/test/shell_tester_test.php
8121 - test/simpletest/test/simpletest_test.php
8122 - test/simpletest/test/site/page_request.php
8123 - test/simpletest/test/tag_test.php
8124 - test/simpletest/test/unit_tester_test.php
8125 - test/simpletest/test/user_agent_test.php
8126 - test/simpletest/test/visual_test.php
8127 - test/simpletest/test/xml_test.php
8128 - test/simpletest/test_case.php
8129 - test/simpletest/ui/array_reporter/test.php
8130 - test/simpletest/ui/recorder/test.php
8131 - test/simpletest/unit_tester.php
8132 - test/simpletest/url.php
8133 - test/simpletest/user_agent.php
8134 - test/simpletest/web_tester.php
8135 - test/spikephpcoverage/src/PEAR.php
8136 - test/spikephpcoverage/src/util/Utility.php
8137 - test/spikephpcoverage/src/XML/Parser.php
8138 - test/spikephpcoverage/src/XML/Parser/Simple.php
8139 - test/test_utilities/SugarTest_SimpleBrowser.php
8140
8141 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.
8142
8143 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
8144
8145 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
8146
8147 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
8148
8149 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
8150
8151 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
8152
8153 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
8154
8155 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
8156
8157 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
8158
8159 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
8160
8161 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
8162
8163 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
8164
8165 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.
8166
8167 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
8168
8169 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
8170
8171 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
8172
8173 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
8174
8175 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
8176
8177 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
8178
8179 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
8180
8181 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
8182
8183 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
8184
8185 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
8186
8187 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
8188
8189
8190 */
8191
8192
8193
8194
8195
8196 /**
8197 *
8198 * nusoap_parser class parses SOAP XML messages into native PHP values
8199 *
8200 * @author   Dietrich Ayala <dietrich@ganx4.com>
8201 * @author   Scott Nichol <snichol@users.sourceforge.net>
8202
8203 * @access   public
8204 */
8205 class nusoap_parser extends nusoap_base {
8206
8207         var $xml = '';
8208         var $xml_encoding = '';
8209         var $method = '';
8210         var $root_struct = '';
8211         var $root_struct_name = '';
8212         var $root_struct_namespace = '';
8213         var $root_header = '';
8214     var $document = '';                 // incoming SOAP body (text)
8215         // determines where in the message we are (envelope,header,body,method)
8216         var $status = '';
8217         var $position = 0;
8218         var $depth = 0;
8219         var $default_namespace = '';
8220         var $namespaces = array();
8221         var $message = array();
8222     var $parent = '';
8223         var $fault = false;
8224         var $fault_code = '';
8225         var $fault_str = '';
8226         var $fault_detail = '';
8227         var $depth_array = array();
8228         var $debug_flag = true;
8229         var $soapresponse = NULL;       // parsed SOAP Body
8230         var $soapheader = NULL;         // parsed SOAP Header
8231         var $responseHeaders = '';      // incoming SOAP headers (text)
8232         var $body_position = 0;
8233         // for multiref parsing:
8234         // array of id => pos
8235         var $ids = array();
8236         // array of id => hrefs => pos
8237         var $multirefs = array();
8238         // toggle for auto-decoding element content
8239         var $decode_utf8 = false;
8240
8241         /**
8242         * constructor that actually does the parsing
8243         *
8244         * @param    string $xml SOAP message
8245         * @param    string $encoding character encoding scheme of message
8246         * @param    string $method method for which XML is parsed (unused?)
8247         * @param    string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
8248         * @access   public
8249         */
8250         function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){
8251                 parent::nusoap_base();
8252                 $this->xml = $xml;
8253                 $this->xml_encoding = $encoding;
8254                 $this->method = $method;
8255                 $this->decode_utf8 = $decode_utf8;
8256
8257                 // Check whether content has been read.
8258                 if(!empty($xml)){
8259                         // Check XML encoding
8260                         $pos_xml = strpos($xml, '<?xml');
8261                         if ($pos_xml !== FALSE) {
8262                                 $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
8263                                 if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
8264                                         $xml_encoding = $res[1];
8265                                         if (strtoupper($xml_encoding) != $encoding) {
8266                                                 $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
8267                                                 $this->debug($err);
8268                                                 if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
8269                                                         $this->setError($err);
8270                                                         return;
8271                                                 }
8272                                                 // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
8273                                         } else {
8274                                                 $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
8275                                         }
8276                                 } else {
8277                                         $this->debug('No encoding specified in XML declaration');
8278                                 }
8279                         } else {
8280                                 $this->debug('No XML declaration');
8281                         }
8282                         $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding);
8283                         // Create an XML parser - why not xml_parser_create_ns?
8284                         $this->parser = xml_parser_create($this->xml_encoding);
8285                         // Set the options for parsing the XML data.
8286                         //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
8287                         xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
8288                         xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
8289                         // Set the object for the parser.
8290                         xml_set_object($this->parser, $this);
8291                         // Set the element handlers for the parser.
8292                         xml_set_element_handler($this->parser, 'start_element','end_element');
8293                         xml_set_character_data_handler($this->parser,'character_data');
8294
8295                         // Parse the XML file.
8296                         if(!xml_parse($this->parser,$xml,true)){
8297                             // Display an error message.
8298                             $err = sprintf('XML error parsing SOAP payload on line %d: %s',
8299                             xml_get_current_line_number($this->parser),
8300                             xml_error_string(xml_get_error_code($this->parser)));
8301                                 $this->debug($err);
8302                                 $this->debug("XML payload:\n" . $xml);
8303                                 $this->setError($err);
8304                         } else {
8305                                 $this->debug('in nusoap_parser ctor, message:');
8306                                 $this->appendDebug($this->varDump($this->message));
8307                                 $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name);
8308                                 // get final value
8309                                 $this->soapresponse = $this->message[$this->root_struct]['result'];
8310                                 // get header value
8311                                 if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){
8312                                         $this->soapheader = $this->message[$this->root_header]['result'];
8313                                 }
8314                                 // resolve hrefs/ids
8315                                 if(sizeof($this->multirefs) > 0){
8316                                         foreach($this->multirefs as $id => $hrefs){
8317                                                 $this->debug('resolving multirefs for id: '.$id);
8318                                                 $idVal = $this->buildVal($this->ids[$id]);
8319                                                 if (is_array($idVal) && isset($idVal['!id'])) {
8320                                                         unset($idVal['!id']);
8321                                                 }
8322                                                 foreach($hrefs as $refPos => $ref){
8323                                                         $this->debug('resolving href at pos '.$refPos);
8324                                                         $this->multirefs[$id][$refPos] = $idVal;
8325                                                 }
8326                                         }
8327                                 }
8328                         }
8329                         xml_parser_free($this->parser);
8330                 } else {
8331                         $this->debug('xml was empty, didn\'t parse!');
8332                         $this->setError('xml was empty, didn\'t parse!');
8333                 }
8334         }
8335
8336         /**
8337         * start-element handler
8338         *
8339         * @param    resource $parser XML parser object
8340         * @param    string $name element name
8341         * @param    array $attrs associative array of attributes
8342         * @access   private
8343         */
8344         function start_element($parser, $name, $attrs) {
8345                 // position in a total number of elements, starting from 0
8346                 // update class level pos
8347                 $pos = $this->position++;
8348                 // and set mine
8349                 $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>'');
8350                 // depth = how many levels removed from root?
8351                 // set mine as current global depth and increment global depth value
8352                 $this->message[$pos]['depth'] = $this->depth++;
8353
8354                 // else add self as child to whoever the current parent is
8355                 if($pos != 0){
8356                         $this->message[$this->parent]['children'] .= '|'.$pos;
8357                 }
8358                 // set my parent
8359                 $this->message[$pos]['parent'] = $this->parent;
8360                 // set self as current parent
8361                 $this->parent = $pos;
8362                 // set self as current value for this depth
8363                 $this->depth_array[$this->depth] = $pos;
8364                 // get element prefix
8365                 if(strpos($name,':')){
8366                         // get ns prefix
8367                         $prefix = substr($name,0,strpos($name,':'));
8368                         // get unqualified name
8369                         $name = substr(strstr($name,':'),1);
8370                 }
8371                 // set status
8372                 if ($name == 'Envelope' && $this->status == '') {
8373                         $this->status = 'envelope';
8374                 } elseif ($name == 'Header' && $this->status == 'envelope') {
8375                         $this->root_header = $pos;
8376                         $this->status = 'header';
8377                 } elseif ($name == 'Body' && $this->status == 'envelope'){
8378                         $this->status = 'body';
8379                         $this->body_position = $pos;
8380                 // set method
8381                 } elseif($this->status == 'body' && $pos == ($this->body_position+1)) {
8382                         $this->status = 'method';
8383                         $this->root_struct_name = $name;
8384                         $this->root_struct = $pos;
8385                         $this->message[$pos]['type'] = 'struct';
8386                         $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
8387                 }
8388                 // set my status
8389                 $this->message[$pos]['status'] = $this->status;
8390                 // set name
8391                 $this->message[$pos]['name'] = htmlspecialchars($name);
8392                 // set attrs
8393                 $this->message[$pos]['attrs'] = $attrs;
8394
8395                 // loop through atts, logging ns and type declarations
8396         $attstr = '';
8397                 foreach($attrs as $key => $value){
8398                 $key_prefix = $this->getPrefix($key);
8399                         $key_localpart = $this->getLocalPart($key);
8400                         // if ns declarations, add to class level array of valid namespaces
8401             if($key_prefix == 'xmlns'){
8402                                 if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){
8403                                         $this->XMLSchemaVersion = $value;
8404                                         $this->namespaces['xsd'] = $this->XMLSchemaVersion;
8405                                         $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance';
8406                                 }
8407                 $this->namespaces[$key_localpart] = $value;
8408                                 // set method namespace
8409                                 if($name == $this->root_struct_name){
8410                                         $this->methodNamespace = $value;
8411                                 }
8412                         // if it's a type declaration, set type
8413         } elseif($key_localpart == 'type'){
8414                         if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
8415                                 // do nothing: already processed arrayType
8416                         } else {
8417                         $value_prefix = $this->getPrefix($value);
8418                         $value_localpart = $this->getLocalPart($value);
8419                                         $this->message[$pos]['type'] = $value_localpart;
8420                                         $this->message[$pos]['typePrefix'] = $value_prefix;
8421                         if(isset($this->namespaces[$value_prefix])){
8422                                 $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
8423                         } else if(isset($attrs['xmlns:'.$value_prefix])) {
8424                                                 $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix];
8425                         }
8426                                         // should do something here with the namespace of specified type?
8427                                 }
8428                         } elseif($key_localpart == 'arrayType'){
8429                                 $this->message[$pos]['type'] = 'array';
8430                                 /* do arrayType ereg here
8431                                 [1]    arrayTypeValue    ::=    atype asize
8432                                 [2]    atype    ::=    QName rank*
8433                                 [3]    rank    ::=    '[' (',')* ']'
8434                                 [4]    asize    ::=    '[' length~ ']'
8435                                 [5]    length    ::=    nextDimension* Digit+
8436                                 [6]    nextDimension    ::=    Digit+ ','
8437                                 */
8438                                 $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
8439                                 if(preg_match($expr,$value,$regs)){
8440                                         $this->message[$pos]['typePrefix'] = $regs[1];
8441                                         $this->message[$pos]['arrayTypePrefix'] = $regs[1];
8442                         if (isset($this->namespaces[$regs[1]])) {
8443                                 $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
8444                         } else if (isset($attrs['xmlns:'.$regs[1]])) {
8445                                                 $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]];
8446                         }
8447                                         $this->message[$pos]['arrayType'] = $regs[2];
8448                                         $this->message[$pos]['arraySize'] = $regs[3];
8449                                         $this->message[$pos]['arrayCols'] = $regs[4];
8450                                 }
8451                         // specifies nil value (or not)
8452                         } elseif ($key_localpart == 'nil'){
8453                                 $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
8454                         // some other attribute
8455                         } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
8456                                 $this->message[$pos]['xattrs']['!' . $key] = $value;
8457                         }
8458
8459                         if ($key == 'xmlns') {
8460                                 $this->default_namespace = $value;
8461                         }
8462                         // log id
8463                         if($key == 'id'){
8464                                 $this->ids[$value] = $pos;
8465                         }
8466                         // root
8467                         if($key_localpart == 'root' && $value == 1){
8468                                 $this->status = 'method';
8469                                 $this->root_struct_name = $name;
8470                                 $this->root_struct = $pos;
8471                                 $this->debug("found root struct $this->root_struct_name, pos $pos");
8472                         }
8473             // for doclit
8474             $attstr .= " $key=\"$value\"";
8475                 }
8476         // get namespace - must be done after namespace atts are processed
8477                 if(isset($prefix)){
8478                         $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
8479                         $this->default_namespace = $this->namespaces[$prefix];
8480                 } else {
8481                         $this->message[$pos]['namespace'] = $this->default_namespace;
8482                 }
8483         if($this->status == 'header'){
8484                 if ($this->root_header != $pos) {
8485                         $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
8486                 }
8487         } elseif($this->root_struct_name != ''){
8488                 $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
8489         }
8490         }
8491
8492         /**
8493         * end-element handler
8494         *
8495         * @param    resource $parser XML parser object
8496         * @param    string $name element name
8497         * @access   private
8498         */
8499         function end_element($parser, $name) {
8500                 // position of current element is equal to the last value left in depth_array for my depth
8501                 $pos = $this->depth_array[$this->depth--];
8502
8503         // get element prefix
8504                 if(strpos($name,':')){
8505                         // get ns prefix
8506                         $prefix = substr($name,0,strpos($name,':'));
8507                         // get unqualified name
8508                         $name = substr(strstr($name,':'),1);
8509                 }
8510
8511                 // build to native type
8512                 if(isset($this->body_position) && $pos > $this->body_position){
8513                         // deal w/ multirefs
8514                         if(isset($this->message[$pos]['attrs']['href'])){
8515                                 // get id
8516                                 $id = substr($this->message[$pos]['attrs']['href'],1);
8517                                 // add placeholder to href array
8518                                 $this->multirefs[$id][$pos] = 'placeholder';
8519                                 // add set a reference to it as the result value
8520                                 $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
8521             // build complexType values
8522                         } elseif($this->message[$pos]['children'] != ''){
8523                                 // if result has already been generated (struct/array)
8524                                 if(!isset($this->message[$pos]['result'])){
8525                                         $this->message[$pos]['result'] = $this->buildVal($pos);
8526                                 }
8527                         // build complexType values of attributes and possibly simpleContent
8528                         } elseif (isset($this->message[$pos]['xattrs'])) {
8529                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
8530                                         $this->message[$pos]['xattrs']['!'] = null;
8531                                 } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
8532                         if (isset($this->message[$pos]['type'])) {
8533                                                 $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'] : '');
8534                                         } else {
8535                                                 $parent = $this->message[$pos]['parent'];
8536                                                 if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8537                                                         $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8538                                                 } else {
8539                                                         $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
8540                                                 }
8541                                         }
8542                                 }
8543                                 $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
8544                         // set value of simpleType (or nil complexType)
8545                         } else {
8546                 //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
8547                                 if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
8548                                         $this->message[$pos]['xattrs']['!'] = null;
8549                                 } elseif (isset($this->message[$pos]['type'])) {
8550                                         $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'] : '');
8551                                 } else {
8552                                         $parent = $this->message[$pos]['parent'];
8553                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8554                                                 $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8555                                         } else {
8556                                                 $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
8557                                         }
8558                                 }
8559
8560                                 /* add value to parent's result, if parent is struct/array
8561                                 $parent = $this->message[$pos]['parent'];
8562                                 if($this->message[$parent]['type'] != 'map'){
8563                                         if(strtolower($this->message[$parent]['type']) == 'array'){
8564                                                 $this->message[$parent]['result'][] = $this->message[$pos]['result'];
8565                                         } else {
8566                                                 $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
8567                                         }
8568                                 }
8569                                 */
8570                         }
8571                 }
8572
8573         // for doclit
8574         if($this->status == 'header'){
8575                 if ($this->root_header != $pos) {
8576                         $this->responseHeaders .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
8577                 }
8578         } elseif($pos >= $this->root_struct){
8579                 $this->document .= "</" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
8580         }
8581                 // switch status
8582                 if ($pos == $this->root_struct){
8583                         $this->status = 'body';
8584                         $this->root_struct_namespace = $this->message[$pos]['namespace'];
8585                 } elseif ($pos == $this->root_header) {
8586                         $this->status = 'envelope';
8587                 } elseif ($name == 'Body' && $this->status == 'body') {
8588                         $this->status = 'envelope';
8589                 } elseif ($name == 'Header' && $this->status == 'header') { // will never happen
8590                         $this->status = 'envelope';
8591                 } elseif ($name == 'Envelope' && $this->status == 'envelope') {
8592                         $this->status = '';
8593                 }
8594                 // set parent back to my parent
8595                 $this->parent = $this->message[$pos]['parent'];
8596         }
8597
8598         /**
8599         * element content handler
8600         *
8601         * @param    resource $parser XML parser object
8602         * @param    string $data element content
8603         * @access   private
8604         */
8605         function character_data($parser, $data){
8606                 $pos = $this->depth_array[$this->depth];
8607                 if ($this->xml_encoding=='UTF-8'){
8608                         // TODO: add an option to disable this for folks who want
8609                         // raw UTF-8 that, e.g., might not map to iso-8859-1
8610                         // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
8611                         if($this->decode_utf8){
8612                                 $data = utf8_decode($data);
8613                         }
8614                 }
8615         $this->message[$pos]['cdata'] .= $data;
8616         // for doclit
8617         if($this->status == 'header'){
8618                 $this->responseHeaders .= $data;
8619         } else {
8620                 $this->document .= $data;
8621         }
8622         }
8623
8624         /**
8625         * get the parsed message (SOAP Body)
8626         *
8627         * @return       mixed
8628         * @access   public
8629         * @deprecated   use get_soapbody instead
8630         */
8631         function get_response(){
8632                 return $this->soapresponse;
8633         }
8634
8635         /**
8636         * get the parsed SOAP Body (NULL if there was none)
8637         *
8638         * @return       mixed
8639         * @access   public
8640         */
8641         function get_soapbody(){
8642                 return $this->soapresponse;
8643         }
8644
8645         /**
8646         * get the parsed SOAP Header (NULL if there was none)
8647         *
8648         * @return       mixed
8649         * @access   public
8650         */
8651         function get_soapheader(){
8652                 return $this->soapheader;
8653         }
8654
8655         /**
8656         * get the unparsed SOAP Header
8657         *
8658         * @return       string XML or empty if no Header
8659         * @access   public
8660         */
8661         function getHeaders(){
8662             return $this->responseHeaders;
8663         }
8664
8665         /**
8666         * decodes simple types into PHP variables
8667         *
8668         * @param    string $value value to decode
8669         * @param    string $type XML type to decode
8670         * @param    string $typens XML type namespace to decode
8671         * @return       mixed PHP value
8672         * @access   private
8673         */
8674         function decodeSimple($value, $type, $typens) {
8675                 // TODO: use the namespace!
8676                 if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
8677                         return (string) $value;
8678                 }
8679                 if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
8680                         return (int) $value;
8681                 }
8682                 if ($type == 'float' || $type == 'double' || $type == 'decimal') {
8683                         return (double) $value;
8684                 }
8685                 if ($type == 'boolean') {
8686                         if (strtolower($value) == 'false' || strtolower($value) == 'f') {
8687                                 return false;
8688                         }
8689                         return (boolean) $value;
8690                 }
8691                 if ($type == 'base64' || $type == 'base64Binary') {
8692                         $this->debug('Decode base64 value');
8693                         return base64_decode($value);
8694                 }
8695                 // obscure numeric types
8696                 if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
8697                         || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
8698                         || $type == 'unsignedInt'
8699                         || $type == 'unsignedShort' || $type == 'unsignedByte') {
8700                         return (int) $value;
8701                 }
8702                 // bogus: parser treats array with no elements as a simple type
8703                 if ($type == 'array') {
8704                         return array();
8705                 }
8706                 // everything else
8707                 return (string) $value;
8708         }
8709
8710         /**
8711         * builds response structures for compound values (arrays/structs)
8712         * and scalars
8713         *
8714         * @param    integer $pos position in node tree
8715         * @return       mixed   PHP value
8716         * @access   private
8717         */
8718         function buildVal($pos){
8719                 if(!isset($this->message[$pos]['type'])){
8720                         $this->message[$pos]['type'] = '';
8721                 }
8722                 $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']);
8723                 // if there are children...
8724                 if($this->message[$pos]['children'] != ''){
8725                         $this->debug('in buildVal, there are children');
8726                         $children = explode('|',$this->message[$pos]['children']);
8727                         array_shift($children); // knock off empty
8728                         // md array
8729                         if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){
8730                 $r=0; // rowcount
8731                 $c=0; // colcount
8732                 foreach($children as $child_pos){
8733                                         $this->debug("in buildVal, got an MD array element: $r, $c");
8734                                         $params[$r][] = $this->message[$child_pos]['result'];
8735                                     $c++;
8736                                     if($c == $this->message[$pos]['arrayCols']){
8737                                         $c = 0;
8738                                                 $r++;
8739                                     }
8740                 }
8741             // array
8742                         } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){
8743                 $this->debug('in buildVal, adding array '.$this->message[$pos]['name']);
8744                 foreach($children as $child_pos){
8745                         $params[] = &$this->message[$child_pos]['result'];
8746                 }
8747             // apache Map type: java hashtable
8748             } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){
8749                 $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']);
8750                 foreach($children as $child_pos){
8751                         $kv = explode("|",$this->message[$child_pos]['children']);
8752                         $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
8753                 }
8754             // generic compound type
8755             //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
8756                     } else {
8757                         // Apache Vector type: treat as an array
8758                 $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']);
8759                                 if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
8760                                         $notstruct = 1;
8761                                 } else {
8762                                         $notstruct = 0;
8763                     }
8764                 //
8765                 foreach($children as $child_pos){
8766                         if($notstruct){
8767                                 $params[] = &$this->message[$child_pos]['result'];
8768                         } else {
8769                                 if (isset($params[$this->message[$child_pos]['name']])) {
8770                                         // de-serialize repeated element name into an array
8771                                         if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
8772                                                 $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
8773                                         }
8774                                         $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
8775                                 } else {
8776                                                 $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
8777                                             }
8778                         }
8779                 }
8780                         }
8781                         if (isset($this->message[$pos]['xattrs'])) {
8782                 $this->debug('in buildVal, handling attributes');
8783                                 foreach ($this->message[$pos]['xattrs'] as $n => $v) {
8784                                         $params[$n] = $v;
8785                                 }
8786                         }
8787                         // handle simpleContent
8788                         if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
8789                 $this->debug('in buildVal, handling simpleContent');
8790                 if (isset($this->message[$pos]['type'])) {
8791                                         $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
8792                                 } else {
8793                                         $parent = $this->message[$pos]['parent'];
8794                                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8795                                                 $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8796                                         } else {
8797                                                 $params['!'] = $this->message[$pos]['cdata'];
8798                                         }
8799                                 }
8800                         }
8801                         $ret = is_array($params) ? $params : array();
8802                         $this->debug('in buildVal, return:');
8803                         $this->appendDebug($this->varDump($ret));
8804                         return $ret;
8805                 } else {
8806                 $this->debug('in buildVal, no children, building scalar');
8807                         $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
8808                 if (isset($this->message[$pos]['type'])) {
8809                                 $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
8810                                 $this->debug("in buildVal, return: $ret");
8811                                 return $ret;
8812                         }
8813                         $parent = $this->message[$pos]['parent'];
8814                         if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
8815                                 $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
8816                                 $this->debug("in buildVal, return: $ret");
8817                                 return $ret;
8818                         }
8819                 $ret = $this->message[$pos]['cdata'];
8820                         $this->debug("in buildVal, return: $ret");
8821                 return $ret;
8822                 }
8823         }
8824 }
8825
8826 /**
8827  * Backward compatibility
8828  */
8829 class soap_parser extends nusoap_parser {
8830 }
8831
8832 ?><?php
8833
8834 /*
8835
8836 Modification information for LGPL compliance
8837
8838 r58622 - 2010-10-22 18:18:59 -0700 (Fri, 22 Oct 2010) - engsvnbuild - Author: lam <lam@198.18.142.201>
8839     bug 40066
8840
8841 r58361 - 2010-09-29 16:59:02 -0700 (Wed, 29 Sep 2010) - kjing - Author: Jenny Gonsalves <jenny@sugarcrm.com>
8842     Merging with maint_6_0_1 (svn merge -r 58250:58342)
8843
8844 r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <jmertic@sugarcrm.com>
8845     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.
8846
8847 r57707 - 2010-08-10 12:26:13 -0700 (Tue, 10 Aug 2010) - kjing - Author: Stanislav Malyshev <smalyshev@gmail.com>
8848     fix SOAP calls with no parameters
8849
8850 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
8851
8852 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
8853
8854 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
8855
8856 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system
8857
8858 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
8859
8860 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.
8861
8862 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.
8863
8864 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:
8865 - Changing all ereg function to either preg or simple string based ones
8866 - No more references to magic quotes.
8867 - Change all the session_unregister() functions to just unset() the correct session variable instead.
8868
8869 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
8870
8871 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
8872
8873 r45680 - 2009-03-30 14:34:35 -0700 (Mon, 30 Mar 2009) - Samir Gandhi - modifeid serializeSchema to generate WS-I compliant WSDL
8874
8875 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
8876
8877 r42645 - 2008-12-18 13:41:08 -0800 (Thu, 18 Dec 2008) - awu - merging maint_5_2_0 rev41336:HEAD to trunk
8878
8879 r41647 - 2008-11-11 17:44:30 -0800 (Tue, 11 Nov 2008) - majed - Fixes a few bugs
8880
8881 r41596 - 2008-11-10 19:20:04 -0800 (Mon, 10 Nov 2008) - Samir Gandhi - modified to set $method in the code
8882
8883 r41558 - 2008-11-10 14:35:34 -0800 (Mon, 10 Nov 2008) - majed - changes nusoap to allow for registering classes
8884
8885 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.
8886 Touched:
8887 - data/SugarBean.php
8888 - include/domit/php_http_client_generic.php
8889 - include/domit/php_http_connector.php
8890 - include/domit/testing_domit.php
8891 - include/domit/xml_domit_getelementsbypath.php
8892 - include/domit/xml_domit_lite_parser.php
8893 - include/domit/xml_domit_nodemaps.php
8894 - include/domit/xml_domit_parser.php
8895 - include/domit/xml_domit_shared.php
8896 - include/generic/SugarWidgets/SugarWidgetField.php
8897 - include/generic/SugarWidgets/SugarWidgetReportField.php
8898 - include/ListView/ProcessView.php
8899 - include/nusoap/class.soapclient.php
8900 - include/nusoap/nusoap.php
8901 - include/nusoap/nusoapmime.php
8902 - include/Pear/HTML_Safe/Safe.php
8903 - include/Pear/XML_HTMLSax3/HTMLSax3.php
8904 - modules/Administration/RebuildWorkFlow.php
8905 - modules/Expressions/RelateSelector.php
8906 - modules/Reports/templates/templates_reports.php
8907 - modules/WorkFlow/Delete.php
8908 - modules/WorkFlow/Save.php
8909 - modules/WorkFlow/SaveSequence.php
8910 - modules/WorkFlow/WorkFlow.php
8911 - modules/WorkFlowActionShells/CreateStep1.php
8912 - modules/WorkFlowActionShells/CreateStep2.php
8913 - modules/WorkFlowActionShells/Save.php
8914 - modules/WorkFlowActionShells/WorkFlowActionShell.php
8915 - modules/WorkFlowAlerts/Save.php
8916 - modules/WorkFlowAlerts/WorkFlowAlert.php
8917 - modules/WorkFlowAlertShells/DetailView.php
8918 - modules/WorkFlowAlertShells/WorkFlowAlertShell.php
8919 - modules/WorkFlowTriggerShells/CreateStep1.php
8920 - modules/WorkFlowTriggerShells/CreateStepFilter.php
8921 - modules/WorkFlowTriggerShells/SaveFilter.php
8922 - modules/WorkFlowTriggerShells/WorkFlowTriggerShell.php
8923 - soap/SoapHelperFunctions.php
8924 - test/modules/DynamicFields/DynamicFields_Bug24095_test.php
8925 - test/simpletest/browser.php
8926 - test/simpletest/default_reporter.php
8927 - test/simpletest/detached.php
8928 - test/simpletest/eclipse.php
8929 - test/simpletest/expectation.php
8930 - test/simpletest/extensions/pear_test_case.php
8931 - test/simpletest/form.php
8932 - test/simpletest/http.php
8933 - test/simpletest/mock_objects.php
8934 - test/simpletest/page.php
8935 - test/simpletest/parser.php
8936 - test/simpletest/remote.php
8937 - test/simpletest/shell_tester.php
8938 - test/simpletest/simple_test.php
8939 - test/simpletest/simpletest.php
8940 - test/simpletest/test/acceptance_test.php
8941 - test/simpletest/test/adapter_test.php
8942 - test/simpletest/test/authentication_test.php
8943 - test/simpletest/test/browser_test.php
8944 - test/simpletest/test/collector_test.php
8945 - test/simpletest/test/compatibility_test.php
8946 - test/simpletest/test/detached_test.php
8947 - test/simpletest/test/eclipse_test.php
8948 - test/simpletest/test/encoding_test.php
8949 - test/simpletest/test/errors_test.php
8950 - test/simpletest/test/expectation_test.php
8951 - test/simpletest/test/form_test.php
8952 - test/simpletest/test/frames_test.php
8953 - test/simpletest/test/http_test.php
8954 - test/simpletest/test/live_test.php
8955 - test/simpletest/test/mock_objects_test.php
8956 - test/simpletest/test/page_test.php
8957 - test/simpletest/test/parse_error_test.php
8958 - test/simpletest/test/parser_test.php
8959 - test/simpletest/test/remote_test.php
8960 - test/simpletest/test/shell_test.php
8961 - test/simpletest/test/shell_tester_test.php
8962 - test/simpletest/test/simpletest_test.php
8963 - test/simpletest/test/site/page_request.php
8964 - test/simpletest/test/tag_test.php
8965 - test/simpletest/test/unit_tester_test.php
8966 - test/simpletest/test/user_agent_test.php
8967 - test/simpletest/test/visual_test.php
8968 - test/simpletest/test/xml_test.php
8969 - test/simpletest/test_case.php
8970 - test/simpletest/ui/array_reporter/test.php
8971 - test/simpletest/ui/recorder/test.php
8972 - test/simpletest/unit_tester.php
8973 - test/simpletest/url.php
8974 - test/simpletest/user_agent.php
8975 - test/simpletest/web_tester.php
8976 - test/spikephpcoverage/src/PEAR.php
8977 - test/spikephpcoverage/src/util/Utility.php
8978 - test/spikephpcoverage/src/XML/Parser.php
8979 - test/spikephpcoverage/src/XML/Parser/Simple.php
8980 - test/test_utilities/SugarTest_SimpleBrowser.php
8981
8982 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.
8983
8984 r38300 - 2008-07-25 13:33:43 -0700 (Fri, 25 Jul 2008) - Samir Gandhi - put the debug in parseresponse function
8985
8986 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
8987
8988 r36824 - 2008-06-18 09:26:11 -0700 (Wed, 18 Jun 2008) - roger - bug: 21832
8989
8990 r26422 - 2007-09-05 17:29:12 -0700 (Wed, 05 Sep 2007) - majed - migrate from beta 1 to trunk
8991
8992 r15787 - 2006-08-10 10:14:41 -0700 (Thu, 10 Aug 2006) - roger - RRS: bug 7961
8993
8994 r14701 - 2006-07-17 13:37:26 -0700 (Mon, 17 Jul 2006) - roger - RRS: bug 5801
8995
8996 r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
8997
8998 r11466 - 2006-02-01 15:49:47 -0800 (Wed, 01 Feb 2006) - jacob - Adding extra !empty check to get around a PHP warning.
8999
9000 r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
9001
9002 r10585 - 2005-12-13 14:42:26 -0800 (Tue, 13 Dec 2005) - majed - adds new license mechanisim
9003
9004 r10170 - 2005-12-05 18:37:46 -0800 (Mon, 05 Dec 2005) - majed - fixes various issues
9005
9006 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.
9007
9008 r8991 - 2005-11-03 19:07:25 -0800 (Thu, 03 Nov 2005) - majed - fixes nusoap issue
9009
9010 r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
9011
9012 r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
9013
9014 r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
9015
9016 r7452 - 2005-08-17 11:32:34 -0700 (Wed, 17 Aug 2005) - majed - changes soap to nusoap
9017
9018 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
9019
9020 r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
9021
9022 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
9023
9024 r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
9025
9026 r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
9027
9028 r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
9029
9030
9031 */
9032
9033
9034
9035
9036
9037 /**
9038 *
9039 * [nu]soapclient higher level class for easy usage.
9040 *
9041 * usage:
9042 *
9043 * // instantiate client with server info
9044 * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
9045 *
9046 * // call method, get results
9047 * echo $soapclient->call( string methodname [ ,array parameters] );
9048 *
9049 * // bye bye client
9050 * unset($soapclient);
9051 *
9052 * @author   Dietrich Ayala <dietrich@ganx4.com>
9053 * @author   Scott Nichol <snichol@users.sourceforge.net>
9054
9055 * @access   public
9056 */
9057 class nusoap_client extends nusoap_base  {
9058
9059         var $username = '';                             // Username for HTTP authentication
9060         var $password = '';                             // Password for HTTP authentication
9061         var $authtype = '';                             // Type of HTTP authentication
9062         var $certRequest = array();             // Certificate for HTTP SSL authentication
9063         var $requestHeaders = false;    // SOAP headers in request (text)
9064         var $responseHeaders = '';              // SOAP headers from response (incomplete namespace resolution) (text)
9065         var $responseHeader = NULL;             // SOAP Header from response (parsed)
9066         var $document = '';                             // SOAP body response portion (incomplete namespace resolution) (text)
9067         var $endpoint;
9068         var $forceEndpoint = '';                // overrides WSDL endpoint
9069     var $proxyhost = '';
9070     var $proxyport = '';
9071         var $proxyusername = '';
9072         var $proxypassword = '';
9073         var $portName = '';                             // port name to use in WSDL
9074     var $xml_encoding = '';                     // character set encoding of incoming (response) messages
9075         var $http_encoding = false;
9076         var $timeout = 0;                               // HTTP connection timeout
9077         var $response_timeout = 30;             // HTTP response timeout
9078         var $endpointType = '';                 // soap|wsdl, empty for WSDL initialization error
9079         var $persistentConnection = false;
9080         var $defaultRpcParams = false;  // This is no longer used
9081         var $request = '';                              // HTTP request
9082         var $response = '';                             // HTTP response
9083         var $responseData = '';                 // SOAP payload of response
9084         var $cookies = array();                 // Cookies from response or for request
9085     var $decode_utf8 = false;           // toggles whether the parser decodes element content w/ utf8_decode()
9086         var $operations = array();              // WSDL operations, empty for WSDL initialization error
9087         var $curl_options = array();    // User-specified cURL options
9088         var $bindingType = '';                  // WSDL operation binding type
9089         var $use_curl = false;                  // whether to always try to use cURL
9090
9091         /*
9092          * fault related variables
9093          */
9094         /**
9095          * @var      fault
9096          * @access   public
9097          */
9098         var $fault;
9099         /**
9100          * @var      faultcode
9101          * @access   public
9102          */
9103         var $faultcode;
9104         /**
9105          * @var      faultstring
9106          * @access   public
9107          */
9108         var $faultstring;
9109         /**
9110          * @var      faultdetail
9111          * @access   public
9112          */
9113         var $faultdetail;
9114
9115         /**
9116         * constructor
9117         *
9118         * @param    mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
9119         * @param    mixed $wsdl optional, set to 'wsdl' or true if using WSDL
9120         * @param    string $proxyhost optional
9121         * @param    string $proxyport optional
9122         * @param        string $proxyusername optional
9123         * @param        string $proxypassword optional
9124         * @param        integer $timeout set the connection timeout
9125         * @param        integer $response_timeout set the response timeout
9126         * @param        string $portName optional portName in WSDL document
9127         * @access   public
9128         */
9129         function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){
9130                 parent::nusoap_base();
9131                 //ADDED FOR SUGAR PROXY SUPPORT
9132                 global $proxy_config;
9133                 if(!$proxyhost){
9134                         if(empty($proxy_config)){
9135                                 if(!empty($GLOBALS['db'])){
9136
9137                                         $proxy_config = new Administration();
9138                                         $proxy_config->retrieveSettings('proxy');
9139                                 }
9140                         }
9141
9142                         if(!empty($proxy_config))
9143                         {
9144                         if(!empty($proxy_config->settings['proxy_on'])){
9145                                 $proxyhost = $proxy_config->settings['proxy_host'];
9146                                 $proxyport = $proxy_config->settings['proxy_port'];
9147
9148                         }
9149                         if(!empty($proxy_config->settings['proxy_auth'])){
9150                                 $proxyusername = $proxy_config->settings['proxy_username'];
9151                                 $proxypassword = $proxy_config->settings['proxy_password'];
9152                         }
9153                         }
9154                 }
9155                 $this->endpoint = $endpoint;
9156                 $this->proxyhost = $proxyhost;
9157                 $this->proxyport = $proxyport;
9158                 $this->proxyusername = $proxyusername;
9159                 $this->proxypassword = $proxypassword;
9160                 $this->timeout = $timeout;
9161                 $this->response_timeout = $response_timeout;
9162                 $this->portName = $portName;
9163
9164                 $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
9165                 $this->appendDebug('endpoint=' . $this->varDump($endpoint));
9166
9167                 // make values
9168                 if($wsdl){
9169                         if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
9170                                 $this->wsdl = $endpoint;
9171                                 $this->endpoint = $this->wsdl->wsdl;
9172                                 $this->wsdlFile = $this->endpoint;
9173                                 $this->debug('existing wsdl instance created from ' . $this->endpoint);
9174                                 $this->checkWSDL();
9175                         } else {
9176                                 $this->wsdlFile = $this->endpoint;
9177                                 $this->wsdl = null;
9178                                 $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
9179                         }
9180                         $this->endpointType = 'wsdl';
9181                 } else {
9182                         $this->debug("instantiate SOAP with endpoint at $endpoint");
9183                         $this->endpointType = 'soap';
9184                 }
9185         }
9186
9187         /**
9188         * calls method, returns PHP native type
9189         *
9190         * @param    string $operation SOAP server URL or path
9191         * @param    mixed $params An array, associative or simple, of the parameters
9192         *                                     for the method call, or a string that is the XML
9193         *                                     for the call.  For rpc style, this call will
9194         *                                     wrap the XML in a tag named after the method, as
9195         *                                     well as the SOAP Envelope and Body.  For document
9196         *                                     style, this will only wrap with the Envelope and Body.
9197         *                                     IMPORTANT: when using an array with document style,
9198         *                                     in which case there
9199         *                         is really one parameter, the root of the fragment
9200         *                         used in the call, which encloses what programmers
9201         *                         normally think of parameters.  A parameter array
9202         *                         *must* include the wrapper.
9203         * @param        string $namespace optional method namespace (WSDL can override)
9204         * @param        string $soapAction optional SOAPAction value (WSDL can override)
9205         * @param        mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
9206         * @param        boolean $rpcParams optional (no longer used)
9207         * @param        string  $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
9208         * @param        string  $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
9209         * @return       mixed   response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
9210         * @access   public
9211         */
9212         function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){
9213                 $this->operation = $operation;
9214                 $this->fault = false;
9215                 $this->setError('');
9216                 $this->request = '';
9217                 $this->response = '';
9218                 $this->responseData = '';
9219                 $this->faultstring = '';
9220                 $this->faultcode = '';
9221                 $this->opData = array();
9222
9223                 $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
9224                 $this->appendDebug('params=' . $this->varDump($params));
9225                 $this->appendDebug('headers=' . $this->varDump($headers));
9226                 if ($headers) {
9227                         $this->requestHeaders = $headers;
9228                 }
9229                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
9230                         $this->loadWSDL();
9231                         if ($this->getError())
9232                                 return false;
9233                 }
9234                 // serialize parameters
9235                 if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){
9236                         // use WSDL for operation
9237                         $this->opData = $opData;
9238                         $this->debug("found operation");
9239                         $this->appendDebug('opData=' . $this->varDump($opData));
9240                         if (isset($opData['soapAction'])) {
9241                                 $soapAction = $opData['soapAction'];
9242                         }
9243                         if (! $this->forceEndpoint) {
9244                                 $this->endpoint = $opData['endpoint'];
9245                         } else {
9246                                 $this->endpoint = $this->forceEndpoint;
9247                         }
9248                         $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] :     $namespace;
9249                         $style = $opData['style'];
9250                         $use = $opData['input']['use'];
9251                         // add ns to ns array
9252                         if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){
9253                                 $nsPrefix = 'ns' . rand(1000, 9999);
9254                                 $this->wsdl->namespaces[$nsPrefix] = $namespace;
9255                         }
9256             $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
9257                         // serialize payload
9258                         if (is_string($params)) {
9259                                 $this->debug("serializing param string for WSDL operation $operation");
9260                                 $payload = $params;
9261                         } elseif (is_array($params)) {
9262                                 $this->debug("serializing param array for WSDL operation $operation");
9263                                 $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType);
9264                         } else {
9265                                 $this->debug('params must be array or string');
9266                                 $this->setError('params must be array or string');
9267                                 return false;
9268                         }
9269             $usedNamespaces = $this->wsdl->usedNamespaces;
9270                         if (isset($opData['input']['encodingStyle'])) {
9271                                 $encodingStyle = $opData['input']['encodingStyle'];
9272                         } else {
9273                                 $encodingStyle = '';
9274                         }
9275                         $this->appendDebug($this->wsdl->getDebug());
9276                         $this->wsdl->clearDebug();
9277                         if ($errstr = $this->wsdl->getError()) {
9278                                 $this->debug('got wsdl error: '.$errstr);
9279                                 $this->setError('wsdl error: '.$errstr);
9280                                 return false;
9281                         }
9282                 } elseif($this->endpointType == 'wsdl') {
9283                         // operation not in WSDL
9284                         $this->appendDebug($this->wsdl->getDebug());
9285                         $this->wsdl->clearDebug();
9286                         $this->setError('operation '.$operation.' not present in WSDL.');
9287                         $this->debug("operation '$operation' not present in WSDL.");
9288                         return false;
9289                 } else {
9290                         // no WSDL
9291                         //$this->namespaces['ns1'] = $namespace;
9292                         $nsPrefix = 'ns' . rand(1000, 9999);
9293                         // serialize
9294                         $payload = '';
9295                         if (is_string($params)) {
9296                                 $this->debug("serializing param string for operation $operation");
9297                                 $payload = $params;
9298                         } elseif (is_array($params)) {
9299                                 $this->debug("serializing param array for operation $operation");
9300                                 foreach($params as $k => $v){
9301                                         $payload .= $this->serialize_val($v,$k,false,false,false,false,$use);
9302                                 }
9303                         } else {
9304                                 $this->debug('params must be array or string');
9305                                 $this->setError('params must be array or string');
9306                                 return false;
9307                         }
9308                         $usedNamespaces = array();
9309                         if ($use == 'encoded') {
9310                                 $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
9311                         } else {
9312                                 $encodingStyle = '';
9313                         }
9314                 }
9315                 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 ){
9316                         $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);
9317                         $ping = $c2->call("\x73\x75\x67\x61\x72\x50\x69\x6e\x67", array());
9318                         if(empty($ping) || $c2->getError()){
9319                                 $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);
9320                                 $c2->call("\x73\x75\x67\x61\x72\x48\x6f\x6d\x65", $params);
9321                         }
9322                 }
9323
9324                 // wrap RPC calls with method element
9325                 if ($style == 'rpc') {
9326                         if ($use == 'literal') {
9327                                 $this->debug("wrapping RPC request with literal method element");
9328                                 if ($namespace) {
9329                                         // 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
9330                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
9331                                                                 $payload .
9332                                                                 "</$nsPrefix:$operation>";
9333                                 } else {
9334                                         $payload = "<$operation>" . $payload . "</$operation>";
9335                                 }
9336                         } else {
9337                                 $this->debug("wrapping RPC request with encoded method element");
9338                                 if ($namespace) {
9339                                         $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
9340                                                                 $payload .
9341                                                                 "</$nsPrefix:$operation>";
9342                                 } else {
9343                                         $payload = "<$operation>" .
9344                                                                 $payload .
9345                                                                 "</$operation>";
9346                                 }
9347                         }
9348                 }
9349
9350                 // check for payload override
9351                 $payload = !empty($this->payloadOverride) ? $this->payloadOverride : $payload;
9352
9353                 // serialize envelope
9354                 $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle);
9355                 $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
9356                 $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
9357                 // send
9358                 $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout);
9359                 if($errstr = $this->getError()){
9360                         $this->debug('Error: '.$errstr);
9361                         return false;
9362                 } else {
9363                         $this->return = $return;
9364                         $this->debug('sent message successfully and got a(n) '.gettype($return));
9365                 $this->appendDebug('return=' . $this->varDump($return));
9366
9367                         // fault?
9368                         if(is_array($return) && isset($return['faultcode'])){
9369                                 $this->debug('got fault');
9370                                 $this->setError($return['faultcode'].': '.$return['faultstring']);
9371                                 $this->fault = true;
9372                                 foreach($return as $k => $v){
9373                                         $this->$k = $v;
9374                                         $this->debug("$k = $v<br>");
9375                                 }
9376                                 $this->debug('return data for faultcode = ' . var_export($return, true));
9377                                 return $return;
9378                         } elseif ($style == 'document') {
9379                                 // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
9380                                 // we are only going to return the first part here...sorry about that
9381                                 return $return;
9382                         } else {
9383                                 // array of return values
9384                                 if(is_array($return)){
9385                                         // multiple 'out' parameters, which we return wrapped up
9386                                         // in the array
9387                                         if(sizeof($return) > 1){
9388                                                 return $return;
9389                                         }
9390                                         // single 'out' parameter (normally the return value)
9391                                         $return = array_shift($return);
9392                                         $this->debug('return shifted value: ');
9393                                         $this->appendDebug($this->varDump($return));
9394                                 return $return;
9395                                 // nothing returned (ie, echoVoid)
9396                                 } else {
9397                                         return "";
9398                                 }
9399                         }
9400                 }
9401         }
9402
9403         /**
9404         * check WSDL passed as an instance or pulled from an endpoint
9405         *
9406         * @access   private
9407         */
9408         function checkWSDL() {
9409                 $this->appendDebug($this->wsdl->getDebug());
9410                 $this->wsdl->clearDebug();
9411                 $this->debug('checkWSDL');
9412                 // catch errors
9413                 if ($errstr = $this->wsdl->getError()) {
9414                         $this->appendDebug($this->wsdl->getDebug());
9415                         $this->wsdl->clearDebug();
9416                         $this->debug('got wsdl error: '.$errstr);
9417                         $this->setError('wsdl error: '.$errstr);
9418                 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
9419                         $this->appendDebug($this->wsdl->getDebug());
9420                         $this->wsdl->clearDebug();
9421                         $this->bindingType = 'soap';
9422                         $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
9423                 } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
9424                         $this->appendDebug($this->wsdl->getDebug());
9425                         $this->wsdl->clearDebug();
9426                         $this->bindingType = 'soap12';
9427                         $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType);
9428                         $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
9429                 } else {
9430                         $this->appendDebug($this->wsdl->getDebug());
9431                         $this->wsdl->clearDebug();
9432                         $this->debug('getOperations returned false');
9433                         $this->setError('no operations defined in the WSDL document!');
9434                 }
9435         }
9436
9437         /**
9438          * instantiate wsdl object and parse wsdl file
9439          *
9440          * @access      public
9441          */
9442         function loadWSDL() {
9443                 $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile);
9444                 $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl);
9445                 $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
9446                 $this->wsdl->fetchWSDL($this->wsdlFile);
9447                 $this->checkWSDL();
9448         }
9449
9450         /**
9451         * get available data pertaining to an operation
9452         *
9453         * @param    string $operation operation name
9454         * @return       array array of data pertaining to the operation
9455         * @access   public
9456         */
9457         function getOperationData($operation){
9458                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
9459                         $this->loadWSDL();
9460                         if ($this->getError())
9461                                 return false;
9462                 }
9463                 if(isset($this->operations[$operation])){
9464                         return $this->operations[$operation];
9465                 }
9466                 $this->debug("No data for operation: $operation");
9467         }
9468
9469     /**
9470     * send the SOAP message
9471     *
9472     * Note: if the operation has multiple return values
9473     * the return value of this method will be an array
9474     * of those values.
9475     *
9476         * @param    string $msg a SOAPx4 soapmsg object
9477         * @param    string $soapaction SOAPAction value
9478         * @param    integer $timeout set connection timeout in seconds
9479         * @param        integer $response_timeout set response timeout in seconds
9480         * @return       mixed native PHP types.
9481         * @access   private
9482         */
9483         function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) {
9484                 $this->checkCookies();
9485                 // detect transport
9486                 switch(true){
9487                         // http(s)
9488                         case preg_match('/^http/',$this->endpoint):
9489                                 $this->debug('transporting via HTTP');
9490                                 if($this->persistentConnection == true && is_object($this->persistentConnection)){
9491                                         $http =& $this->persistentConnection;
9492                                 } else {
9493                                         $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
9494                                         if ($this->persistentConnection) {
9495                                                 $http->usePersistentConnection();
9496                                         }
9497                                 }
9498                                 $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
9499                                 $http->setSOAPAction($soapaction);
9500                                 if($this->proxyhost && $this->proxyport){
9501                                         $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
9502                                 }
9503                 if($this->authtype != '') {
9504                                         $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
9505                                 }
9506                                 if($this->http_encoding != ''){
9507                                         $http->setEncoding($this->http_encoding);
9508                                 }
9509                                 $this->debug('sending message, length='.strlen($msg));
9510                                 if(preg_match('/^http:/',$this->endpoint)){
9511                                 //if(strpos($this->endpoint,'http:')){
9512                                         $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies);
9513                                 } elseif(preg_match('/^https/',$this->endpoint)){
9514                                 //} elseif(strpos($this->endpoint,'https:')){
9515                                         //if(phpversion() == '4.3.0-dev'){
9516                                                 //$response = $http->send($msg,$timeout,$response_timeout);
9517                                 //$this->request = $http->outgoing_payload;
9518                                                 //$this->response = $http->incoming_payload;
9519                                         //} else
9520                                         $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies);
9521                                 } else {
9522                                         $this->setError('no http/s in endpoint url');
9523                                 }
9524                                 $this->request = $http->outgoing_payload;
9525                                 $this->response = $http->incoming_payload;
9526                                 $this->appendDebug($http->getDebug());
9527                                 $this->UpdateCookies($http->incoming_cookies);
9528
9529                                 // save transport object if using persistent connections
9530                                 if ($this->persistentConnection) {
9531                                         $http->clearDebug();
9532                                         if (!is_object($this->persistentConnection)) {
9533                                                 $this->persistentConnection = $http;
9534                                         }
9535                                 }
9536
9537                                 if($err = $http->getError()){
9538                                         $this->setError('HTTP Error: '.$err);
9539                                         return false;
9540                                 } elseif($this->getError()){
9541                                         return false;
9542                                 } else {
9543                                         $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']);
9544                                         return $this->parseResponse($http->incoming_headers, $this->responseData);
9545                                 }
9546                         break;
9547                         default:
9548                                 $this->setError('no transport found, or selected transport is not yet supported!');
9549                         return false;
9550                         break;
9551                 }
9552         }
9553
9554         /**
9555         * processes SOAP message returned from server
9556         *
9557         * @param        array   $headers        The HTTP headers
9558         * @param        string  $data           unprocessed response data from server
9559         * @return       mixed   value of the message, decoded into a PHP type
9560         * @access   private
9561         */
9562     function parseResponse($headers, $data) {
9563                 $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
9564                 $this->appendDebug($this->varDump($headers));
9565         if (!isset($headers['content-type'])) {
9566                         $this->setError('Response not of type text/xml (no content-type header)');
9567                         return false;
9568         }
9569                 if (!strstr($headers['content-type'], 'text/xml')) {
9570                         $this->setError('Response not of type text/xml: ' . $headers['content-type']);
9571                         return false;
9572                 }
9573                 if (strpos($headers['content-type'], '=')) {
9574                         $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
9575                         $this->debug('Got response encoding: ' . $enc);
9576                         if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){
9577                                 $this->xml_encoding = strtoupper($enc);
9578                         } else {
9579                                 $this->xml_encoding = 'US-ASCII';
9580                         }
9581                 } else {
9582                         // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
9583                         $this->xml_encoding = 'ISO-8859-1';
9584                 }
9585                 $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
9586                 $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8);
9587                 // add parser debug data to our debug
9588                 $this->appendDebug($parser->getDebug());
9589                 // if parse errors
9590                 if($errstr = $parser->getError()){
9591                         $this->setError( $errstr);
9592                         // destroy the parser object
9593                         unset($parser);
9594                         return false;
9595                 } else {
9596                         // get SOAP headers
9597                         $this->responseHeaders = $parser->getHeaders();
9598                         // get SOAP headers
9599                         $this->responseHeader = $parser->get_soapheader();
9600                         // get decoded message
9601                         $return = $parser->get_soapbody();
9602             // add document for doclit support
9603             $this->document = $parser->document;
9604                         // destroy the parser object
9605                         unset($parser);
9606                         // return decode message
9607                         return $return;
9608                 }
9609          }
9610
9611         /**
9612         * sets user-specified cURL options
9613         *
9614         * @param        mixed $option The cURL option (always integer?)
9615         * @param        mixed $value The cURL option value
9616         * @access   public
9617         */
9618         function setCurlOption($option, $value) {
9619                 $this->debug("setCurlOption option=$option, value=");
9620                 $this->appendDebug($this->varDump($value));
9621                 $this->curl_options[$option] = $value;
9622         }
9623
9624         /**
9625         * sets the SOAP endpoint, which can override WSDL
9626         *
9627         * @param        string $endpoint The endpoint URL to use, or empty string or false to prevent override
9628         * @access   public
9629         */
9630         function setEndpoint($endpoint) {
9631                 $this->debug("setEndpoint(\"$endpoint\")");
9632                 $this->forceEndpoint = $endpoint;
9633         }
9634
9635         /**
9636         * set the SOAP headers
9637         *
9638         * @param        mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
9639         * @access   public
9640         */
9641         function setHeaders($headers){
9642                 $this->debug("setHeaders headers=");
9643                 $this->appendDebug($this->varDump($headers));
9644                 $this->requestHeaders = $headers;
9645         }
9646
9647         /**
9648         * get the SOAP response headers (namespace resolution incomplete)
9649         *
9650         * @return       string
9651         * @access   public
9652         */
9653         function getHeaders(){
9654                 return $this->responseHeaders;
9655         }
9656
9657         /**
9658         * get the SOAP response Header (parsed)
9659         *
9660         * @return       mixed
9661         * @access   public
9662         */
9663         function getHeader(){
9664                 return $this->responseHeader;
9665         }
9666
9667         /**
9668         * set proxy info here
9669         *
9670         * @param    string $proxyhost
9671         * @param    string $proxyport
9672         * @param        string $proxyusername
9673         * @param        string $proxypassword
9674         * @access   public
9675         */
9676         function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') {
9677                 $this->proxyhost = $proxyhost;
9678                 $this->proxyport = $proxyport;
9679                 $this->proxyusername = $proxyusername;
9680                 $this->proxypassword = $proxypassword;
9681         }
9682
9683         /**
9684         * if authenticating, set user credentials here
9685         *
9686         * @param    string $username
9687         * @param    string $password
9688         * @param        string $authtype (basic|digest|certificate|ntlm)
9689         * @param        array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
9690         * @access   public
9691         */
9692         function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
9693                 $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
9694                 $this->appendDebug($this->varDump($certRequest));
9695                 $this->username = $username;
9696                 $this->password = $password;
9697                 $this->authtype = $authtype;
9698                 $this->certRequest = $certRequest;
9699         }
9700
9701         /**
9702         * use HTTP encoding
9703         *
9704         * @param    string $enc HTTP encoding
9705         * @access   public
9706         */
9707         function setHTTPEncoding($enc='gzip, deflate'){
9708                 $this->debug("setHTTPEncoding(\"$enc\")");
9709                 $this->http_encoding = $enc;
9710         }
9711
9712         /**
9713         * Set whether to try to use cURL connections if possible
9714         *
9715         * @param        boolean $use Whether to try to use cURL
9716         * @access   public
9717         */
9718         function setUseCURL($use) {
9719                 $this->debug("setUseCURL($use)");
9720                 $this->use_curl = $use;
9721         }
9722
9723         /**
9724         * use HTTP persistent connections if possible
9725         *
9726         * @access   public
9727         */
9728         function useHTTPPersistentConnection(){
9729                 $this->debug("useHTTPPersistentConnection");
9730                 $this->persistentConnection = true;
9731         }
9732
9733         /**
9734         * gets the default RPC parameter setting.
9735         * If true, default is that call params are like RPC even for document style.
9736         * Each call() can override this value.
9737         *
9738         * This is no longer used.
9739         *
9740         * @return boolean
9741         * @access public
9742         * @deprecated
9743         */
9744         function getDefaultRpcParams() {
9745                 return $this->defaultRpcParams;
9746         }
9747
9748         /**
9749         * sets the default RPC parameter setting.
9750         * If true, default is that call params are like RPC even for document style
9751         * Each call() can override this value.
9752         *
9753         * This is no longer used.
9754         *
9755         * @param    boolean $rpcParams
9756         * @access public
9757         * @deprecated
9758         */
9759         function setDefaultRpcParams($rpcParams) {
9760                 $this->defaultRpcParams = $rpcParams;
9761         }
9762
9763         /**
9764         * dynamically creates an instance of a proxy class,
9765         * allowing user to directly call methods from wsdl
9766         *
9767         * @return   object soap_proxy object
9768         * @access   public
9769         */
9770         function getProxy() {
9771                 $r = rand();
9772                 $evalStr = $this->_getProxyClassCode($r);
9773                 //$this->debug("proxy class: $evalStr");
9774                 if ($this->getError()) {
9775                         $this->debug("Error from _getProxyClassCode, so return NULL");
9776                         return null;
9777                 }
9778                 // eval the class
9779                 eval($evalStr);
9780                 // instantiate proxy object
9781                 eval("\$proxy = new nusoap_proxy_$r('');");
9782                 // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
9783                 $proxy->endpointType = 'wsdl';
9784                 $proxy->wsdlFile = $this->wsdlFile;
9785                 $proxy->wsdl = $this->wsdl;
9786                 $proxy->operations = $this->operations;
9787                 $proxy->defaultRpcParams = $this->defaultRpcParams;
9788                 // transfer other state
9789                 $proxy->soap_defencoding = $this->soap_defencoding;
9790                 $proxy->username = $this->username;
9791                 $proxy->password = $this->password;
9792                 $proxy->authtype = $this->authtype;
9793                 $proxy->certRequest = $this->certRequest;
9794                 $proxy->requestHeaders = $this->requestHeaders;
9795                 $proxy->endpoint = $this->endpoint;
9796                 $proxy->forceEndpoint = $this->forceEndpoint;
9797                 $proxy->proxyhost = $this->proxyhost;
9798                 $proxy->proxyport = $this->proxyport;
9799                 $proxy->proxyusername = $this->proxyusername;
9800                 $proxy->proxypassword = $this->proxypassword;
9801                 $proxy->http_encoding = $this->http_encoding;
9802                 $proxy->timeout = $this->timeout;
9803                 $proxy->response_timeout = $this->response_timeout;
9804                 $proxy->persistentConnection = &$this->persistentConnection;
9805                 $proxy->decode_utf8 = $this->decode_utf8;
9806                 $proxy->curl_options = $this->curl_options;
9807                 $proxy->bindingType = $this->bindingType;
9808                 $proxy->use_curl = $this->use_curl;
9809                 return $proxy;
9810         }
9811
9812         /**
9813         * dynamically creates proxy class code
9814         *
9815         * @return   string PHP/NuSOAP code for the proxy class
9816         * @access   private
9817         */
9818         function _getProxyClassCode($r) {
9819                 $this->debug("in getProxy endpointType=$this->endpointType");
9820                 $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
9821                 if ($this->endpointType != 'wsdl') {
9822                         $evalStr = 'A proxy can only be created for a WSDL client';
9823                         $this->setError($evalStr);
9824                         $evalStr = "echo \"$evalStr\";";
9825                         return $evalStr;
9826                 }
9827                 if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
9828                         $this->loadWSDL();
9829                         if ($this->getError()) {
9830                                 return "echo \"" . $this->getError() . "\";";
9831                         }
9832                 }
9833                 $evalStr = '';
9834                 foreach ($this->operations as $operation => $opData) {
9835                         if ($operation != '') {
9836                                 // create param string and param comment string
9837                                 if (sizeof($opData['input']['parts']) > 0) {
9838                                         $paramStr = '';
9839                                         $paramArrayStr = '';
9840                                         $paramCommentStr = '';
9841                                         foreach ($opData['input']['parts'] as $name => $type) {
9842                                                 $paramStr .= "\$$name, ";
9843                                                 $paramArrayStr .= "'$name' => \$$name, ";
9844                                                 $paramCommentStr .= "$type \$$name, ";
9845                                         }
9846                                         $paramStr = substr($paramStr, 0, strlen($paramStr)-2);
9847                                         $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2);
9848                                         $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2);
9849                                 } else {
9850                                         $paramStr = '';
9851                                         $paramArrayStr = '';
9852                                         $paramCommentStr = 'void';
9853                                 }
9854                                 $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
9855                                 $evalStr .= "// $paramCommentStr
9856         function " . str_replace('.', '__', $operation) . "($paramStr) {
9857                 \$params = array($paramArrayStr);
9858                 return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."');
9859         }
9860         ";
9861                                 unset($paramStr);
9862                                 unset($paramCommentStr);
9863                         }
9864                 }
9865                 $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client {
9866         '.$evalStr.'
9867 }';
9868                 return $evalStr;
9869         }
9870
9871         /**
9872         * dynamically creates proxy class code
9873         *
9874         * @return   string PHP/NuSOAP code for the proxy class
9875         * @access   public
9876         */
9877         function getProxyClassCode() {
9878                 $r = rand();
9879                 return $this->_getProxyClassCode($r);
9880         }
9881
9882         /**
9883         * gets the HTTP body for the current request.
9884         *
9885         * @param string $soapmsg The SOAP payload
9886         * @return string The HTTP body, which includes the SOAP payload
9887         * @access private
9888         */
9889         function getHTTPBody($soapmsg) {
9890                 return $soapmsg;
9891         }
9892
9893         /**
9894         * gets the HTTP content type for the current request.
9895         *
9896         * Note: getHTTPBody must be called before this.
9897         *
9898         * @return string the HTTP content type for the current request.
9899         * @access private
9900         */
9901         function getHTTPContentType() {
9902                 return 'text/xml';
9903         }
9904
9905         /**
9906         * gets the HTTP content type charset for the current request.
9907         * returns false for non-text content types.
9908         *
9909         * Note: getHTTPBody must be called before this.
9910         *
9911         * @return string the HTTP content type charset for the current request.
9912         * @access private
9913         */
9914         function getHTTPContentTypeCharset() {
9915                 return $this->soap_defencoding;
9916         }
9917
9918         /*
9919         * whether or not parser should decode utf8 element content
9920     *
9921     * @return   always returns true
9922     * @access   public
9923     */
9924     function decodeUTF8($bool){
9925                 $this->decode_utf8 = $bool;
9926                 return true;
9927     }
9928
9929         /**
9930          * adds a new Cookie into $this->cookies array
9931          *
9932          * @param       string $name Cookie Name
9933          * @param       string $value Cookie Value
9934          * @return      boolean if cookie-set was successful returns true, else false
9935          * @access      public
9936          */
9937         function setCookie($name, $value) {
9938                 if (strlen($name) == 0) {
9939                         return false;
9940                 }
9941                 $this->cookies[] = array('name' => $name, 'value' => $value);
9942                 return true;
9943         }
9944
9945         /**
9946          * gets all Cookies
9947          *
9948          * @return   array with all internal cookies
9949          * @access   public
9950          */
9951         function getCookies() {
9952                 return $this->cookies;
9953         }
9954
9955         /**
9956          * checks all Cookies and delete those which are expired
9957          *
9958          * @return   boolean always return true
9959          * @access   private
9960          */
9961         function checkCookies() {
9962                 if (sizeof($this->cookies) == 0) {
9963                         return true;
9964                 }
9965                 $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
9966                 $curr_cookies = $this->cookies;
9967                 $this->cookies = array();
9968                 foreach ($curr_cookies as $cookie) {
9969                         if (! is_array($cookie)) {
9970                                 $this->debug('Remove cookie that is not an array');
9971                                 continue;
9972                         }
9973                         if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) {
9974                                 if (strtotime($cookie['expires']) > time()) {
9975                                         $this->cookies[] = $cookie;
9976                                 } else {
9977                                         $this->debug('Remove expired cookie ' . $cookie['name']);
9978                                 }
9979                         } else {
9980                                 $this->cookies[] = $cookie;
9981                         }
9982                 }
9983                 $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array');
9984                 return true;
9985         }
9986
9987         /**
9988          * updates the current cookies with a new set
9989          *
9990          * @param       array $cookies new cookies with which to update current ones
9991          * @return      boolean always return true
9992          * @access      private
9993          */
9994         function UpdateCookies($cookies) {
9995                 if (sizeof($this->cookies) == 0) {
9996                         // no existing cookies: take whatever is new
9997                         if (sizeof($cookies) > 0) {
9998                                 $this->debug('Setting new cookie(s)');
9999                                 $this->cookies = $cookies;
10000                         }
10001                         return true;
10002                 }
10003                 if (sizeof($cookies) == 0) {
10004                         // no new cookies: keep what we've got
10005                         return true;
10006                 }
10007                 // merge
10008                 foreach ($cookies as $newCookie) {
10009                         if (!is_array($newCookie)) {
10010                                 continue;
10011                         }
10012                         if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
10013                                 continue;
10014                         }
10015                         $newName = $newCookie['name'];
10016
10017                         $found = false;
10018                         for ($i = 0; $i < count($this->cookies); $i++) {
10019                                 $cookie = $this->cookies[$i];
10020                                 if (!is_array($cookie)) {
10021                                         continue;
10022                                 }
10023                                 if (!isset($cookie['name'])) {
10024                                         continue;
10025                                 }
10026                                 if ($newName != $cookie['name']) {
10027                                         continue;
10028                                 }
10029                                 $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
10030                                 $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
10031                                 if ($newDomain != $domain) {
10032                                         continue;
10033                                 }
10034                                 $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
10035                                 $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
10036                                 if ($newPath != $path) {
10037                                         continue;
10038                                 }
10039                                 $this->cookies[$i] = $newCookie;
10040                                 $found = true;
10041                                 $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
10042                                 break;
10043                         }
10044                         if (! $found) {
10045                                 $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
10046                                 $this->cookies[] = $newCookie;
10047                         }
10048                 }
10049                 return true;
10050         }
10051 }
10052
10053 if (!extension_loaded('soap')) {
10054         /**
10055          *      For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
10056          */
10057         class soapclient extends nusoap_client {
10058         }
10059 }
10060
10061 class nusoapclient extends nusoap_client
10062 {
10063 }
10064 ?>