Issues (4069)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

include/nusoap/class.wsdl.php (22 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
5
Modification information for LGPL compliance
6
7
r57813 - 2010-08-19 10:34:44 -0700 (Thu, 19 Aug 2010) - kjing - Author: John Mertic <[email protected]>
8
    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.
9
10
r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
11
12
r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
13
14
r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
15
16
r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3  tags and updated the build system 
17
18
r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
19
20
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:
21
- Changing all ereg function to either preg or simple string based ones
22
- No more references to magic quotes.
23
- Change all the session_unregister() functions to just unset() the correct session variable instead.
24
25
r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
26
27
r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
28
29
r13782 - 2006-06-06 10:58:55 -0700 (Tue, 06 Jun 2006) - majed - changes entry point code
30
31
r11115 - 2006-01-17 14:54:45 -0800 (Tue, 17 Jan 2006) - majed - add entry point validation
32
33
r8846 - 2005-10-31 11:01:12 -0800 (Mon, 31 Oct 2005) - majed - new version of nusoap
34
35
r7905 - 2005-09-21 19:12:57 -0700 (Wed, 21 Sep 2005) - majed - restores old nusoap pre & with a few fixes
36
37
r7861 - 2005-09-20 15:40:25 -0700 (Tue, 20 Sep 2005) - majed - & fix for 3.5.1
38
39
r5462 - 2005-05-25 13:50:11 -0700 (Wed, 25 May 2005) - majed - upgraded nusoap to .6.9
40
41
r573 - 2004-09-04 13:03:32 -0700 (Sat, 04 Sep 2004) - sugarclint - undoing copyrights added in inadvertantly.  --clint
42
43
r546 - 2004-09-03 11:49:38 -0700 (Fri, 03 Sep 2004) - sugarmsi - removed echo count
44
45
r354 - 2004-08-02 23:00:37 -0700 (Mon, 02 Aug 2004) - sugarjacob - Adding Soap
46
47
48
*/
49
50
51
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
52
53
54
55
56
/**
57
* parses a WSDL file, allows access to it's data, other utility methods.
58
* also builds WSDL structures programmatically.
59
*
60
* @author   Dietrich Ayala <[email protected]>
61
* @author   Scott Nichol <[email protected]>
62
63
* @access public
64
*/
65
class wsdl extends nusoap_base {
66
	// URL or filename of the root of this WSDL
67
    var $wsdl;
68
    // define internal arrays of bindings, ports, operations, messages, etc.
69
    var $schemas = array();
70
    var $currentSchema;
71
    var $message = array();
72
    var $complexTypes = array();
73
    var $messages = array();
74
    var $currentMessage;
75
    var $currentOperation;
76
    var $portTypes = array();
77
    var $currentPortType;
78
    var $bindings = array();
79
    var $currentBinding;
80
    var $ports = array();
81
    var $currentPort;
82
    var $opData = array();
83
    var $status = '';
84
    var $documentation = false;
85
    var $endpoint = '';
86
    // array of wsdl docs to import
87
    var $import = array();
88
    // parser vars
89
    var $parser;
90
    var $position = 0;
91
    var $depth = 0;
92
    var $depth_array = array();
93
	// for getting wsdl
94
	var $proxyhost = '';
95
    var $proxyport = '';
96
	var $proxyusername = '';
97
	var $proxypassword = '';
98
	var $timeout = 0;
99
	var $response_timeout = 30;
100
	var $curl_options = array();	// User-specified cURL options
101
	var $use_curl = false;			// whether to always try to use cURL
102
	// for HTTP authentication
103
	var $username = '';				// Username for HTTP authentication
104
	var $password = '';				// Password for HTTP authentication
105
	var $authtype = '';				// Type of HTTP authentication
106
	var $certRequest = array();		// Certificate for HTTP SSL authentication
107
108
    /**
109
     * constructor
110
     *
111
     * @param string $wsdl WSDL document URL
112
	 * @param string $proxyhost
113
	 * @param string $proxyport
114
	 * @param string $proxyusername
115
	 * @param string $proxypassword
116
	 * @param integer $timeout set the connection timeout
117
	 * @param integer $response_timeout set the response timeout
118
	 * @param array $curl_options user-specified cURL options
119
	 * @param boolean $use_curl try to use cURL
120
     * @access public
121
     */
122
    function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){
123
		parent::nusoap_base();
124
		$this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
125
        $this->proxyhost = $proxyhost;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyhost can also be of type false. However, the property $proxyhost is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
126
        $this->proxyport = $proxyport;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyport can also be of type false. However, the property $proxyport is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
127
		$this->proxyusername = $proxyusername;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyusername can also be of type false. However, the property $proxyusername is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
128
		$this->proxypassword = $proxypassword;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxypassword can also be of type false. However, the property $proxypassword is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
129
		$this->timeout = $timeout;
130
		$this->response_timeout = $response_timeout;
131
		if (is_array($curl_options))
132
			$this->curl_options = $curl_options;
133
		$this->use_curl = $use_curl;
134
		$this->fetchWSDL($wsdl);
135
    }
136
137
	/**
138
	 * fetches the WSDL document and parses it
139
	 *
140
	 * @access public
141
	 */
142
	function fetchWSDL($wsdl) {
143
		$this->debug("parse and process WSDL path=$wsdl");
144
		$this->wsdl = $wsdl;
145
        // parse wsdl file
146
        if ($this->wsdl != "") {
147
            $this->parseWSDL($this->wsdl);
148
        }
149
        // imports
150
        // TODO: handle imports more properly, grabbing them in-line and nesting them
151
    	$imported_urls = array();
152
    	$imported = 1;
153
    	while ($imported > 0) {
154
    		$imported = 0;
155
    		// Schema imports
156
    		foreach ($this->schemas as $ns => $list) {
157
    			foreach ($list as $xs) {
158
					$wsdlparts = parse_url($this->wsdl);	// this is bogusly simple!
159
		            foreach ($xs->imports as $ns2 => $list2) {
160
		                for ($ii = 0; $ii < count($list2); $ii++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
161
		                	if (! $list2[$ii]['loaded']) {
162
		                		$this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
163
		                		$url = $list2[$ii]['location'];
164
								if ($url != '') {
165
									$urlparts = parse_url($url);
166
									if (!isset($urlparts['host'])) {
167
										$url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') .
168
												substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
169
									}
170
									if (! in_array($url, $imported_urls)) {
171
					                	$this->parseWSDL($url);
172
				                		$imported++;
173
				                		$imported_urls[] = $url;
174
				                	}
175
								} else {
176
									$this->debug("Unexpected scenario: empty URL for unloaded import");
177
								}
178
							}
179
						}
180
		            }
181
    			}
182
    		}
183
    		// WSDL imports
184
			$wsdlparts = parse_url($this->wsdl);	// this is bogusly simple!
185
            foreach ($this->import as $ns => $list) {
186
                for ($ii = 0; $ii < count($list); $ii++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
187
                	if (! $list[$ii]['loaded']) {
188
                		$this->import[$ns][$ii]['loaded'] = true;
189
                		$url = $list[$ii]['location'];
190
						if ($url != '') {
191
							$urlparts = parse_url($url);
192
							if (!isset($urlparts['host'])) {
193
								$url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
194
										substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path'];
195
							}
196
							if (! in_array($url, $imported_urls)) {
197
			                	$this->parseWSDL($url);
198
		                		$imported++;
199
		                		$imported_urls[] = $url;
200
		                	}
201
						} else {
202
							$this->debug("Unexpected scenario: empty URL for unloaded import");
203
						}
204
					}
205
				}
206
            }
207
		}
208
        // add new data to operation data
209
        foreach($this->bindings as $binding => $bindingData) {
210
            if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
211
                foreach($bindingData['operations'] as $operation => $data) {
212
                    $this->debug('post-parse data gathering for ' . $operation);
213
                    $this->bindings[$binding]['operations'][$operation]['input'] =
214
						isset($this->bindings[$binding]['operations'][$operation]['input']) ?
215
						array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) :
216
						$this->portTypes[ $bindingData['portType'] ][$operation]['input'];
217
                    $this->bindings[$binding]['operations'][$operation]['output'] =
218
						isset($this->bindings[$binding]['operations'][$operation]['output']) ?
219
						array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) :
220
						$this->portTypes[ $bindingData['portType'] ][$operation]['output'];
221
                    if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){
222
						$this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ];
223
					}
224
					if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){
225
                   		$this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ];
226
                    }
227
                    // Set operation style if necessary, but do not override one already provided
228
					if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
229
                        $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
230
                    }
231
                    $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
232
                    $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : '';
233
                    $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
234
                }
235
            }
236
        }
237
	}
238
239
    /**
240
     * parses the wsdl document
241
     *
242
     * @param string $wsdl path or URL
243
     * @access private
244
     */
245
    function parseWSDL($wsdl = '') {
246
		$this->debug("parse WSDL at path=$wsdl");
247
248
        if ($wsdl == '') {
249
            $this->debug('no wsdl passed to parseWSDL()!!');
250
            $this->setError('no wsdl passed to parseWSDL()!!');
251
            return false;
252
        }
253
254
        // parse $wsdl for url format
255
        $wsdl_props = parse_url($wsdl);
256
257
        if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
258
            $this->debug('getting WSDL http(s) URL ' . $wsdl);
259
        	// get wsdl
260
	        $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
261
			$tr->request_method = 'GET';
262
			$tr->useSOAPAction = false;
263
			if($this->proxyhost && $this->proxyport){
264
				$tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword);
265
			}
266
			if ($this->authtype != '') {
267
				$tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
268
			}
269
			$tr->setEncoding('gzip, deflate');
270
			$wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
271
			//$this->debug("WSDL request\n" . $tr->outgoing_payload);
272
			//$this->debug("WSDL response\n" . $tr->incoming_payload);
273
			$this->appendDebug($tr->getDebug());
274
			// catch errors
275
			if($err = $tr->getError() ){
276
				$errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err;
277
				$this->debug($errstr);
278
	            $this->setError($errstr);
279
				unset($tr);
280
	            return false;
281
			}
282
			unset($tr);
283
			$this->debug("got WSDL URL");
284
        } else {
285
            // $wsdl is not http(s), so treat it as a file URL or plain file path
286
        	if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
287
        		$path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
288
        	} else {
289
        		$path = $wsdl;
290
        	}
291
            $this->debug('getting WSDL file ' . $path);
292
            $wsdl_string = @file_get_contents($path);
293
            if ($wsdl_string === false) {
294
            	$errstr = "Bad path to WSDL file $path";
295
            	$this->debug($errstr);
296
                $this->setError($errstr);
297
                return false;
298
            }
299
        }
300
        $this->debug('Parse WSDL');
301
        // end new code added
302
        // Create an XML parser.
303
        $this->parser = xml_parser_create();
304
        // Set the options for parsing the XML data.
305
        // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
306
        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
307
        // Set the object for the parser.
308
        xml_set_object($this->parser, $this);
309
        // Set the element handlers for the parser.
310
        xml_set_element_handler($this->parser, 'start_element', 'end_element');
311
        xml_set_character_data_handler($this->parser, 'character_data');
312
        // Parse the XML file.
313
        if (!xml_parse($this->parser, $wsdl_string, true)) {
314
            // Display an error message.
315
            $errstr = sprintf(
316
				'XML error parsing WSDL from %s on line %d: %s',
317
				$wsdl,
318
                xml_get_current_line_number($this->parser),
319
                xml_error_string(xml_get_error_code($this->parser))
320
                );
321
            $this->debug($errstr);
322
			$this->debug("XML payload:\n" . $wsdl_string);
323
            $this->setError($errstr);
324
            return false;
325
        }
326
		// free the parser
327
        xml_parser_free($this->parser);
328
        $this->debug('Parsing WSDL done');
329
		// catch wsdl parse errors
330
		if($this->getError()){
331
			return false;
332
		}
333
        return true;
334
    }
335
336
    /**
337
     * start-element handler
338
     *
339
     * @param string $parser XML parser object
340
     * @param string $name element name
341
     * @param string $attrs associative array of attributes
342
     * @access private
343
     */
344
    function start_element($parser, $name, $attrs)
345
    {
346
        if ($this->status == 'schema') {
347
            $this->currentSchema->schemaStartElement($parser, $name, $attrs);
348
            $this->appendDebug($this->currentSchema->getDebug());
349
            $this->currentSchema->clearDebug();
350
        } elseif (preg_match('/schema$/', $name)) {
351
        	$this->debug('Parsing WSDL schema');
352
            // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
353
            $this->status = 'schema';
354
            $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
355
            $this->currentSchema->schemaStartElement($parser, $name, $attrs);
356
            $this->appendDebug($this->currentSchema->getDebug());
357
            $this->currentSchema->clearDebug();
358
        } else {
359
            // position in the total number of elements, starting from 0
360
            $pos = $this->position++;
361
            $depth = $this->depth++;
362
            // set self as current value for this depth
363
            $this->depth_array[$depth] = $pos;
364
            $this->message[$pos] = array('cdata' => '');
365
            // process attributes
366
            if (count($attrs) > 0) {
367
				// register namespace declarations
368
                foreach($attrs as $k => $v) {
0 ignored issues
show
The expression $attrs of type string is not traversable.
Loading history...
369
                    if (preg_match('/^xmlns/',$k)) {
370
                        if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
371
                            $this->namespaces[$ns_prefix] = $v;
372
                        } else {
373
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
374
                        }
375
                        if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
376
                            $this->XMLSchemaVersion = $v;
377
                            $this->namespaces['xsi'] = $v . '-instance';
378
                        }
379
                    }
380
                }
381
                // expand each attribute prefix to its namespace
382
                foreach($attrs as $k => $v) {
0 ignored issues
show
The expression $attrs of type string is not traversable.
Loading history...
383
                    $k = strpos($k, ':') ? $this->expandQname($k) : $k;
384
                    if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
385
                        $v = strpos($v, ':') ? $this->expandQname($v) : $v;
386
                    }
387
                    $eAttrs[$k] = $v;
388
                }
389
                $attrs = $eAttrs;
390
            } else {
391
                $attrs = array();
392
            }
393
            // get element prefix, namespace and name
394
            if (preg_match('/:/', $name)) {
395
                // get ns prefix
396
                $prefix = substr($name, 0, strpos($name, ':'));
397
                // get ns
398
                $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
399
                // get unqualified name
400
                $name = substr(strstr($name, ':'), 1);
401
            }
402
			// process attributes, expanding any prefixes to namespaces
403
            // find status, register data
404
            switch ($this->status) {
405
                case 'message':
406
                    if ($name == 'part') {
407
			            if (isset($attrs['type'])) {
408
		                    $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
409
		                    $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
410
            			}
411
			            if (isset($attrs['element'])) {
412
		                    $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
413
			                $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
414
			            }
415
        			}
416
        			break;
417
			    case 'portType':
418
			        switch ($name) {
419
			            case 'operation':
420
			                $this->currentPortOperation = $attrs['name'];
421
			                $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
422
			                if (isset($attrs['parameterOrder'])) {
423
			                	$this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
424
			        		}
425
			        		break;
426
					    case 'documentation':
427
					        $this->documentation = true;
428
					        break;
429
					    // merge input/output data
430
					    default:
431
					        $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
432
					        $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
433
					        break;
434
					}
435
			    	break;
436
				case 'binding':
437
				    switch ($name) {
438
				        case 'binding':
439
				            // get ns prefix
440
				            if (isset($attrs['style'])) {
441
				            $this->bindings[$this->currentBinding]['prefix'] = $prefix;
442
					    	}
443
					    	$this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
444
					    	break;
445
						case 'header':
446
						    $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
447
						    break;
448
						case 'operation':
449
						    if (isset($attrs['soapAction'])) {
450
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
451
						    }
452
						    if (isset($attrs['style'])) {
453
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
454
						    }
455
						    if (isset($attrs['name'])) {
456
						        $this->currentOperation = $attrs['name'];
457
						        $this->debug("current binding operation: $this->currentOperation");
458
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
459
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
460
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
461
						    }
462
						    break;
463
						case 'input':
464
						    $this->opStatus = 'input';
465
						    break;
466
						case 'output':
467
						    $this->opStatus = 'output';
468
						    break;
469
						case 'body':
470
						    if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
471
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
472
						    } else {
473
						        $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
474
						    }
475
						    break;
476
					}
477
					break;
478
				case 'service':
479
					switch ($name) {
480
					    case 'port':
481
					        $this->currentPort = $attrs['name'];
482
					        $this->debug('current port: ' . $this->currentPort);
483
					        $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
484
485
					        break;
486
					    case 'address':
487
					        $this->ports[$this->currentPort]['location'] = $attrs['location'];
488
					        $this->ports[$this->currentPort]['bindingType'] = $namespace;
489
					        $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace;
490
					        $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location'];
491
					        break;
492
					}
493
					break;
494
			}
495
		// set status
496
		switch ($name) {
497
			case 'import':
498
			    if (isset($attrs['location'])) {
499
                    $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
500
                    $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')');
501
				} else {
502
                    $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
503
					if (! $this->getPrefixFromNamespace($attrs['namespace'])) {
504
						$this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace'];
505
					}
506
                    $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')');
507
				}
508
				break;
509
			//wait for schema
510
			//case 'types':
511
			//	$this->status = 'schema';
512
			//	break;
513
			case 'message':
514
				$this->status = 'message';
515
				$this->messages[$attrs['name']] = array();
516
				$this->currentMessage = $attrs['name'];
517
				break;
518
			case 'portType':
519
				$this->status = 'portType';
520
				$this->portTypes[$attrs['name']] = array();
521
				$this->currentPortType = $attrs['name'];
522
				break;
523
			case "binding":
524
				if (isset($attrs['name'])) {
525
				// get binding name
526
					if (strpos($attrs['name'], ':')) {
527
			    		$this->currentBinding = $this->getLocalPart($attrs['name']);
528
					} else {
529
			    		$this->currentBinding = $attrs['name'];
530
					}
531
					$this->status = 'binding';
532
					$this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
533
					$this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
534
				}
535
				break;
536
			case 'service':
537
				$this->serviceName = $attrs['name'];
538
				$this->status = 'service';
539
				$this->debug('current service: ' . $this->serviceName);
540
				break;
541
			case 'definitions':
542
				foreach ($attrs as $name => $value) {
543
					$this->wsdl_info[$name] = $value;
544
				}
545
				break;
546
			}
547
		}
548
	}
549
550
	/**
551
	* end-element handler
552
	*
553
	* @param string $parser XML parser object
554
	* @param string $name element name
555
	* @access private
556
	*/
557
	function end_element($parser, $name){
558
		// unset schema status
559
		if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) {
560
			$this->status = "";
561
            $this->appendDebug($this->currentSchema->getDebug());
562
            $this->currentSchema->clearDebug();
563
			$this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
564
        	$this->debug('Parsing WSDL schema done');
565
		}
566
		if ($this->status == 'schema') {
567
			$this->currentSchema->schemaEndElement($parser, $name);
568
		} else {
569
			// bring depth down a notch
570
			$this->depth--;
571
		}
572
		// end documentation
573
		if ($this->documentation) {
574
			//TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
575
			//$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
576
			$this->documentation = false;
577
		}
578
	}
579
580
	/**
581
	 * element content handler
582
	 *
583
	 * @param string $parser XML parser object
584
	 * @param string $data element content
585
	 * @access private
586
	 */
587
	function character_data($parser, $data)
588
	{
589
		$pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
590
		if (isset($this->message[$pos]['cdata'])) {
591
			$this->message[$pos]['cdata'] .= $data;
592
		}
593
		if ($this->documentation) {
594
			$this->documentation .= $data;
595
		}
596
	}
597
598
	/**
599
	* if authenticating, set user credentials here
600
	*
601
	* @param    string $username
602
	* @param    string $password
603
	* @param	string $authtype (basic|digest|certificate|ntlm)
604
	* @param	array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
605
	* @access   public
606
	*/
607
	function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) {
608
		$this->debug("setCredentials username=$username authtype=$authtype certRequest=");
609
		$this->appendDebug($this->varDump($certRequest));
610
		$this->username = $username;
611
		$this->password = $password;
612
		$this->authtype = $authtype;
613
		$this->certRequest = $certRequest;
614
	}
615
616
	function getBindingData($binding)
617
	{
618
		if (is_array($this->bindings[$binding])) {
619
			return $this->bindings[$binding];
620
		}
621
	}
622
623
	/**
624
	 * returns an assoc array of operation names => operation data
625
	 *
626
	 * @param string $portName WSDL port name
627
	 * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
628
	 * @return array
629
	 * @access public
630
	 */
631
	function getOperations($portName = '', $bindingType = 'soap') {
632
		$ops = array();
633
		if ($bindingType == 'soap') {
634
			$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
635
		} elseif ($bindingType == 'soap12') {
636
			$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
637
		} else {
638
			$this->debug("getOperations bindingType $bindingType may not be supported");
639
		}
640
		$this->debug("getOperations for port '$portName' bindingType $bindingType");
641
		// loop thru ports
642
		foreach($this->ports as $port => $portData) {
643
			$this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
644
			if ($portName == '' || $port == $portName) {
645
				// binding type of port matches parameter
646
				if ($portData['bindingType'] == $bindingType) {
647
					$this->debug("getOperations found port $port bindingType $bindingType");
648
					//$this->debug("port data: " . $this->varDump($portData));
649
					//$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
650
					// merge bindings
651
					if (isset($this->bindings[ $portData['binding'] ]['operations'])) {
652
						$ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']);
653
					}
654
				}
655
			}
656
		}
657
		if (count($ops) == 0) {
658
			$this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
659
		}
660
		return $ops;
661
	}
662
663
	/**
664
	 * returns an associative array of data necessary for calling an operation
665
	 *
666
	 * @param string $operation name of operation
667
	 * @param string $bindingType type of binding eg: soap, soap12
668
	 * @return array
669
	 * @access public
670
	 */
671
	function getOperationData($operation, $bindingType = 'soap')
672
	{
673
		if ($bindingType == 'soap') {
674
			$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
675
		} elseif ($bindingType == 'soap12') {
676
			$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
677
		}
678
		// loop thru ports
679
		foreach($this->ports as $port => $portData) {
680
			// binding type of port matches parameter
681
			if ($portData['bindingType'] == $bindingType) {
682
				// get binding
683
				//foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
684
				foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) {
685
					// note that we could/should also check the namespace here
686
					if ($operation == $bOperation) {
687
						$opData = $this->bindings[ $portData['binding'] ]['operations'][$operation];
688
					    return $opData;
689
					}
690
				}
691
			}
692
		}
693
	}
694
695
	/**
696
	 * returns an associative array of data necessary for calling an operation
697
	 *
698
	 * @param string $soapAction soapAction for operation
699
	 * @param string $bindingType type of binding eg: soap, soap12
700
	 * @return array
701
	 * @access public
702
	 */
703
	function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') {
704
		if ($bindingType == 'soap') {
705
			$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
706
		} elseif ($bindingType == 'soap12') {
707
			$bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
708
		}
709
		// loop thru ports
710
		foreach($this->ports as $port => $portData) {
711
			// binding type of port matches parameter
712
			if ($portData['bindingType'] == $bindingType) {
713
				// loop through operations for the binding
714
				foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
715
					if ($opData['soapAction'] == $soapAction) {
716
					    return $opData;
717
					}
718
				}
719
			}
720
		}
721
	}
722
723
	/**
724
    * returns an array of information about a given type
725
    * returns false if no type exists by the given name
726
    *
727
	*	 typeDef = array(
728
	*	 'elements' => array(), // refs to elements array
729
	*	'restrictionBase' => '',
730
	*	'phpType' => '',
731
	*	'order' => '(sequence|all)',
732
	*	'attrs' => array() // refs to attributes array
733
	*	)
734
    *
735
    * @param string $type the type
736
    * @param string $ns namespace (not prefix) of the type
737
    * @return mixed
738
    * @access public
739
    * @see nusoap_xmlschema
740
    */
741
	function getTypeDef($type, $ns) {
742
		$this->debug("in getTypeDef: type=$type, ns=$ns");
743
		if ((! $ns) && isset($this->namespaces['tns'])) {
744
			$ns = $this->namespaces['tns'];
745
			$this->debug("in getTypeDef: type namespace forced to $ns");
746
		}
747
		if (!isset($this->schemas[$ns])) {
748
			foreach ($this->schemas as $ns0 => $schema0) {
749
				if (strcasecmp($ns, $ns0) == 0) {
750
					$this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
751
					$ns = $ns0;
752
					break;
753
				}
754
			}
755
		}
756
		if (isset($this->schemas[$ns])) {
757
			$this->debug("in getTypeDef: have schema for namespace $ns");
758
			for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
759
				$xs = &$this->schemas[$ns][$i];
760
				$t = $xs->getTypeDef($type);
761
				$this->appendDebug($xs->getDebug());
762
				$xs->clearDebug();
763
				if ($t) {
764
					$this->debug("in getTypeDef: found type $type");
765
					if (!isset($t['phpType'])) {
766
						// get info for type to tack onto the element
767
						$uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
768
						$ns = substr($t['type'], 0, strrpos($t['type'], ':'));
769
						$etype = $this->getTypeDef($uqType, $ns);
770
						if ($etype) {
771
							$this->debug("found type for [element] $type:");
772
							$this->debug($this->varDump($etype));
773
							if (isset($etype['phpType'])) {
774
								$t['phpType'] = $etype['phpType'];
775
							}
776
							if (isset($etype['elements'])) {
777
								$t['elements'] = $etype['elements'];
778
							}
779
							if (isset($etype['attrs'])) {
780
								$t['attrs'] = $etype['attrs'];
781
							}
782
						} else {
783
							$this->debug("did not find type for [element] $type");
784
						}
785
					}
786
					return $t;
787
				}
788
			}
789
			$this->debug("in getTypeDef: did not find type $type");
790
		} else {
791
			$this->debug("in getTypeDef: do not have schema for namespace $ns");
792
		}
793
		return false;
794
	}
795
796
    /**
797
    * prints html description of services
798
    *
799
    * @access private
800
    */
801
    function webDescription(){
802
    	global $HTTP_SERVER_VARS;
803
804
		if (isset($_SERVER)) {
805
			$PHP_SELF = $_SERVER['PHP_SELF'];
806
		} elseif (isset($HTTP_SERVER_VARS)) {
807
			$PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
808
		} else {
809
			$this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
810
		}
811
812
		$b = '
813
		<html><head><title>NuSOAP: '.$this->serviceName.'</title>
814
		<style type="text/css">
815
		    body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0px 0px 0px 0px; }
816
		    p       { font-family: arial; color: #000000; margin-top: 0px; margin-bottom: 12px; }
817
		    pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
818
		    ul      { margin-top: 10px; margin-left: 20px; }
819
		    li      { list-style-type: none; margin-top: 10px; color: #000000; }
820
		    .content{
821
			margin-left: 0px; padding-bottom: 2em; }
822
		    .nav {
823
			padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
824
			margin-top: 10px; margin-left: 0px; color: #000000;
825
			background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
826
		    .title {
827
			font-family: arial; font-size: 26px; color: #ffffff;
828
			background-color: #999999; width: 100%;
829
			margin-left: 0px; margin-right: 0px;
830
			padding-top: 10px; padding-bottom: 10px;}
831
		    .hidden {
832
			position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
833
			font-family: arial; overflow: hidden; width: 600;
834
			padding: 20px; font-size: 10px; background-color: #999999;
835
			layer-background-color:#FFFFFF; }
836
		    a,a:active  { color: charcoal; font-weight: bold; }
837
		    a:visited   { color: #666666; font-weight: bold; }
838
		    a:hover     { color: cc3300; font-weight: bold; }
839
		</style>
840
		<script language="JavaScript" type="text/javascript">
841
		<!--
842
		// POP-UP CAPTIONS...
843
		function lib_bwcheck(){ //Browsercheck (needed)
844
		    this.ver=navigator.appVersion
845
		    this.agent=navigator.userAgent
846
		    this.dom=document.getElementById?1:0
847
		    this.opera5=this.agent.indexOf("Opera 5")>-1
848
		    this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
849
		    this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
850
		    this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
851
		    this.ie=this.ie4||this.ie5||this.ie6
852
		    this.mac=this.agent.indexOf("Mac")>-1
853
		    this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
854
		    this.ns4=(document.layers && !this.dom)?1:0;
855
		    this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
856
		    return this
857
		}
858
		var bw = new lib_bwcheck()
859
		//Makes crossbrowser object.
860
		function makeObj(obj){
861
		    this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
862
		    if(!this.evnt) return false
863
		    this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
864
		    this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
865
		    this.writeIt=b_writeIt;
866
		    return this
867
		}
868
		// A unit of measure that will be added when setting the position of a layer.
869
		//var px = bw.ns4||window.opera?"":"px";
870
		function b_writeIt(text){
871
		    if (bw.ns4){this.wref.write(text);this.wref.close()}
872
		    else this.wref.innerHTML = text
873
		}
874
		//Shows the messages
875
		var oDesc;
876
		function popup(divid){
877
		    if(oDesc = new makeObj(divid)){
878
			oDesc.css.visibility = "visible"
879
		    }
880
		}
881
		function popout(){ // Hides message
882
		    if(oDesc) oDesc.css.visibility = "hidden"
883
		}
884
		//-->
885
		</script>
886
		</head>
887
		<body>
888
		<div class=content>
889
			<br><br>
890
			<div class=title>'.$this->serviceName.'</div>
891
			<div class=nav>
892
				<p>View the <a href="'.$PHP_SELF.'?wsdl">WSDL</a> for the service.
893
				Click on an operation name to view it&apos;s details.</p>
894
				<ul>';
895
				foreach($this->getOperations() as $op => $data){
896
				    $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
897
				    // create hidden div
898
				    $b .= "<div id='$op' class='hidden'>
899
				    <a href='#' onclick='popout()'><font color='#ffffff'>Close</font></a><br><br>";
900
				    foreach($data as $donnie => $marie){ // loop through opdata
901
						if($donnie == 'input' || $donnie == 'output'){ // show input/output data
902
						    $b .= "<font color='white'>".ucfirst($donnie).':</font><br>';
903
						    foreach($marie as $captain => $tenille){ // loop through data
904
								if($captain == 'parts'){ // loop thru parts
905
								    $b .= "&nbsp;&nbsp;$captain:<br>";
906
					                //if(is_array($tenille)){
907
								    	foreach($tenille as $joanie => $chachi){
908
											$b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
909
								    	}
910
					        		//}
911
								} else {
912
								    $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
913
								}
914
						    }
915
						} else {
916
						    $b .= "<font color='white'>".ucfirst($donnie).":</font> $marie<br>";
917
						}
918
				    }
919
					$b .= '</div>';
920
				}
921
				$b .= '
922
				<ul>
923
			</div>
924
		</div></body></html>';
925
		return $b;
926
    }
927
928
	/**
929
	* serialize the parsed wsdl
930
	*
931
	* @param mixed $debug whether to put debug=1 in endpoint URL
932
	* @return string serialization of WSDL
933
	* @access public
934
	*/
935
	function serialize($debug = 0)
936
	{
937
		$xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
938
		$xml .= "\n<definitions";
939
		foreach($this->namespaces as $k => $v) {
940
			$xml .= " xmlns:$k=\"$v\"";
941
		}
942
		// 10.9.02 - add poulter fix for wsdl and tns declarations
943
		if (isset($this->namespaces['wsdl'])) {
944
			$xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
945
		}
946
		if (isset($this->namespaces['tns'])) {
947
			$xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
948
		}
949
		$xml .= '>';
950
		// imports
951
		if (sizeof($this->import) > 0) {
952
			foreach($this->import as $ns => $list) {
953
				foreach ($list as $ii) {
954
					if ($ii['location'] != '') {
955
						$xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
956
					} else {
957
						$xml .= '<import namespace="' . $ns . '" />';
958
					}
959
				}
960
			}
961
		}
962
		// types
963
		if (count($this->schemas)>=1) {
964
			$xml .= "\n<types>\n";
965
			foreach ($this->schemas as $ns => $list) {
966
				foreach ($list as $xs) {
967
					$xml .= $xs->serializeSchema();
968
				}
969
			}
970
			$xml .= '</types>';
971
		}
972
		// messages
973
		if (count($this->messages) >= 1) {
974
			foreach($this->messages as $msgName => $msgParts) {
975
				$xml .= "\n<message name=\"" . $msgName . '">';
976
				if(is_array($msgParts)){
977
					foreach($msgParts as $partName => $partType) {
978
						// print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
979
						if (strpos($partType, ':')) {
980
						    $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
0 ignored issues
show
It seems like $this->getPrefix($partType) targeting nusoap_base::getPrefix() can also be of type false; however, nusoap_base::getPrefixFromNamespace() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
981
						} elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
982
						    // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
983
						    $typePrefix = 'xsd';
984
						} else {
985
						    foreach($this->typemap as $ns => $types) {
986
						        if (isset($types[$partType])) {
987
						            $typePrefix = $this->getPrefixFromNamespace($ns);
988
						        }
989
						    }
990
						    if (!isset($typePrefix)) {
991
						        die("$partType has no namespace!");
992
						    }
993
						}
994
						$ns = $this->getNamespaceFromPrefix($typePrefix);
995
						$localPart = $this->getLocalPart($partType);
996
						$typeDef = $this->getTypeDef($localPart, $ns);
997
						if ($typeDef['typeClass'] == 'element') {
998
							$elementortype = 'element';
999
							if (substr($localPart, -1) == '^') {
1000
								$localPart = substr($localPart, 0, -1);
1001
							}
1002
						} else {
1003
							$elementortype = 'type';
1004
						}
1005
						$xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
1006
					}
1007
				}
1008
				$xml .= '</message>';
1009
			}
1010
		}
1011
		// bindings & porttypes
1012
		if (count($this->bindings) >= 1) {
1013
			$binding_xml = '';
1014
			$portType_xml = '';
1015
			foreach($this->bindings as $bindingName => $attrs) {
1016
				$binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
1017
				$binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
1018
				$portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
1019
				foreach($attrs['operations'] as $opName => $opParts) {
1020
					$binding_xml .= "\n" . '  <operation name="' . $opName . '">';
1021
					$binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="'. $opParts['style'] . '"/>';
1022
					if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
1023
						$enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
1024
					} else {
1025
						$enc_style = '';
1026
					}
1027
					$binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
1028
					if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
1029
						$enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
1030
					} else {
1031
						$enc_style = '';
1032
					}
1033
					$binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
1034
					$binding_xml .= "\n" . '  </operation>';
1035
					$portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
1036
					if (isset($opParts['parameterOrder'])) {
1037
					    $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
1038
					}
1039
					$portType_xml .= '>';
1040
					if(isset($opParts['documentation']) && $opParts['documentation'] != '') {
1041
						$portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
1042
					}
1043
					$portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';
1044
					$portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';
1045
					$portType_xml .= "\n" . '  </operation>';
1046
				}
1047
				$portType_xml .= "\n" . '</portType>';
1048
				$binding_xml .= "\n" . '</binding>';
1049
			}
1050
			$xml .= $portType_xml . $binding_xml;
1051
		}
1052
		// services
1053
		$xml .= "\n<service name=\"" . $this->serviceName . '">';
1054
		if (count($this->ports) >= 1) {
1055
			foreach($this->ports as $pName => $attrs) {
1056
				$xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
1057
				$xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
1058
				$xml .= "\n" . '  </port>';
1059
			}
1060
		}
1061
		$xml .= "\n" . '</service>';
1062
		return $xml . "\n</definitions>";
1063
	}
1064
1065
	/**
1066
	 * determine whether a set of parameters are unwrapped
1067
	 * when they are expect to be wrapped, Microsoft-style.
1068
	 *
1069
	 * @param string $type the type (element name) of the wrapper
1070
	 * @param array $parameters the parameter values for the SOAP call
1071
	 * @return boolean whether they parameters are unwrapped (and should be wrapped)
1072
	 * @access private
1073
	 */
1074
	function parametersMatchWrapped($type, &$parameters) {
1075
		$this->debug("in parametersMatchWrapped type=$type, parameters=");
1076
		$this->appendDebug($this->varDump($parameters));
1077
1078
		// split type into namespace:unqualified-type
1079
		if (strpos($type, ':')) {
1080
			$uqType = substr($type, strrpos($type, ':') + 1);
1081
			$ns = substr($type, 0, strrpos($type, ':'));
1082
			$this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
1083
			if ($this->getNamespaceFromPrefix($ns)) {
1084
				$ns = $this->getNamespaceFromPrefix($ns);
1085
				$this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
1086
			}
1087
		} else {
1088
			// TODO: should the type be compared to types in XSD, and the namespace
1089
			// set to XSD if the type matches?
1090
			$this->debug("in parametersMatchWrapped: No namespace for type $type");
1091
			$ns = '';
1092
			$uqType = $type;
1093
		}
1094
1095
		// get the type information
1096
		if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
1097
			$this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
1098
			return false;
1099
		}
1100
		$this->debug("in parametersMatchWrapped: found typeDef=");
1101
		$this->appendDebug($this->varDump($typeDef));
1102
		if (substr($uqType, -1) == '^') {
1103
			$uqType = substr($uqType, 0, -1);
1104
		}
1105
		$phpType = $typeDef['phpType'];
1106
		$arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
1107
		$this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
1108
1109
		// we expect a complexType or element of complexType
1110
		if ($phpType != 'struct') {
1111
			$this->debug("in parametersMatchWrapped: not a struct");
1112
			return false;
1113
		}
1114
1115
		// see whether the parameter names match the elements
1116
		if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
1117
			$elements = 0;
1118
			$matches = 0;
1119
			foreach ($typeDef['elements'] as $name => $attrs) {
1120
				if (isset($parameters[$name])) {
1121
					$this->debug("in parametersMatchWrapped: have parameter named $name");
1122
					$matches++;
1123
				} else {
1124
					$this->debug("in parametersMatchWrapped: do not have parameter named $name");
1125
				}
1126
				$elements++;
1127
			}
1128
1129
			$this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
1130
			if ($matches == 0) {
1131
				return false;
1132
			}
1133
			return true;
1134
		}
1135
1136
		// since there are no elements for the type, if the user passed no
1137
		// parameters, the parameters match wrapped.
1138
		$this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
1139
		return count($parameters) == 0;
1140
	}
1141
1142
	/**
1143
	 * serialize PHP values according to a WSDL message definition
1144
	 * contrary to the method name, this is not limited to RPC
1145
	 *
1146
	 * TODO
1147
	 * - multi-ref serialization
1148
	 * - validate PHP values against type definitions, return errors if invalid
1149
	 *
1150
	 * @param string $operation operation name
1151
	 * @param string $direction (input|output)
1152
	 * @param mixed $parameters parameter value(s)
1153
	 * @param string $bindingType (soap|soap12)
1154
	 * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
1155
	 * @access public
1156
	 */
1157
	function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') {
1158
		$this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
1159
		$this->appendDebug('parameters=' . $this->varDump($parameters));
1160
1161
		if ($direction != 'input' && $direction != 'output') {
1162
			$this->debug('The value of the \$direction argument needs to be either "input" or "output"');
1163
			$this->setError('The value of the \$direction argument needs to be either "input" or "output"');
1164
			return false;
1165
		}
1166
		if (!$opData = $this->getOperationData($operation, $bindingType)) {
1167
			$this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
1168
			$this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
1169
			return false;
1170
		}
1171
		$this->debug('in serializeRPCParameters: opData:');
1172
		$this->appendDebug($this->varDump($opData));
1173
1174
		// Get encoding style for output and set to current
1175
		$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
1176
		if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
1177
			$encodingStyle = $opData['output']['encodingStyle'];
1178
			$enc_style = $encodingStyle;
1179
		}
1180
1181
		// set input params
1182
		$xml = '';
1183
		if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
1184
			$parts = &$opData[$direction]['parts'];
1185
			$part_count = sizeof($parts);
1186
			$style = $opData['style'];
1187
			$use = $opData[$direction]['use'];
1188
			$this->debug("have $part_count part(s) to serialize using $style/$use");
1189
			if (is_array($parameters)) {
1190
				$parametersArrayType = $this->isArraySimpleOrStruct($parameters);
1191
				$parameter_count = count($parameters);
1192
				$this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
1193
				// check for Microsoft-style wrapped parameters
1194
				if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
1195
					$this->debug('check whether the caller has wrapped the parameters');
1196
					if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) {
1197
						// TODO: consider checking here for double-wrapping, when
1198
						// service function wraps, then NuSOAP wraps again
1199
						$this->debug("change simple array to associative with 'parameters' element");
1200
						$parameters['parameters'] = $parameters[0];
1201
						unset($parameters[0]);
1202
					}
1203
					if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) {
1204
						$this->debug('check whether caller\'s parameters match the wrapped ones');
1205
						if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
1206
							$this->debug('wrap the parameters for the caller');
1207
							$parameters = array('parameters' => $parameters);
1208
							$parameter_count = 1;
1209
						}
1210
					}
1211
				}
1212
				foreach ($parts as $name => $type) {
1213
					$this->debug("serializing part $name of type $type");
1214
					// Track encoding style
1215
					if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
1216
						$encodingStyle = $opData[$direction]['encodingStyle'];
1217
						$enc_style = $encodingStyle;
1218
					} else {
1219
						$enc_style = false;
1220
					}
1221
					// NOTE: add error handling here
1222
					// if serializeType returns false, then catch global error and fault
1223
					if ($parametersArrayType == 'arraySimple') {
1224
						$p = array_shift($parameters);
1225
						$this->debug('calling serializeType w/indexed param');
1226
						$xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
1227
					} elseif (isset($parameters[$name])) {
1228
						$this->debug('calling serializeType w/named param');
1229
						$xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
1230
					} else {
1231
						// TODO: only send nillable
1232
						$this->debug('calling serializeType w/null param');
1233
						$xml .= $this->serializeType($name, $type, null, $use, $enc_style);
1234
					}
1235
				}
1236
			} else {
1237
				$this->debug('no parameters passed.');
1238
			}
1239
		}
1240
		$this->debug("serializeRPCParameters returning: $xml");
1241
		return $xml;
1242
	}
1243
1244
	/**
1245
	 * serialize a PHP value according to a WSDL message definition
1246
	 *
1247
	 * TODO
1248
	 * - multi-ref serialization
1249
	 * - validate PHP values against type definitions, return errors if invalid
1250
	 *
1251
	 * @param string $operation operation name
1252
	 * @param string $direction (input|output)
1253
	 * @param mixed $parameters parameter value(s)
1254
	 * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
1255
	 * @access public
1256
	 * @deprecated
1257
	 */
1258
	function serializeParameters($operation, $direction, $parameters)
1259
	{
1260
		$this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
1261
		$this->appendDebug('parameters=' . $this->varDump($parameters));
1262
1263
		if ($direction != 'input' && $direction != 'output') {
1264
			$this->debug('The value of the \$direction argument needs to be either "input" or "output"');
1265
			$this->setError('The value of the \$direction argument needs to be either "input" or "output"');
1266
			return false;
1267
		}
1268
		if (!$opData = $this->getOperationData($operation)) {
1269
			$this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
1270
			$this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
1271
			return false;
1272
		}
1273
		$this->debug('opData:');
1274
		$this->appendDebug($this->varDump($opData));
1275
1276
		// Get encoding style for output and set to current
1277
		$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
1278
		if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
1279
			$encodingStyle = $opData['output']['encodingStyle'];
1280
			$enc_style = $encodingStyle;
1281
		}
1282
1283
		// set input params
1284
		$xml = '';
1285
		if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
1286
1287
			$use = $opData[$direction]['use'];
1288
			$this->debug("use=$use");
1289
			$this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
1290
			if (is_array($parameters)) {
1291
				$parametersArrayType = $this->isArraySimpleOrStruct($parameters);
1292
				$this->debug('have ' . $parametersArrayType . ' parameters');
1293
				foreach($opData[$direction]['parts'] as $name => $type) {
1294
					$this->debug('serializing part "'.$name.'" of type "'.$type.'"');
1295
					// Track encoding style
1296
					if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
1297
						$encodingStyle = $opData[$direction]['encodingStyle'];
1298
						$enc_style = $encodingStyle;
1299
					} else {
1300
						$enc_style = false;
1301
					}
1302
					// NOTE: add error handling here
1303
					// if serializeType returns false, then catch global error and fault
1304
					if ($parametersArrayType == 'arraySimple') {
1305
						$p = array_shift($parameters);
1306
						$this->debug('calling serializeType w/indexed param');
1307
						$xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
1308
					} elseif (isset($parameters[$name])) {
1309
						$this->debug('calling serializeType w/named param');
1310
						$xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
1311
					} else {
1312
						// TODO: only send nillable
1313
						$this->debug('calling serializeType w/null param');
1314
						$xml .= $this->serializeType($name, $type, null, $use, $enc_style);
1315
					}
1316
				}
1317
			} else {
1318
				$this->debug('no parameters passed.');
1319
			}
1320
		}
1321
		$this->debug("serializeParameters returning: $xml");
1322
		return $xml;
1323
	}
1324
1325
	/**
1326
	 * serializes a PHP value according a given type definition
1327
	 *
1328
	 * @param string $name name of value (part or element)
1329
	 * @param string $type XML schema type of value (type or element)
1330
	 * @param mixed $value a native PHP value (parameter value)
1331
	 * @param string $use use for part (encoded|literal)
1332
	 * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
1333
	 * @param boolean $unqualified a kludge for what should be XML namespace form handling
1334
	 * @return string value serialized as an XML string
1335
	 * @access private
1336
	 */
1337
	function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false)
1338
	{
1339
		$this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
1340
		$this->appendDebug("value=" . $this->varDump($value));
1341
		if($use == 'encoded' && $encodingStyle) {
1342
			$encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
1343
		}
1344
1345
		// if a soapval has been supplied, let its type override the WSDL
1346
    	if (is_object($value) && get_class($value) == 'soapval') {
1347
    		if ($value->type_ns) {
1348
    			$type = $value->type_ns . ':' . $value->type;
1349
		    	$forceType = true;
1350
		    	$this->debug("in serializeType: soapval overrides type to $type");
1351
    		} elseif ($value->type) {
1352
	    		$type = $value->type;
1353
		    	$forceType = true;
1354
		    	$this->debug("in serializeType: soapval overrides type to $type");
1355
	    	} else {
1356
	    		$forceType = false;
1357
		    	$this->debug("in serializeType: soapval does not override type");
1358
	    	}
1359
	    	$attrs = $value->attributes;
1360
	    	$value = $value->value;
1361
	    	$this->debug("in serializeType: soapval overrides value to $value");
1362
	    	if ($attrs) {
1363
	    		if (!is_array($value)) {
1364
	    			$value['!'] = $value;
1365
	    		}
1366
	    		foreach ($attrs as $n => $v) {
1367
	    			$value['!' . $n] = $v;
1368
	    		}
1369
		    	$this->debug("in serializeType: soapval provides attributes");
1370
		    }
1371
        } else {
1372
        	$forceType = false;
1373
        }
1374
1375
		$xml = '';
1376
		if (strpos($type, ':')) {
1377
			$uqType = substr($type, strrpos($type, ':') + 1);
1378
			$ns = substr($type, 0, strrpos($type, ':'));
1379
			$this->debug("in serializeType: got a prefixed type: $uqType, $ns");
1380
			if ($this->getNamespaceFromPrefix($ns)) {
1381
				$ns = $this->getNamespaceFromPrefix($ns);
1382
				$this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
1383
			}
1384
1385
			if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){
1386
				$this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
1387
				if ($unqualified && $use == 'literal') {
1388
					$elementNS = " xmlns=\"\"";
1389
				} else {
1390
					$elementNS = '';
1391
				}
1392
				if (is_null($value)) {
1393
					if ($use == 'literal') {
1394
						// TODO: depends on minOccurs
1395
						$xml = "<$name$elementNS/>";
1396
					} else {
1397
						// TODO: depends on nillable, which should be checked before calling this method
1398
						$xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
1399
					}
1400
					$this->debug("in serializeType: returning: $xml");
1401
					return $xml;
1402
				}
1403
				if ($uqType == 'Array') {
1404
					// JBoss/Axis does this sometimes
1405
					return $this->serialize_val($value, $name, false, false, false, false, $use);
1406
				}
1407
		    	if ($uqType == 'boolean') {
1408
		    		if ((is_string($value) && $value == 'false') || (! $value)) {
1409
						$value = 'false';
1410
					} else {
1411
						$value = 'true';
1412
					}
1413
				}
1414
				if ($uqType == 'string' && gettype($value) == 'string') {
1415
					$value = $this->expandEntities($value);
1416
				}
1417
				if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
1418
					$value = sprintf("%.0lf", $value);
1419
				}
1420
				// it's a scalar
1421
				// TODO: what about null/nil values?
1422
				// check type isn't a custom type extending xmlschema namespace
1423
				if (!$this->getTypeDef($uqType, $ns)) {
1424
					if ($use == 'literal') {
1425
						if ($forceType) {
1426
							$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
1427
						} else {
1428
							$xml = "<$name$elementNS>$value</$name>";
1429
						}
1430
					} else {
1431
						$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
1432
					}
1433
					$this->debug("in serializeType: returning: $xml");
1434
					return $xml;
1435
				}
1436
				$this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
1437
			} else if ($ns == 'http://xml.apache.org/xml-soap') {
1438
				$this->debug('in serializeType: appears to be Apache SOAP type');
1439
				if ($uqType == 'Map') {
1440
					$tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
1441
					if (! $tt_prefix) {
1442
						$this->debug('in serializeType: Add namespace for Apache SOAP type');
1443
						$tt_prefix = 'ns' . rand(1000, 9999);
1444
						$this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
1445
						// force this to be added to usedNamespaces
1446
						$tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
1447
					}
1448
					$contents = '';
1449
					foreach($value as $k => $v) {
1450
						$this->debug("serializing map element: key $k, value $v");
1451
						$contents .= '<item>';
1452
						$contents .= $this->serialize_val($k,'key',false,false,false,false,$use);
1453
						$contents .= $this->serialize_val($v,'value',false,false,false,false,$use);
1454
						$contents .= '</item>';
1455
					}
1456
					if ($use == 'literal') {
1457
						if ($forceType) {
1458
							$xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
1459
						} else {
1460
							$xml = "<$name>$contents</$name>";
1461
						}
1462
					} else {
1463
						$xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
1464
					}
1465
					$this->debug("in serializeType: returning: $xml");
1466
					return $xml;
1467
				}
1468
				$this->debug('in serializeType: Apache SOAP type, but only support Map');
1469
			}
1470
		} else {
1471
			// TODO: should the type be compared to types in XSD, and the namespace
1472
			// set to XSD if the type matches?
1473
			$this->debug("in serializeType: No namespace for type $type");
1474
			$ns = '';
1475
			$uqType = $type;
1476
		}
1477
		if(!$typeDef = $this->getTypeDef($uqType, $ns)){
1478
			$this->setError("$type ($uqType) is not a supported type.");
1479
			$this->debug("in serializeType: $type ($uqType) is not a supported type.");
1480
			return false;
1481
		} else {
1482
			$this->debug("in serializeType: found typeDef");
1483
			$this->appendDebug('typeDef=' . $this->varDump($typeDef));
1484
			if (substr($uqType, -1) == '^') {
1485
				$uqType = substr($uqType, 0, -1);
1486
			}
1487
		}
1488
		if (!isset($typeDef['phpType'])) {
1489
			$this->setError("$type ($uqType) has no phpType.");
1490
			$this->debug("in serializeType: $type ($uqType) has no phpType.");
1491
			return false;
1492
		}
1493
		$phpType = $typeDef['phpType'];
1494
		$this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') );
1495
		// if php type == struct, map value to the <all> element names
1496
		if ($phpType == 'struct') {
1497
			if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
1498
				$elementName = $uqType;
1499
				if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
1500
					$elementNS = " xmlns=\"$ns\"";
1501
				} else {
1502
					$elementNS = " xmlns=\"\"";
1503
				}
1504
			} else {
1505
				$elementName = $name;
1506
				if ($unqualified) {
1507
					$elementNS = " xmlns=\"\"";
1508
				} else {
1509
					$elementNS = '';
1510
				}
1511
			}
1512
			if (is_null($value)) {
1513
				if ($use == 'literal') {
1514
					// TODO: depends on minOccurs and nillable
1515
					$xml = "<$elementName$elementNS/>";
1516
				} else {
1517
					$xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
1518
				}
1519
				$this->debug("in serializeType: returning: $xml");
1520
				return $xml;
1521
			}
1522
			if (is_object($value)) {
1523
				$value = get_object_vars($value);
1524
			}
1525
			if (is_array($value)) {
1526
				$elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
1527
				if ($use == 'literal') {
1528
					if ($forceType) {
1529
						$xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
1530
					} else {
1531
						$xml = "<$elementName$elementNS$elementAttrs>";
1532
					}
1533
				} else {
1534
					$xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
1535
				}
1536
1537
				if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') {
1538
					if (isset($value['!'])) {
1539
						$xml .= $value['!'];
1540
						$this->debug("in serializeType: serialized simpleContent for type $type");
1541
					} else {
1542
						$this->debug("in serializeType: no simpleContent to serialize for type $type");
1543
					}
1544
				} else {
1545
					// complexContent
1546
					$xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
1547
				}
1548
				$xml .= "</$elementName>";
1549
			} else {
1550
				$this->debug("in serializeType: phpType is struct, but value is not an array");
1551
				$this->setError("phpType is struct, but value is not an array: see debug output for details");
1552
				$xml = '';
1553
			}
1554
		} elseif ($phpType == 'array') {
1555
			if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
1556
				$elementNS = " xmlns=\"$ns\"";
1557
			} else {
1558
				if ($unqualified) {
1559
					$elementNS = " xmlns=\"\"";
1560
				} else {
1561
					$elementNS = '';
1562
				}
1563
			}
1564
			if (is_null($value)) {
1565
				if ($use == 'literal') {
1566
					// TODO: depends on minOccurs
1567
					$xml = "<$name$elementNS/>";
1568
				} else {
1569
					$xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
1570
						$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
1571
						":Array\" " .
1572
						$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
1573
						':arrayType="' .
1574
						$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
0 ignored issues
show
It seems like $this->getPrefix($typeDef['arrayType']) targeting nusoap_base::getPrefix() can also be of type false; however, nusoap_base::getPrefixFromNamespace() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1575
						':' .
1576
						$this->getLocalPart($typeDef['arrayType'])."[0]\"/>";
1577
				}
1578
				$this->debug("in serializeType: returning: $xml");
1579
				return $xml;
1580
			}
1581
			if (isset($typeDef['multidimensional'])) {
1582
				$nv = array();
1583
				foreach($value as $v) {
0 ignored issues
show
The expression $value of type object|integer|double|string|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1584
					$cols = ',' . sizeof($v);
1585
					$nv = array_merge($nv, $v);
1586
				}
1587
				$value = $nv;
1588
			} else {
1589
				$cols = '';
1590
			}
1591
			if (is_array($value) && sizeof($value) >= 1) {
1592
				$rows = sizeof($value);
1593
				$contents = '';
1594
				foreach($value as $k => $v) {
1595
					$this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
1596
					//if (strpos($typeDef['arrayType'], ':') ) {
1597
					if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) {
1598
					    $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
1599
					} else {
1600
					    $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
1601
					}
1602
				}
1603
			} else {
1604
				$rows = 0;
1605
				$contents = null;
1606
			}
1607
			// TODO: for now, an empty value will be serialized as a zero element
1608
			// array.  Revisit this when coding the handling of null/nil values.
1609
			if ($use == 'literal') {
1610
				$xml = "<$name$elementNS>"
1611
					.$contents
1612
					."</$name>";
1613
			} else {
1614
				$xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '.
1615
					$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
1616
					.':arrayType="'
1617
					.$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
0 ignored issues
show
It seems like $this->getPrefix($typeDef['arrayType']) targeting nusoap_base::getPrefix() can also be of type false; however, nusoap_base::getPrefixFromNamespace() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1618
					.":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">"
1619
					.$contents
1620
					."</$name>";
1621
			}
1622
		} elseif ($phpType == 'scalar') {
1623
			if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
1624
				$elementNS = " xmlns=\"$ns\"";
1625
			} else {
1626
				if ($unqualified) {
1627
					$elementNS = " xmlns=\"\"";
1628
				} else {
1629
					$elementNS = '';
1630
				}
1631
			}
1632
			if ($use == 'literal') {
1633
				if ($forceType) {
1634
					$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
1635
				} else {
1636
					$xml = "<$name$elementNS>$value</$name>";
1637
				}
1638
			} else {
1639
				$xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
1640
			}
1641
		}
1642
		$this->debug("in serializeType: returning: $xml");
1643
		return $xml;
1644
	}
1645
1646
	/**
1647
	 * serializes the attributes for a complexType
1648
	 *
1649
	 * @param array $typeDef our internal representation of an XML schema type (or element)
1650
	 * @param mixed $value a native PHP value (parameter value)
1651
	 * @param string $ns the namespace of the type
1652
	 * @param string $uqType the local part of the type
1653
	 * @return string value serialized as an XML string
1654
	 * @access private
1655
	 */
1656
	function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) {
1657
		$this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
1658
		$xml = '';
1659
		if (isset($typeDef['extensionBase'])) {
1660
			$nsx = $this->getPrefix($typeDef['extensionBase']);
1661
			$uqTypex = $this->getLocalPart($typeDef['extensionBase']);
1662
			if ($this->getNamespaceFromPrefix($nsx)) {
0 ignored issues
show
It seems like $nsx defined by $this->getPrefix($typeDef['extensionBase']) on line 1660 can also be of type false; however, nusoap_base::getNamespaceFromPrefix() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1663
				$nsx = $this->getNamespaceFromPrefix($nsx);
0 ignored issues
show
It seems like $nsx defined by $this->getNamespaceFromPrefix($nsx) on line 1663 can also be of type false; however, nusoap_base::getNamespaceFromPrefix() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1664
			}
1665
			if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
1666
				$this->debug("serialize attributes for extension base $nsx:$uqTypex");
1667
				$xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
1668
			} else {
1669
				$this->debug("extension base $nsx:$uqTypex is not a supported type");
1670
			}
1671
		}
1672
		if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
1673
			$this->debug("serialize attributes for XML Schema type $ns:$uqType");
1674
			if (is_array($value)) {
1675
				$xvalue = $value;
1676
			} elseif (is_object($value)) {
1677
				$xvalue = get_object_vars($value);
1678
			} else {
1679
				$this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
1680
				$xvalue = array();
1681
			}
1682
			foreach ($typeDef['attrs'] as $aName => $attrs) {
1683
				if (isset($xvalue['!' . $aName])) {
1684
					$xname = '!' . $aName;
1685
					$this->debug("value provided for attribute $aName with key $xname");
1686
				} elseif (isset($xvalue[$aName])) {
1687
					$xname = $aName;
1688
					$this->debug("value provided for attribute $aName with key $xname");
1689
				} elseif (isset($attrs['default'])) {
1690
					$xname = '!' . $aName;
1691
					$xvalue[$xname] = $attrs['default'];
1692
					$this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
1693
				} else {
1694
					$xname = '';
1695
					$this->debug("no value provided for attribute $aName");
1696
				}
1697
				if ($xname) {
1698
					$xml .=  " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
1699
				}
1700
			}
1701
		} else {
1702
			$this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
1703
		}
1704
		return $xml;
1705
	}
1706
1707
	/**
1708
	 * serializes the elements for a complexType
1709
	 *
1710
	 * @param array $typeDef our internal representation of an XML schema type (or element)
1711
	 * @param mixed $value a native PHP value (parameter value)
1712
	 * @param string $ns the namespace of the type
1713
	 * @param string $uqType the local part of the type
1714
	 * @param string $use use for part (encoded|literal)
1715
	 * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
1716
	 * @return string value serialized as an XML string
1717
	 * @access private
1718
	 */
1719
	function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) {
1720
		$this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
1721
		$xml = '';
1722
		if (isset($typeDef['extensionBase'])) {
1723
			$nsx = $this->getPrefix($typeDef['extensionBase']);
1724
			$uqTypex = $this->getLocalPart($typeDef['extensionBase']);
1725
			if ($this->getNamespaceFromPrefix($nsx)) {
0 ignored issues
show
It seems like $nsx defined by $this->getPrefix($typeDef['extensionBase']) on line 1723 can also be of type false; however, nusoap_base::getNamespaceFromPrefix() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1726
				$nsx = $this->getNamespaceFromPrefix($nsx);
0 ignored issues
show
It seems like $nsx defined by $this->getNamespaceFromPrefix($nsx) on line 1726 can also be of type false; however, nusoap_base::getNamespaceFromPrefix() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1727
			}
1728
			if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
1729
				$this->debug("serialize elements for extension base $nsx:$uqTypex");
1730
				$xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
1731
			} else {
1732
				$this->debug("extension base $nsx:$uqTypex is not a supported type");
1733
			}
1734
		}
1735
		if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
1736
			$this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
1737
			if (is_array($value)) {
1738
				$xvalue = $value;
1739
			} elseif (is_object($value)) {
1740
				$xvalue = get_object_vars($value);
1741
			} else {
1742
				$this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
1743
				$xvalue = array();
1744
			}
1745
			// toggle whether all elements are present - ideally should validate against schema
1746
			if (count($typeDef['elements']) != count($xvalue)){
1747
				$optionals = true;
1748
			}
1749
			foreach ($typeDef['elements'] as $eName => $attrs) {
1750
				if (!isset($xvalue[$eName])) {
1751
					if (isset($attrs['default'])) {
1752
						$xvalue[$eName] = $attrs['default'];
1753
						$this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
1754
					}
1755
				}
1756
				// if user took advantage of a minOccurs=0, then only serialize named parameters
1757
				if (isset($optionals)
1758
				    && (!isset($xvalue[$eName]))
1759
					&& ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
1760
					){
1761
					if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
1762
						$this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
1763
					}
1764
					// do nothing
1765
					$this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
1766
				} else {
1767
					// get value
1768
					if (isset($xvalue[$eName])) {
1769
					    $v = $xvalue[$eName];
1770
					} else {
1771
					    $v = null;
1772
					}
1773
					if (isset($attrs['form'])) {
1774
						$unqualified = ($attrs['form'] == 'unqualified');
1775
					} else {
1776
						$unqualified = false;
1777
					}
1778
					if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
1779
						$vv = $v;
1780
						foreach ($vv as $k => $v) {
1781
							if (isset($attrs['type']) || isset($attrs['ref'])) {
1782
								// serialize schema-defined type
1783
							    $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
1784
							} else {
1785
								// serialize generic type (can this ever really happen?)
1786
							    $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
1787
							    $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
1788
							}
1789
						}
1790
					} else {
1791
						if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') {
0 ignored issues
show
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1792
							// do nothing
1793
						} elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') {
1794
							// TODO: serialize a nil correctly, but for now serialize schema-defined type
1795
						    $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
1796
						} elseif (isset($attrs['type']) || isset($attrs['ref'])) {
1797
							// serialize schema-defined type
1798
						    $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
1799
						} else {
1800
							// serialize generic type (can this ever really happen?)
1801
						    $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
1802
						    $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
1803
						}
1804
					}
1805
				}
1806
			}
1807
		} else {
1808
			$this->debug("no elements to serialize for XML Schema type $ns:$uqType");
1809
		}
1810
		return $xml;
1811
	}
1812
1813
	/**
1814
	* adds an XML Schema complex type to the WSDL types
1815
	*
1816
	* @param string	$name
1817
	* @param string $typeClass (complexType|simpleType|attribute)
1818
	* @param string $phpType currently supported are array and struct (php assoc array)
1819
	* @param string $compositor (all|sequence|choice)
1820
	* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1821
	* @param array $elements e.g. array ( name => array(name=>'',type=>'') )
1822
	* @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
1823
	* @param string $arrayType as namespace:name (xsd:string)
1824
	* @see nusoap_xmlschema
1825
	* @access public
1826
	*/
1827
	function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') {
1828
		if (count($elements) > 0) {
1829
			$eElements = array();
1830
	    	foreach($elements as $n => $e){
1831
	            // expand each element
1832
	            $ee = array();
1833
	            foreach ($e as $k => $v) {
1834
		            $k = strpos($k,':') ? $this->expandQname($k) : $k;
1835
		            $v = strpos($v,':') ? $this->expandQname($v) : $v;
1836
		            $ee[$k] = $v;
1837
		    	}
1838
	    		$eElements[$n] = $ee;
1839
	    	}
1840
	    	$elements = $eElements;
1841
		}
1842
1843
		if (count($attrs) > 0) {
1844
	    	foreach($attrs as $n => $a){
1845
	            // expand each attribute
1846
	            foreach ($a as $k => $v) {
1847
		            $k = strpos($k,':') ? $this->expandQname($k) : $k;
1848
		            $v = strpos($v,':') ? $this->expandQname($v) : $v;
1849
		            $aa[$k] = $v;
1850
		    	}
1851
	    		$eAttrs[$n] = $aa;
1852
	    	}
1853
	    	$attrs = $eAttrs;
1854
		}
1855
1856
		$restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
1857
		$arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType;
1858
1859
		$typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
1860
		$this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType);
1861
	}
1862
1863
	/**
1864
	* adds an XML Schema simple type to the WSDL types
1865
	*
1866
	* @param string $name
1867
	* @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
1868
	* @param string $typeClass (should always be simpleType)
1869
	* @param string $phpType (should always be scalar)
1870
	* @param array $enumeration array of values
1871
	* @see nusoap_xmlschema
1872
	* @access public
1873
	*/
1874
	function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) {
1875
		$restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase;
1876
1877
		$typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
1878
		$this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
1879
	}
1880
1881
	/**
1882
	* adds an element to the WSDL types
1883
	*
1884
	* @param array $attrs attributes that must include name and type
1885
	* @see nusoap_xmlschema
1886
	* @access public
1887
	*/
1888
	function addElement($attrs) {
1889
		$typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
1890
		$this->schemas[$typens][0]->addElement($attrs);
1891
	}
1892
1893
	/**
1894
	* register an operation with the server
1895
	*
1896
	* @param string $name operation (method) name
1897
	* @param array $in assoc array of input values: key = param name, value = param type
1898
	* @param array $out assoc array of output values: key = param name, value = param type
1899
	* @param string $namespace optional The namespace for the operation
1900
	* @param string $soapaction optional The soapaction for the operation
1901
	* @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
1902
	* @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
1903
	* @param string $documentation optional The description to include in the WSDL
1904
	* @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
1905
	* @access public
1906
	*/
1907
	function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){
1908
		if ($use == 'encoded' && $encodingStyle == '') {
1909
			$encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
1910
		}
1911
1912
		if ($style == 'document') {
1913
			$elements = array();
1914
			foreach ($in as $n => $t) {
0 ignored issues
show
The expression $in of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1915
				$elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
1916
			}
1917
			$this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
1918
			$this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
1919
			$in = array('parameters' => 'tns:' . $name . '^');
1920
1921
			$elements = array();
1922
			foreach ($out as $n => $t) {
0 ignored issues
show
The expression $out of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1923
				$elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
1924
			}
1925
			$this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
1926
			$this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
1927
			$out = array('parameters' => 'tns:' . $name . 'Response' . '^');
1928
		}
1929
1930
		// get binding
1931
		$this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] =
1932
		array(
1933
		'name' => $name,
1934
		'binding' => $this->serviceName . 'Binding',
1935
		'endpoint' => $this->endpoint,
1936
		'soapAction' => $soapaction,
1937
		'style' => $style,
1938
		'input' => array(
1939
			'use' => $use,
1940
			'namespace' => $namespace,
1941
			'encodingStyle' => $encodingStyle,
1942
			'message' => $name . 'Request',
1943
			'parts' => $in),
1944
		'output' => array(
1945
			'use' => $use,
1946
			'namespace' => $namespace,
1947
			'encodingStyle' => $encodingStyle,
1948
			'message' => $name . 'Response',
1949
			'parts' => $out),
1950
		'namespace' => $namespace,
1951
		'transport' => 'http://schemas.xmlsoap.org/soap/http',
1952
		'documentation' => $documentation);
1953
		// add portTypes
1954
		// add messages
1955
		if($in)
1956
		{
1957
			foreach($in as $pName => $pType)
1958
			{
1959
				if(strpos($pType,':')) {
1960
					$pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
0 ignored issues
show
It seems like $this->getPrefix($pType) targeting nusoap_base::getPrefix() can also be of type false; however, nusoap_base::getNamespaceFromPrefix() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1961
				}
1962
				$this->messages[$name.'Request'][$pName] = $pType;
1963
			}
1964
		} else {
1965
            $this->messages[$name.'Request']= '0';
1966
        }
1967
		if($out)
1968
		{
1969
			foreach($out as $pName => $pType)
1970
			{
1971
				if(strpos($pType,':')) {
1972
					$pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType);
0 ignored issues
show
It seems like $this->getPrefix($pType) targeting nusoap_base::getPrefix() can also be of type false; however, nusoap_base::getNamespaceFromPrefix() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1973
				}
1974
				$this->messages[$name.'Response'][$pName] = $pType;
1975
			}
1976
		} else {
1977
            $this->messages[$name.'Response']= '0';
1978
        }
1979
		return true;
1980
	}
1981
}
1982
1983
?>