Completed
Push — master ( 9d3fbd...af269e )
by Michael
09:48
created

Wsdl::getOperationDataForSoapAction()   B

Complexity

Conditions 7
Paths 15

Size

Total Lines 20
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 10
nc 15
nop 2
dl 0
loc 20
rs 8.2222
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 84 and the first side effect is on line 74.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
3
/*
4
5
6
NuSOAP - Web Services Toolkit for PHP
7
8
Copyright (c) 2002 NuSphere Corporation
9
10
This library is free software; you can redistribute it and/or
11
modify it under the terms of the GNU Lesser General Public
12
License as published by the Free Software Foundation; either
13
version 2.1 of the License, or (at your option) any later version.
14
15
This library is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
Lesser General Public License for more details.
19
20
You should have received a copy of the GNU Lesser General Public
21
License along with this library; if not, write to the Free Software
22
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
24
The NuSOAP project home is:
25
http://sourceforge.net/projects/nusoap/
26
27
The primary support for NuSOAP is the Help forum on the project home page.
28
29
If you have any questions or comments, please email:
30
31
Dietrich Ayala
32
[email protected]
33
http://dietrich.ganx4.com/nusoap
34
35
NuSphere Corporation
36
http://www.nusphere.com
37
38
*/
39
40
/*
41
 *  Some of the standards implmented in whole or part by NuSOAP:
42
 *
43
 *  SOAP 1.1 (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
44
 *  WSDL 1.1 (http://www.w3.org/TR/2001/NOTE-wsdl-20010315)
45
 *  SOAP Messages With Attachments (http://www.w3.org/TR/SOAP-attachments)
46
 *  XML 1.0 (http://www.w3.org/TR/2006/REC-xml-20060816/)
47
 *  Namespaces in XML 1.0 (http://www.w3.org/TR/2006/REC-xml-names-20060816/)
48
 *  XML Schema 1.0 (http://www.w3.org/TR/xmlschema-0/)
49
 *  RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies
50
 *  RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1
51
 *  RFC 2617 HTTP Authentication: Basic and Digest Access Authentication
52
 */
53
54
/* load classes
0 ignored issues
show
Unused Code Comprehensibility introduced by
52% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
55
56
// necessary classes
57
require_once('class.soapclient.php');
58
require_once('class.soap_val.php');
59
require_once('class.soap_parser.php');
60
require_once('class.soap_fault.php');
61
62
// transport classes
63
require_once('class.soap_transport_http.php');
64
65
// optional add-on classes
66
require_once('class.xmlschema.php');
67
require_once('class.wsdl.php');
68
69
// server class
70
require_once('class.soap_server.php');*/
71
72
// class variable emulation
73
// cf. http://www.webkreator.com/php/techniques/php-static-class-variables.html
74
$GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = 9;
75
76
/**
77
 *
78
 * nusoap_base
79
 *
80
 * @author   Dietrich Ayala <[email protected]>
81
 * @author   Scott Nichol <[email protected]>
82
 * @access   public
83
 */
84
class Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
85
{
86
    /**
87
     * Identification for HTTP headers.
88
     *
89
     * @var string
90
     * @access private
91
     */
92
    public $title = 'NuSOAP';
93
    /**
94
     * Version for HTTP headers.
95
     *
96
     * @var string
97
     * @access private
98
     */
99
    public $version = '0.9.5';
100
    /**
101
     * CVS revision for HTTP headers.
102
     *
103
     * @var string
104
     * @access private
105
     */
106
    public $revision = '$Revision: 1.123 $';
107
    /**
108
     * Current error string (manipulated by getError/setError)
109
     *
110
     * @var string
111
     * @access private
112
     */
113
    public $error_str = '';
114
    /**
115
     * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
116
     *
117
     * @var string
118
     * @access private
119
     */
120
    public $debug_str = '';
121
    /**
122
     * toggles automatic encoding of special characters as entities
123
     * (should always be true, I think)
124
     *
125
     * @var boolean
126
     * @access private
127
     */
128
    public $charencoding = true;
129
    /**
130
     * the debug level for this instance
131
     *
132
     * @var integer
133
     * @access private
134
     */
135
    public $debugLevel;
136
137
    /**
138
     * set schema version
139
     *
140
     * @var string
141
     * @access   public
142
     */
143
    public $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
144
145
    /**
146
     * charset encoding for outgoing messages
147
     *
148
     * @var string
149
     * @access   public
150
     */
151
    public $soap_defencoding = 'ISO-8859-1';
152
    //var $soap_defencoding = 'UTF-8';
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
153
154
    /**
155
     * namespaces in an array of prefix => uri
156
     *
157
     * this is "seeded" by a set of constants, but it may be altered by code
158
     *
159
     * @var array
160
     * @access   public
161
     */
162
    public $namespaces = array(
163
        'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
164
        'xsd'      => 'http://www.w3.org/2001/XMLSchema',
165
        'xsi'      => 'http://www.w3.org/2001/XMLSchema-instance',
166
        'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
167
    );
168
169
    /**
170
     * namespaces used in the current context, e.g. during serialization
171
     *
172
     * @var array
173
     * @access   private
174
     */
175
    public $usedNamespaces = array();
176
177
    /**
178
     * XML Schema types in an array of uri => (array of xml type => php type)
179
     * is this legacy yet?
180
     * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
181
     * @var array
182
     * @access   public
183
     */
184
    public $typemap = array(
185
        'http://www.w3.org/2001/XMLSchema'          => array(
186
            'string'             => 'string',
187
            'boolean'            => 'boolean',
188
            'float'              => 'double',
189
            'double'             => 'double',
190
            'decimal'            => 'double',
191
            'duration'           => '',
192
            'dateTime'           => 'string',
193
            'time'               => 'string',
194
            'date'               => 'string',
195
            'gYearMonth'         => '',
196
            'gYear'              => '',
197
            'gMonthDay'          => '',
198
            'gDay'               => '',
199
            'gMonth'             => '',
200
            'hexBinary'          => 'string',
201
            'base64Binary'       => 'string',
202
            // abstract "any" types
203
            'anyType'            => 'string',
204
            'anySimpleType'      => 'string',
205
            // derived datatypes
206
            'normalizedString'   => 'string',
207
            'token'              => 'string',
208
            'language'           => '',
209
            'NMTOKEN'            => '',
210
            'NMTOKENS'           => '',
211
            'Name'               => '',
212
            'NCName'             => '',
213
            'ID'                 => '',
214
            'IDREF'              => '',
215
            'IDREFS'             => '',
216
            'ENTITY'             => '',
217
            'ENTITIES'           => '',
218
            'integer'            => 'integer',
219
            'nonPositiveInteger' => 'integer',
220
            'negativeInteger'    => 'integer',
221
            'long'               => 'integer',
222
            'int'                => 'integer',
223
            'short'              => 'integer',
224
            'byte'               => 'integer',
225
            'nonNegativeInteger' => 'integer',
226
            'unsignedLong'       => '',
227
            'unsignedInt'        => '',
228
            'unsignedShort'      => '',
229
            'unsignedByte'       => '',
230
            'positiveInteger'    => ''
231
        ),
232
        'http://www.w3.org/2000/10/XMLSchema'       => array(
233
            'i4'           => '',
234
            'int'          => 'integer',
235
            'boolean'      => 'boolean',
236
            'string'       => 'string',
237
            'double'       => 'double',
238
            'float'        => 'double',
239
            'dateTime'     => 'string',
240
            'timeInstant'  => 'string',
241
            'base64Binary' => 'string',
242
            'base64'       => 'string',
243
            'ur-type'      => 'array'
244
        ),
245
        'http://www.w3.org/1999/XMLSchema'          => array(
246
            'i4'           => '',
247
            'int'          => 'integer',
248
            'boolean'      => 'boolean',
249
            'string'       => 'string',
250
            'double'       => 'double',
251
            'float'        => 'double',
252
            'dateTime'     => 'string',
253
            'timeInstant'  => 'string',
254
            'base64Binary' => 'string',
255
            'base64'       => 'string',
256
            'ur-type'      => 'array'
257
        ),
258
        'http://soapinterop.org/xsd'                => array('SOAPStruct' => 'struct'),
259
        'http://schemas.xmlsoap.org/soap/encoding/' => array(
260
            'base64' => 'string',
261
            'array'  => 'array',
262
            'Array'  => 'array'
263
        ),
264
        'http://xml.apache.org/xml-soap'            => array('Map')
265
    );
266
267
    /**
268
     * XML entities to convert
269
     *
270
     * @var array
271
     * @access   public
272
     * @deprecated
273
     * @see      expandEntities
274
     */
275
    public $xmlEntities = array(
276
        'quot' => '"',
277
        'amp'  => '&',
278
        'lt'   => '<',
279
        'gt'   => '>',
280
        'apos' => "'"
281
    );
282
283
    /**
284
     * constructor
285
     *
286
     * @access   public
287
     */
288
    public function nusoap_base()
0 ignored issues
show
Coding Style introduced by
nusoap_base uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
289
    {
290
        $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
291
    }
292
293
    /**
294
     * gets the global debug level, which applies to future instances
295
     *
296
     * @return integer Debug level 0-9, where 0 turns off
297
     * @access   public
298
     */
299
    public function getGlobalDebugLevel()
0 ignored issues
show
Coding Style introduced by
getGlobalDebugLevel uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
300
    {
301
        return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
302
    }
303
304
    /**
305
     * sets the global debug level, which applies to future instances
306
     *
307
     * @param int $level Debug level 0-9, where 0 turns off
308
     * @access   public
309
     */
310
    public function setGlobalDebugLevel($level)
0 ignored issues
show
Coding Style introduced by
setGlobalDebugLevel uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
311
    {
312
        $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
313
    }
314
315
    /**
316
     * gets the debug level for this instance
317
     *
318
     * @return int Debug level 0-9, where 0 turns off
319
     * @access   public
320
     */
321
    public function getDebugLevel()
322
    {
323
        return $this->debugLevel;
324
    }
325
326
    /**
327
     * sets the debug level for this instance
328
     *
329
     * @param int $level Debug level 0-9, where 0 turns off
330
     * @access   public
331
     */
332
    public function setDebugLevel($level)
333
    {
334
        $this->debugLevel = $level;
335
    }
336
337
    /**
338
     * adds debug data to the instance debug string with formatting
339
     *
340
     * @param string $string debug data
341
     * @access   private
342
     */
343
    public function debug($string)
344
    {
345
        if ($this->debugLevel > 0) {
346
            $this->appendDebug($this->getmicrotime() . ' ' . get_class($this) . ": $string\n");
347
        }
348
    }
349
350
    /**
351
     * adds debug data to the instance debug string without formatting
352
     *
353
     * @param string $string debug data
354
     * @access   public
355
     */
356
    public function appendDebug($string)
357
    {
358
        if ($this->debugLevel > 0) {
359
            // it would be nice to use a memory stream here to use
360
            // memory more efficiently
361
            $this->debug_str .= $string;
362
        }
363
    }
364
365
    /**
366
     * clears the current debug data for this instance
367
     *
368
     * @access   public
369
     */
370
    public function clearDebug()
371
    {
372
        // it would be nice to use a memory stream here to use
373
        // memory more efficiently
374
        $this->debug_str = '';
375
    }
376
377
    /**
378
     * gets the current debug data for this instance
379
     *
380
     * @return debug data
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
381
     * @access   public
382
     */
383
    public function &getDebug()
384
    {
385
        // it would be nice to use a memory stream here to use
386
        // memory more efficiently
387
        return $this->debug_str;
388
    }
389
390
    /**
391
     * gets the current debug data for this instance as an XML comment
392
     * this may change the contents of the debug data
393
     *
394
     * @return debug data as an XML comment
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
395
     * @access   public
396
     */
397
    public function &getDebugAsXMLComment()
398
    {
399
        // it would be nice to use a memory stream here to use
400
        // memory more efficiently
401
        while (strpos($this->debug_str, '--')) {
402
            $this->debug_str = str_replace('--', '- -', $this->debug_str);
403
        }
404
        $ret = "<!--\n" . $this->debug_str . "\n-->";
405
406
        return $ret;
407
    }
408
409
    /**
410
     * expands entities, e.g. changes '<' to '&lt;'.
411
     *
412
     * @param string $val The string in which to expand entities.
413
     * @access   private
414
     * @return mixed|string
415
     */
416
    public function expandEntities($val)
417
    {
418
        if ($this->charencoding) {
419
            $val = str_replace('&', '&amp;', $val);
420
            $val = str_replace("'", '&apos;', $val);
421
            $val = str_replace('"', '&quot;', $val);
422
            $val = str_replace('<', '&lt;', $val);
423
            $val = str_replace('>', '&gt;', $val);
424
        }
425
426
        return $val;
427
    }
428
429
    /**
430
     * returns error string if present
431
     *
432
     * @return mixed error string or false
433
     * @access   public
434
     */
435
    public function getError()
436
    {
437
        if ($this->error_str != '') {
438
            return $this->error_str;
439
        }
440
441
        return false;
442
    }
443
444
    /**
445
     * sets error string
446
     *
447
     * @param $str
448
     * @return bool $string error string
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
449
     * @access   private
450
     */
451
    public function setError($str)
452
    {
453
        $this->error_str = $str;
454
    }
455
456
    /**
457
     * detect if array is a simple array or a struct (associative array)
458
     *
459
     * @param  mixed $val The PHP array
460
     * @return string (arraySimple|arrayStruct)
461
     * @access   private
462
     */
463
    public function isArraySimpleOrStruct($val)
464
    {
465
        $keyList = array_keys($val);
466
        foreach ($keyList as $keyListValue) {
467
            if (!is_int($keyListValue)) {
468
                return 'arrayStruct';
469
            }
470
        }
471
472
        return 'arraySimple';
473
    }
474
475
    /**
476
     * serializes PHP values in accordance w/ section 5. Type information is
477
     * not serialized if $use == 'literal'.
478
     *
479
     * @param  mixed       $val        The value to serialize
480
     * @param  bool|string $name       The name (local part) of the XML element
481
     * @param  bool|string $type       The XML schema type (local part) for the element
482
     * @param  bool|string $name_ns    The namespace for the name of the XML element
483
     * @param  bool|string $type_ns    The namespace for the type of the element
484
     * @param  array|bool  $attributes The attributes to serialize as name=>value pairs
485
     * @param  string      $use        The WSDL "use" (encoded|literal)
486
     * @param  boolean     $soapval    Whether this is called from soapval.
487
     * @return string      The serialized element, possibly with child elements
488
     * @access   public
489
     */
490
    public function serialize_val(
491
        $val,
492
        $name = false,
493
        $type = false,
494
        $name_ns = false,
495
        $type_ns = false,
496
        $attributes = false,
497
        $use = 'encoded',
498
        $soapval = false)
499
    {
500
        $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
501
        $this->appendDebug('value=' . $this->varDump($val));
502
        $this->appendDebug('attributes=' . $this->varDump($attributes));
503
504
        if (is_object($val) && get_class($val) === 'soapval' && (!$soapval)) {
505
            $this->debug('serialize_val: serialize soapval');
506
            $xml = $val->serialize($use);
507
            $this->appendDebug($val->getDebug());
508
            $val->clearDebug();
509
            $this->debug("serialize_val of soapval returning $xml");
510
511
            return $xml;
512
        }
513
        // force valid name if necessary
514
        if (is_numeric($name)) {
515
            $name = '__numeric_' . $name;
516
        } elseif (!$name) {
517
            $name = 'noname';
518
        }
519
        // if name has ns, add ns prefix to name
520
        $xmlns = '';
521
        if ($name_ns) {
522
            $prefix = 'nu' . mt_rand(1000, 9999);
523
            $name   = $prefix . ':' . $name;
524
            $xmlns  .= " xmlns:$prefix=\"$name_ns\"";
525
        }
526
        // if type is prefixed, create type prefix
527
        if ($type_ns != '' && $type_ns == $this->namespaces['xsd']) {
528
            // need to fix this. shouldn't default to xsd if no ns specified
529
            // w/o checking against typemap
530
            $type_prefix = 'xsd';
531
        } elseif ($type_ns) {
532
            $type_prefix = 'ns' . mt_rand(1000, 9999);
533
            $xmlns       .= " xmlns:$type_prefix=\"$type_ns\"";
534
        }
535
        // serialize attributes if present
536
        $atts = '';
537
        if ($attributes) {
538
            foreach ($attributes as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attributes of type 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...
539
                $atts .= " $k=\"" . $this->expandEntities($v) . '"';
540
            }
541
        }
542
        // serialize null value
543
        if (null === $val) {
544
            $this->debug('serialize_val: serialize null');
545
            if ($use === 'literal') {
546
                // TODO: depends on minOccurs
547
                $xml = "<$name$xmlns$atts>";
548
                $this->debug("serialize_val returning $xml");
549
550
                return $xml;
551
            } else {
552
                if (isset($type) && isset($type_prefix)) {
553
                    $type_str = " xsi:type=\"$type_prefix:$type\"";
554
                } else {
555
                    $type_str = '';
556
                }
557
                $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\">";
558
                $this->debug("serialize_val returning $xml");
559
560
                return $xml;
561
            }
562
        }
563
        // serialize if an xsd built-in primitive type
564
        if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])) {
565
            $this->debug('serialize_val: serialize xsd built-in primitive type');
566
            if (is_bool($val)) {
567 View Code Duplication
                if ($type === 'boolean') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
568
                    $val = $val ? 'true' : 'false';
569
                } elseif (!$val) {
570
                    $val = 0;
571
                }
572
            } elseif (is_string($val)) {
573
                $val = $this->expandEntities($val);
574
            }
575
            if ($use === 'literal') {
576
                $xml = "<$name$xmlns$atts>$val</$name>";
577
                $this->debug("serialize_val returning $xml");
578
579
                return $xml;
580
            } else {
581
                $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val</$name>";
582
                $this->debug("serialize_val returning $xml");
583
584
                return $xml;
585
            }
586
        }
587
        // detect type and serialize
588
        $xml = '';
589
        switch (true) {
590
            case (is_bool($val) || $type === 'boolean'):
591
                $this->debug('serialize_val: serialize boolean');
592 View Code Duplication
                if ($type === 'boolean') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
593
                    $val = $val ? 'true' : 'false';
594
                } elseif (!$val) {
595
                    $val = 0;
596
                }
597
                if ($use === 'literal') {
598
                    $xml .= "<$name$xmlns$atts>$val</$name>";
599
                } else {
600
                    $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val</$name>";
601
                }
602
                break;
603 View Code Duplication
            case (is_int($val) || is_int($val) || $type === 'int'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
604
                $this->debug('serialize_val: serialize int');
605
                if ($use === 'literal') {
606
                    $xml .= "<$name$xmlns$atts>$val</$name>";
607
                } else {
608
                    $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val</$name>";
609
                }
610
                break;
611 View Code Duplication
            case (is_float($val) || is_float($val) || $type === 'float'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
612
                $this->debug('serialize_val: serialize float');
613
                if ($use === 'literal') {
614
                    $xml .= "<$name$xmlns$atts>$val</$name>";
615
                } else {
616
                    $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val</$name>";
617
                }
618
                break;
619 View Code Duplication
            case (is_string($val) || $type === 'string'):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
620
                $this->debug('serialize_val: serialize string');
621
                $val = $this->expandEntities($val);
0 ignored issues
show
Bug introduced by
It seems like $val can also be of type array or null or object; however, Nusoap_base::expandEntities() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
622
                if ($use === 'literal') {
623
                    $xml .= "<$name$xmlns$atts>$val</$name>";
624
                } else {
625
                    $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val</$name>";
626
                }
627
                break;
628
            case is_object($val):
629
                $this->debug('serialize_val: serialize object');
630
                if (get_class($val) === 'soapval') {
631
                    $this->debug('serialize_val: serialize soapval object');
632
                    $pXml = $val->serialize($use);
633
                    $this->appendDebug($val->getDebug());
634
                    $val->clearDebug();
635
                } else {
636
                    if (!$name) {
637
                        $name = get_class($val);
638
                        $this->debug("In serialize_val, used class name $name as element name");
639
                    } else {
640
                        $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
641
                    }
642
                    foreach (get_object_vars($val) as $k => $v) {
643
                        $pXml = isset($pXml) ? $pXml . $this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use);
644
                    }
645
                }
646
                if (isset($type) && isset($type_prefix)) {
647
                    $type_str = " xsi:type=\"$type_prefix:$type\"";
648
                } else {
649
                    $type_str = '';
650
                }
651
                if ($use === 'literal') {
652
                    $xml .= "<$name$xmlns$atts>$pXml</$name>";
0 ignored issues
show
Bug introduced by
The variable $pXml does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
653
                } else {
654
                    $xml .= "<$name$xmlns$type_str$atts>$pXml</$name>";
655
                }
656
                break;
657
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
658
            case (is_array($val) || $type):
659
                // detect if struct or array
660
                $valueType = $this->isArraySimpleOrStruct($val);
661
                if ($valueType === 'arraySimple' || preg_match('/^ArrayOf/', $type)) {
662
                    $this->debug('serialize_val: serialize array');
663
                    $i = 0;
664
                    if (is_array($val) && count($val) > 0) {
665
                        foreach ($val as $v) {
666
                            if (is_object($v) && get_class($v) === 'soapval') {
667
                                $tt_ns = $v->type_ns;
668
                                $tt    = $v->type;
669
                            } elseif (is_array($v)) {
670
                                $tt = $this->isArraySimpleOrStruct($v);
671
                            } else {
672
                                $tt = gettype($v);
673
                            }
674
                            $array_types[$tt] = 1;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$array_types was never initialized. Although not strictly required by PHP, it is generally a good practice to add $array_types = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
675
                            // TODO: for literal, the name should be $name
676
                            $xml .= $this->serialize_val($v, 'item', false, false, false, false, $use);
677
                            ++$i;
678
                        }
679
                        if (count($array_types) > 1) {
0 ignored issues
show
Bug introduced by
The variable $array_types does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
680
                            $array_typename = 'xsd:anyType';
681
                        } elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
682
                            if ($tt === 'integer') {
683
                                $tt = 'int';
684
                            }
685
                            $array_typename = 'xsd:' . $tt;
686
                        } elseif (isset($tt) && $tt === 'arraySimple') {
687
                            $array_typename = 'SOAP-ENC:Array';
688
                        } elseif (isset($tt) && $tt === 'arrayStruct') {
689
                            $array_typename = 'unnamed_struct_use_soapval';
690
                        } else {
691
                            // if type is prefixed, create type prefix
692
                            if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']) {
693
                                $array_typename = 'xsd:' . $tt;
0 ignored issues
show
Bug introduced by
The variable $tt does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
694
                            } elseif ($tt_ns) {
0 ignored issues
show
Bug introduced by
The variable $tt_ns does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
695
                                $tt_prefix      = 'ns' . mt_rand(1000, 9999);
696
                                $array_typename = "$tt_prefix:$tt";
697
                                $xmlns          .= " xmlns:$tt_prefix=\"$tt_ns\"";
698
                            } else {
699
                                $array_typename = $tt;
700
                            }
701
                        }
702
                        $array_type = $i;
703 View Code Duplication
                        if ($use === 'literal') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
704
                            $type_str = '';
705
                        } elseif (isset($type) && isset($type_prefix)) {
706
                            $type_str = " xsi:type=\"$type_prefix:$type\"";
707
                        } else {
708
                            $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\"";
709
                        }
710
                        // empty array
711
                    } else {
712 View Code Duplication
                        if ($use === 'literal') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
713
                            $type_str = '';
714
                        } elseif (isset($type) && isset($type_prefix)) {
715
                            $type_str = " xsi:type=\"$type_prefix:$type\"";
716
                        } else {
717
                            $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
718
                        }
719
                    }
720
                    // TODO: for array in literal, there is no wrapper here
721
                    $xml = "<$name$xmlns$type_str$atts>" . $xml . "</$name>";
722
                } else {
723
                    // got a struct
724
                    $this->debug('serialize_val: serialize struct');
725
                    if (isset($type) && isset($type_prefix)) {
726
                        $type_str = " xsi:type=\"$type_prefix:$type\"";
727
                    } else {
728
                        $type_str = '';
729
                    }
730
                    if ($use === 'literal') {
731
                        $xml .= "<$name$xmlns$atts>";
732
                    } else {
733
                        $xml .= "<$name$xmlns$type_str$atts>";
734
                    }
735
                    foreach ($val as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $val of type null|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...
736
                        // Apache Map
737
                        if ($type === 'Map' && $type_ns === 'http://xml.apache.org/xml-soap') {
738
                            $xml .= '<item>';
739
                            $xml .= $this->serialize_val($k, 'key', false, false, false, false, $use);
740
                            $xml .= $this->serialize_val($v, 'value', false, false, false, false, $use);
741
                            $xml .= '</item>';
742 View Code Duplication
                        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
743
                            $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
744
                        }
745
                    }
746
                    $xml .= "</$name>";
747
                }
748
                break;
749
            default:
750
                $this->debug('serialize_val: serialize unknown');
751
                $xml .= 'not detected, got ' . gettype($val) . ' for ' . $val;
752
                break;
753
        }
754
        $this->debug("serialize_val returning $xml");
755
756
        return $xml;
757
    }
758
759
    /**
760
     * serializes a message
761
     *
762
     * @param  string $body          the XML of the SOAP body
763
     * @param  mixed  $headers       optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
764
     * @param  array  $namespaces    optional the namespaces used in generating the body and headers
765
     * @param  string $style         optional (rpc|document)
766
     * @param  string $use           optional (encoded|literal)
767
     * @param  string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
768
     * @return string the message
769
     * @access public
770
     */
771
    public function serializeEnvelope(
772
        $body,
773
        $headers = false,
774
        $namespaces = array(),
775
        $style = 'rpc',
776
        $use = 'encoded',
777
        $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/')
778
    {
779
        // TODO: add an option to automatically run utf8_encode on $body and $headers
780
        // if $this->soap_defencoding is UTF-8.  Not doing this automatically allows
781
        // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
782
783
        $this->debug('In serializeEnvelope length=' . strlen($body) . ' body (max 1000 characters)=' . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
784
        $this->debug('headers:');
785
        $this->appendDebug($this->varDump($headers));
786
        $this->debug('namespaces:');
787
        $this->appendDebug($this->varDump($namespaces));
788
789
        // serialize namespaces
790
        $ns_string = '';
791
        foreach (array_merge($this->namespaces, $namespaces) as $k => $v) {
792
            $ns_string .= " xmlns:$k=\"$v\"";
793
        }
794
        if ($encodingStyle) {
795
            $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
796
        }
797
798
        // serialize headers
799
        if ($headers) {
800
            if (is_array($headers)) {
801
                $xml = '';
802
                foreach ($headers as $k => $v) {
803
                    if (is_object($v) && get_class($v) === 'soapval') {
804
                        $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
805 View Code Duplication
                    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
806
                        $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
807
                    }
808
                }
809
                $headers = $xml;
810
                $this->debug("In serializeEnvelope, serialized array of headers to $headers");
811
            }
812
            $headers = '<SOAP-ENV:Header>' . $headers . '</SOAP-ENV:Header>';
813
        }
814
815
        // serialize envelope
816
        return '<?xml version="1.0" encoding="' . $this->soap_defencoding . '"?' . '>' . '<SOAP-ENV:Envelope' . $ns_string . '>' . $headers . '<SOAP-ENV:Body>' . $body . '</SOAP-ENV:Body>' . '</SOAP-ENV:Envelope>';
817
    }
818
819
    /**
820
     * formats a string to be inserted into an HTML stream
821
     *
822
     * @param  string $str The string to format
823
     * @return string The formatted string
824
     * @access public
825
     * @deprecated
826
     */
827
    public function formatDump($str)
828
    {
829
        $str = htmlspecialchars($str);
830
831
        return nl2br($str);
832
    }
833
834
    /**
835
     * contracts (changes namespace to prefix) a qualified name
836
     *
837
     * @param  string $qname qname
838
     * @return string contracted qname
839
     * @access   private
840
     */
841
    public function contractQname($qname)
842
    {
843
        // get element namespace
844
        //$this->xdebug("Contract $qname");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
845
        if (strrpos($qname, ':')) {
846
            // get unqualified name
847
            $name = substr($qname, strrpos($qname, ':') + 1);
848
            // get ns
849
            $ns = substr($qname, 0, strrpos($qname, ':'));
850
            $p  = $this->getPrefixFromNamespace($ns);
851
            if ($p) {
852
                return $p . ':' . $name;
853
            }
854
855
            return $qname;
856
        } else {
857
            return $qname;
858
        }
859
    }
860
861
    /**
862
     * expands (changes prefix to namespace) a qualified name
863
     *
864
     * @param  string $qname qname
865
     * @return string expanded qname
866
     * @access   private
867
     */
868
    public function expandQname($qname)
869
    {
870
        // get element prefix
871
        if (strpos($qname, ':') && !preg_match('/^http:\/\//', $qname)) {
872
            // get unqualified name
873
            $name = substr(strstr($qname, ':'), 1);
874
            // get ns prefix
875
            $prefix = substr($qname, 0, strpos($qname, ':'));
876
            if (isset($this->namespaces[$prefix])) {
877
                return $this->namespaces[$prefix] . ':' . $name;
878
            } else {
879
                return $qname;
880
            }
881
        } else {
882
            return $qname;
883
        }
884
    }
885
886
    /**
887
     * returns the local part of a prefixed string
888
     * returns the original string, if not prefixed
889
     *
890
     * @param  string $str The prefixed string
891
     * @return string The local part
892
     * @access public
893
     */
894
    public function getLocalPart($str)
895
    {
896
        if ($sstr = strrchr($str, ':')) {
897
            // get unqualified name
898
            return substr($sstr, 1);
899
        } else {
900
            return $str;
901
        }
902
    }
903
904
    /**
905
     * returns the prefix part of a prefixed string
906
     * returns false, if not prefixed
907
     *
908
     * @param  string $str The prefixed string
909
     * @return mixed  The prefix or false if there is no prefix
910
     * @access public
911
     */
912
    public function getPrefix($str)
913
    {
914
        if ($pos = strrpos($str, ':')) {
915
            // get prefix
916
            return substr($str, 0, $pos);
917
        }
918
919
        return false;
920
    }
921
922
    /**
923
     * pass it a prefix, it returns a namespace
924
     *
925
     * @param  string $prefix The prefix
926
     * @return mixed  The namespace, false if no namespace has the specified prefix
927
     * @access public
928
     */
929
    public function getNamespaceFromPrefix($prefix)
930
    {
931
        if (isset($this->namespaces[$prefix])) {
932
            return $this->namespaces[$prefix];
933
        }
934
935
        //$this->setError("No namespace registered for prefix '$prefix'");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
936
        return false;
937
    }
938
939
    /**
940
     * returns the prefix for a given namespace (or prefix)
941
     * or false if no prefixes registered for the given namespace
942
     *
943
     * @param  string $ns The namespace
944
     * @return mixed  The prefix, false if the namespace has no prefixes
945
     * @access public
946
     */
947
    public function getPrefixFromNamespace($ns)
948
    {
949
        foreach ($this->namespaces as $p => $n) {
950
            if ($ns == $n || $ns == $p) {
951
                $this->usedNamespaces[$p] = $n;
952
953
                return $p;
954
            }
955
        }
956
957
        return false;
958
    }
959
960
    /**
961
     * returns the time in ODBC canonical form with microseconds
962
     *
963
     * @return string The time in ODBC canonical form with microseconds
964
     * @access public
965
     */
966
    public function getmicrotime()
967
    {
968
        if (function_exists('gettimeofday')) {
969
            $tod  = gettimeofday();
970
            $sec  = $tod['sec'];
971
            $usec = $tod['usec'];
972
        } else {
973
            $sec  = time();
974
            $usec = 0;
975
        }
976
977
        return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
978
    }
979
980
    /**
981
     * Returns a string with the output of var_dump
982
     *
983
     * @param  mixed $data The variable to var_dump
984
     * @return string The output of var_dump
985
     * @access public
986
     */
987
    public function varDump($data)
988
    {
989
        ob_start();
990
        var_dump($data);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($data); looks like debug code. Are you sure you do not want to remove it? This might expose sensitive data.
Loading history...
991
        $ret_val = ob_get_contents();
992
        ob_end_clean();
993
994
        return $ret_val;
995
    }
996
997
    /**
998
     * represents the object as a string
999
     *
1000
     * @return string
1001
     * @access   public
1002
     */
1003
    public function __toString()
1004
    {
1005
        return $this->varDump($this);
1006
    }
1007
}
1008
1009
// XML Schema Datatype Helper Functions
1010
1011
//xsd:dateTime helpers
1012
1013
/**
1014
 * convert unix timestamp to ISO 8601 compliant date string
1015
 *
1016
 * @param  int     $timestamp Unix time stamp
1017
 * @param  boolean $utc       Whether the time stamp is UTC or local
1018
 * @return mixed   ISO 8601 date string or false
1019
 * @access   public
1020
 */
1021
function timestamp_to_iso8601($timestamp, $utc = true)
1022
{
1023
    $datestr = date('Y-m-d\TH:i:sO', $timestamp);
1024
    $pos     = strrpos($datestr, '+');
1025
    if ($pos === false) {
1026
        $pos = strrpos($datestr, '-');
1027
    }
1028
    if ($pos !== false) {
1029
        if (strlen($datestr) == $pos + 5) {
1030
            $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
1031
        }
1032
    }
1033
    if ($utc) {
1034
        $pattern = '/' . '([0-9]{4})-' .    // centuries & years CCYY-
1035
                   '([0-9]{2})-' .    // months MM-
1036
                   '([0-9]{2})' .    // days DD
1037
                   'T' .            // separator T
1038
                   '([0-9]{2}):' .    // hours hh:
1039
                   '([0-9]{2}):' .    // minutes mm:
1040
                   '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
1041
                   '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1042
                   '/';
1043
1044
        if (preg_match($pattern, $datestr, $regs)) {
1045
            return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
1046
        }
1047
1048
        return false;
1049
    } else {
1050
        return $datestr;
1051
    }
1052
}
1053
1054
/**
1055
 * convert ISO 8601 compliant date string to unix timestamp
1056
 *
1057
 * @param  string $datestr ISO 8601 compliant date string
1058
 * @return mixed  Unix timestamp (int) or false
1059
 * @access   public
1060
 */
1061
function iso8601_to_timestamp($datestr)
1062
{
1063
    $pattern = '/' . '([0-9]{4})-' .    // centuries & years CCYY-
1064
               '([0-9]{2})-' .    // months MM-
1065
               '([0-9]{2})' .    // days DD
1066
               'T' .            // separator T
1067
               '([0-9]{2}):' .    // hours hh:
1068
               '([0-9]{2}):' .    // minutes mm:
1069
               '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
1070
               '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
1071
               '/';
1072
    if (preg_match($pattern, $datestr, $regs)) {
1073
        // not utc
1074
        if ($regs[8] !== 'Z') {
1075
            $op = substr($regs[8], 0, 1);
1076
            $h  = substr($regs[8], 1, 2);
1077
            $m  = substr($regs[8], strlen($regs[8]) - 2, 2);
1078
            if ($op == '-') {
1079
                $regs[4] = $regs[4] + $h;
1080
                $regs[5] = $regs[5] + $m;
1081
            } elseif ($op == '+') {
1082
                $regs[4] = $regs[4] - $h;
1083
                $regs[5] = $regs[5] - $m;
1084
            }
1085
        }
1086
1087
        return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
1088
        //      return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1089
    } else {
1090
        return false;
1091
    }
1092
}
1093
1094
/**
1095
 * sleeps some number of microseconds
1096
 *
1097
 * @param string $usec the number of microseconds to sleep
1098
 * @access   public
1099
 * @deprecated
1100
 */
1101
function usleepWindows($usec)
1102
{
1103
    $start = gettimeofday();
1104
1105
    do {
1106
        $stop       = gettimeofday();
1107
        $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + $stop['usec'] - $start['usec'];
1108
    } while ($timePassed < $usec);
1109
}
1110
1111
?><?php
1112
1113
/**
1114
 * Contains information for a SOAP fault.
1115
 * Mainly used for returning faults from deployed functions
1116
 * in a server instance.
1117
 * @author   Dietrich Ayala <[email protected]>
1118
 * @access   public
1119
 */
1120
class Nusoap_fault extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
1121
{
1122
    /**
1123
     * The fault code (client|server)
1124
     * @var string
1125
     * @access private
1126
     */
1127
    public $faultcode;
1128
    /**
1129
     * The fault actor
1130
     * @var string
1131
     * @access private
1132
     */
1133
    public $faultactor;
1134
    /**
1135
     * The fault string, a description of the fault
1136
     * @var string
1137
     * @access private
1138
     */
1139
    public $faultstring;
1140
    /**
1141
     * The fault detail, typically a string or array of string
1142
     * @var mixed
1143
     * @access private
1144
     */
1145
    public $faultdetail;
1146
1147
    /**
1148
     * constructor
1149
     *
1150
     * @param string $faultcode   (SOAP-ENV:Client | SOAP-ENV:Server)
1151
     * @param string $faultactor  only used when msg routed between multiple actors
1152
     * @param string $faultstring human readable error message
1153
     * @param mixed  $faultdetail detail, typically a string or array of string
1154
     * @return Nusoap_fault
0 ignored issues
show
Documentation introduced by
Should the return type not be Nusoap_fault|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1155
     */
1156
    public function nusoap_fault($faultcode, $faultactor = '', $faultstring = '', $faultdetail = '')
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
1157
    {
1158
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of nusoap_fault()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1159
        $this->faultcode   = $faultcode;
1160
        $this->faultactor  = $faultactor;
1161
        $this->faultstring = $faultstring;
1162
        $this->faultdetail = $faultdetail;
1163
    }
1164
1165
    /**
1166
     * serialize a fault
1167
     *
1168
     * @return string The serialization of the fault instance.
1169
     * @access   public
1170
     */
1171
    public function serialize()
1172
    {
1173
        $ns_string = '';
1174
        foreach ($this->namespaces as $k => $v) {
1175
            $ns_string .= "\n  xmlns:$k=\"$v\"";
1176
        }
1177
        $return_msg = '<?xml version="1.0" encoding="'
1178
                      . $this->soap_defencoding
1179
                      . '"?>'
1180
                      . '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"'
1181
                      . $ns_string
1182
                      . ">\n"
1183
                      . '<SOAP-ENV:Body>'
1184
                      . '<SOAP-ENV:Fault>'
1185
                      . $this->serialize_val($this->faultcode, 'faultcode')
1186
                      . $this->serialize_val($this->faultactor, 'faultactor')
1187
                      . $this->serialize_val($this->faultstring, 'faultstring')
1188
                      . $this->serialize_val($this->faultdetail, 'detail')
1189
                      . '</SOAP-ENV:Fault>'
1190
                      . '</SOAP-ENV:Body>'
1191
                      . '</SOAP-ENV:Envelope>';
1192
1193
        return $return_msg;
1194
    }
1195
}
1196
1197
/**
1198
 * Backward compatibility
1199
 */
1200
class Soap_fault extends Nusoap_fault
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
1201
{
1202
}
1203
1204
?><?php
1205
1206
/**
1207
 * parses an XML Schema, allows access to it's data, other utility methods.
1208
 * imperfect, no validation... yet, but quite functional.
1209
 *
1210
 * @author   Dietrich Ayala <[email protected]>
1211
 * @author   Scott Nichol <[email protected]>
1212
 * @access   public
1213
 */
1214
class Nusoap_xmlschema extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
1215
{
1216
    // files
1217
    public $schema = '';
1218
    public $xml    = '';
1219
    // namespaces
1220
    public $enclosingNamespaces;
1221
    // schema info
1222
    public $schemaInfo            = array();
1223
    public $schemaTargetNamespace = '';
1224
    // types, elements, attributes defined by the schema
1225
    public $attributes         = array();
1226
    public $complexTypes       = array();
1227
    public $complexTypeStack   = array();
1228
    public $currentComplexType = null;
1229
    public $elements           = array();
1230
    public $elementStack       = array();
1231
    public $currentElement     = null;
1232
    public $simpleTypes        = array();
1233
    public $simpleTypeStack    = array();
1234
    public $currentSimpleType  = null;
1235
    // imports
1236
    public $imports = array();
1237
    // parser vars
1238
    public $parser;
1239
    public $position         = 0;
1240
    public $depth            = 0;
1241
    public $depth_array      = array();
1242
    public $message          = array();
1243
    public $defaultNamespace = array();
1244
1245
    /**
1246
     * constructor
1247
     *
1248
     * @param string       $schema     schema document URI
1249
     * @param string       $xml        xml document URI
1250
     * @param array|string $namespaces namespaces defined in enclosing XML
1251
     * @access   public
1252
     * @return Nusoap_xmlschema
0 ignored issues
show
Documentation introduced by
Should the return type not be Nusoap_xmlschema|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
1253
     */
1254
    public function nusoap_xmlschema($schema = '', $xml = '', $namespaces = array())
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
1255
    {
1256
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of nusoap_xmlschema()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1257
        $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1258
        // files
1259
        $this->schema = $schema;
1260
        $this->xml    = $xml;
1261
1262
        // namespaces
1263
        $this->enclosingNamespaces = $namespaces;
1264
        $this->namespaces          = array_merge($this->namespaces, $namespaces);
1265
1266
        // parse schema file
1267
        if ($schema != '') {
1268
            $this->debug('initial schema file: ' . $schema);
1269
            $this->parseFile($schema, 'schema');
1270
        }
1271
1272
        // parse xml file
1273
        if ($xml != '') {
1274
            $this->debug('initial xml file: ' . $xml);
1275
            $this->parseFile($xml, 'xml');
1276
        }
1277
    }
1278
1279
    /**
1280
     * parse an XML file
1281
     *
1282
     * @param  string $xml  path/URL to XML file
1283
     * @param  string $type (schema | xml)
1284
     * @return boolean
1285
     * @access public
1286
     */
1287
    public function parseFile($xml, $type)
1288
    {
1289
        // parse xml file
1290
        if ($xml != '') {
1291
            $xmlStr = @implode('', @file($xml));
1292
            if ($xmlStr == '') {
1293
                $msg = 'Error reading XML from ' . $xml;
1294
                $this->setError($msg);
1295
                $this->debug($msg);
1296
1297
                return false;
1298
            } else {
1299
                $this->debug("parsing $xml");
1300
                $this->parseString($xmlStr, $type);
1301
                $this->debug("done parsing $xml");
1302
1303
                return true;
1304
            }
1305
        }
1306
1307
        return false;
1308
    }
1309
1310
    /**
1311
     * parse an XML string
1312
     *
1313
     * @param string $xml  path or URL
1314
     * @param string $type (schema|xml)
1315
     * @access   private
1316
     */
1317
    public function parseString($xml, $type)
1318
    {
1319
        // parse xml string
1320
        if ($xml != '') {
1321
1322
            // Create an XML parser.
1323
            $this->parser = xml_parser_create();
1324
            // Set the options for parsing the XML data.
1325
            xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1326
1327
            // Set the object for the parser.
1328
            xml_set_object($this->parser, $this);
1329
1330
            // Set the element handlers for the parser.
1331
            if ($type === 'schema') {
1332
                xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
1333
                xml_set_character_data_handler($this->parser, 'schemaCharacterData');
1334
            } elseif ($type === 'xml') {
1335
                xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
1336
                xml_set_character_data_handler($this->parser, 'xmlCharacterData');
1337
            }
1338
1339
            // Parse the XML file.
1340 View Code Duplication
            if (!xml_parse($this->parser, $xml, true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1341
                // Display an error message.
1342
                $errstr = sprintf('XML error parsing XML schema on line %d: %s', xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)));
1343
                $this->debug($errstr);
1344
                $this->debug("XML payload:\n" . $xml);
1345
                $this->setError($errstr);
1346
            }
1347
1348
            xml_parser_free($this->parser);
1349
        } else {
1350
            $this->debug('no xml passed to parseString()!!');
1351
            $this->setError('no xml passed to parseString()!!');
1352
        }
1353
    }
1354
1355
    /**
1356
     * gets a type name for an unnamed type
1357
     *
1358
     * @param   string  Element name
1359
     * @return string A type name for an unnamed type
1360
     * @access  private
1361
     */
1362
    public function CreateTypeName($ename)
1363
    {
1364
        $scope = '';
1365
        for ($i = 0, $iMax = count($this->complexTypeStack); $i < $iMax; ++$i) {
1366
            $scope .= $this->complexTypeStack[$i] . '_';
1367
        }
1368
1369
        return $scope . $ename . '_ContainedType';
1370
    }
1371
1372
    /**
1373
     * start-element handler
1374
     *
1375
     * @param string $parser XML parser object
1376
     * @param string $name   element name
1377
     * @param string $attrs  associative array of attributes
1378
     * @access   private
1379
     */
1380
    public function schemaStartElement($parser, $name, $attrs)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1381
    {
1382
1383
        // position in the total number of elements, starting from 0
1384
        $pos   = $this->position++;
1385
        $depth = $this->depth++;
1386
        // set self as current value for this depth
1387
        $this->depth_array[$depth] = $pos;
1388
        $this->message[$pos]       = array('cdata' => '');
1389
        if ($depth > 0) {
1390
            $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1391
        } else {
1392
            $this->defaultNamespace[$pos] = false;
1393
        }
1394
1395
        // get element prefix
1396
        if ($prefix = $this->getPrefix($name)) {
1397
            // get unqualified name
1398
            $name = $this->getLocalPart($name);
1399
        } else {
1400
            $prefix = '';
1401
        }
1402
1403
        // loop thru attributes, expanding, and registering namespace declarations
1404
        if (count($attrs) > 0) {
1405
            foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
1406
                // if ns declarations, add to class level array of valid namespaces
1407
                if (preg_match('/^xmlns/', $k)) {
1408
                    //$this->xdebug("$k: $v");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1409
                    //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
0 ignored issues
show
Unused Code Comprehensibility introduced by
79% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1410
                    if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
1411
                        //$this->xdebug("Add namespace[$ns_prefix] = $v");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1412
                        $this->namespaces[$ns_prefix] = $v;
1413
                    } else {
1414
                        $this->defaultNamespace[$pos] = $v;
1415
                        if (!$this->getPrefixFromNamespace($v)) {
1416
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
1417
                        }
1418
                    }
1419 View Code Duplication
                    if ($v === 'http://www.w3.org/2001/XMLSchema' || $v === 'http://www.w3.org/1999/XMLSchema'
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1420
                        || $v === 'http://www.w3.org/2000/10/XMLSchema') {
1421
                        $this->XMLSchemaVersion  = $v;
1422
                        $this->namespaces['xsi'] = $v . '-instance';
1423
                    }
1424
                }
1425
            }
1426
            foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
1427
                // expand each attribute
1428
                $k          = strpos($k, ':') ? $this->expandQname($k) : $k;
1429
                $v          = strpos($v, ':') ? $this->expandQname($v) : $v;
1430
                $eAttrs[$k] = $v;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$eAttrs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $eAttrs = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
1431
            }
1432
            $attrs = $eAttrs;
0 ignored issues
show
Bug introduced by
The variable $eAttrs does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1433
        } else {
1434
            $attrs = array();
1435
        }
1436
        // find status, register data
1437
        switch ($name) {
1438
            case 'all':            // (optional) compositor content for a complexType
1439
            case 'choice':
1440
            case 'group':
1441
            case 'sequence':
1442
                //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1443
                $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1444
                //if ($name == 'all' || $name == 'sequence') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1445
                //  $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1446
                //}
1447
                break;
1448
            case 'attribute':    // complexType attribute
1449
                //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
84% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1450
                $this->xdebug('parsing attribute:');
1451
                $this->appendDebug($this->varDump($attrs));
1452
                if (!isset($attrs['form'])) {
1453
                    // TODO: handle globals
1454
                    $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1455
                }
1456
                if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1457
                    $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1458 View Code Duplication
                    if (!strpos($v, ':')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1459
                        // no namespace in arrayType attribute value...
1460
                        if ($this->defaultNamespace[$pos]) {
1461
                            // ...so use the default
1462
                            $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1463
                        }
1464
                    }
1465
                }
1466
                if (isset($attrs['name'])) {
1467
                    $this->attributes[$attrs['name']] = $attrs;
1468
                    $aname                            = $attrs['name'];
1469
                } elseif (isset($attrs['ref'])
1470
                          && $attrs['ref'] === 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') {
1471
                    if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1472
                        $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1473
                    } else {
1474
                        $aname = '';
1475
                    }
1476
                } elseif (isset($attrs['ref'])) {
1477
                    $aname                           = $attrs['ref'];
1478
                    $this->attributes[$attrs['ref']] = $attrs;
1479
                }
1480
1481
                if ($this->currentComplexType) {    // This should *always* be
1482
                    $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
0 ignored issues
show
Bug introduced by
The variable $aname does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1483
                }
1484
                // arrayType attribute
1485
                if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])
1486
                    || $this->getLocalPart($aname) === 'arrayType') {
1487
                    $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1488
                    $prefix                                                   = $this->getPrefix($aname);
0 ignored issues
show
Unused Code introduced by
$prefix is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1489
                    if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1490
                        $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1491
                    } else {
1492
                        $v = '';
1493
                    }
1494
                    if (strpos($v, '[,]')) {
1495
                        $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1496
                    }
1497
                    $v = substr($v, 0, strpos($v, '[')); // clip the []
1498
                    if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
1499
                        $v = $this->XMLSchemaVersion . ':' . $v;
1500
                    }
1501
                    $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1502
                }
1503
                break;
1504
            case 'complexContent':    // (optional) content for a complexType
1505
                $this->xdebug("do nothing for element $name");
1506
                break;
1507
            case 'complexType':
1508
                array_push($this->complexTypeStack, $this->currentComplexType);
1509
                if (isset($attrs['name'])) {
1510
                    // TODO: what is the scope of named complexTypes that appear
1511
                    //       nested within other c complexTypes?
1512
                    $this->xdebug('processing named complexType ' . $attrs['name']);
1513
                    //$this->currentElement = false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1514
                    $this->currentComplexType                                   = $attrs['name'];
1515
                    $this->complexTypes[$this->currentComplexType]              = $attrs;
1516
                    $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1517
                    // This is for constructs like
1518
                    //           <complexType name="ListOfString" base="soap:Array">
1519
                    //                <sequence>
1520
                    //                    <element name="string" type="xsd:string"
1521
                    //                        minOccurs="0" maxOccurs="unbounded">
1522
                    //                </sequence>
1523
                    //            </complexType>
1524 View Code Duplication
                    if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1525
                        $this->xdebug('complexType is unusual array');
1526
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1527
                    } else {
1528
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1529
                    }
1530
                } else {
1531
                    $name = $this->CreateTypeName($this->currentElement);
1532
                    $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1533
                    $this->currentComplexType = $name;
1534
                    //$this->currentElement = false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1535
                    $this->complexTypes[$this->currentComplexType]              = $attrs;
1536
                    $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1537
                    // This is for constructs like
1538
                    //           <complexType name="ListOfString" base="soap:Array">
1539
                    //                <sequence>
1540
                    //                    <element name="string" type="xsd:string"
1541
                    //                        minOccurs="0" maxOccurs="unbounded">
1542
                    //                </sequence>
1543
                    //            </complexType>
1544 View Code Duplication
                    if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1545
                        $this->xdebug('complexType is unusual array');
1546
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1547
                    } else {
1548
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1549
                    }
1550
                }
1551
                $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
1552
                break;
1553
            case 'element':
1554
                array_push($this->elementStack, $this->currentElement);
1555
                if (!isset($attrs['form'])) {
1556
                    if ($this->currentComplexType) {
1557
                        $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1558
                    } else {
1559
                        // global
1560
                        $attrs['form'] = 'qualified';
1561
                    }
1562
                }
1563
                if (isset($attrs['type'])) {
1564
                    $this->xdebug('processing typed element ' . $attrs['name'] . ' of type ' . $attrs['type']);
1565
                    if (!$this->getPrefix($attrs['type'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getPrefix($attrs['type']) of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1566 View Code Duplication
                        if ($this->defaultNamespace[$pos]) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1567
                            $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1568
                            $this->xdebug('used default namespace to make type ' . $attrs['type']);
1569
                        }
1570
                    }
1571
                    // This is for constructs like
1572
                    //           <complexType name="ListOfString" base="soap:Array">
1573
                    //                <sequence>
1574
                    //                    <element name="string" type="xsd:string"
1575
                    //                        minOccurs="0" maxOccurs="unbounded">
1576
                    //                </sequence>
1577
                    //            </complexType>
1578 View Code Duplication
                    if ($this->currentComplexType
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1579
                        && $this->complexTypes[$this->currentComplexType]['phpType'] === 'array') {
1580
                        $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1581
                        $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1582
                    }
1583
                    $this->currentElement = $attrs['name'];
1584
                    $ename                = $attrs['name'];
1585
                } elseif (isset($attrs['ref'])) {
1586
                    $this->xdebug('processing element as ref to ' . $attrs['ref']);
1587
                    $this->currentElement = 'ref to ' . $attrs['ref'];
1588
                    $ename                = $this->getLocalPart($attrs['ref']);
1589
                } else {
1590
                    $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1591
                    $this->xdebug('processing untyped element ' . $attrs['name'] . ' type ' . $type);
1592
                    $this->currentElement = $attrs['name'];
1593
                    $attrs['type']        = $this->schemaTargetNamespace . ':' . $type;
1594
                    $ename                = $attrs['name'];
1595
                }
1596
                if (isset($ename) && $this->currentComplexType) {
1597
                    $this->xdebug("add element $ename to complexType $this->currentComplexType");
1598
                    $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1599
                } elseif (!isset($attrs['ref'])) {
1600
                    $this->xdebug("add element $ename to elements array");
1601
                    $this->elements[$attrs['name']]              = $attrs;
1602
                    $this->elements[$attrs['name']]['typeClass'] = 'element';
1603
                }
1604
                break;
1605
            case 'enumeration':    //   restriction value list member
1606
                $this->xdebug('enumeration ' . $attrs['value']);
1607
                if ($this->currentSimpleType) {
1608
                    $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1609
                } elseif ($this->currentComplexType) {
1610
                    $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1611
                }
1612
                break;
1613
            case 'extension':    // simpleContent or complexContent type extension
1614
                $this->xdebug('extension ' . $attrs['base']);
1615
                if ($this->currentComplexType) {
1616
                    $ns = $this->getPrefix($attrs['base']);
1617
                    if ($ns == '') {
1618
                        $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
1619
                    } else {
1620
                        $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1621
                    }
1622
                } else {
1623
                    $this->xdebug('no current complexType to set extensionBase');
1624
                }
1625
                break;
1626
            case 'import':
1627
                if (isset($attrs['schemaLocation'])) {
1628
                    $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1629
                    $this->imports[$attrs['namespace']][] = array(
1630
                        'location' => $attrs['schemaLocation'],
1631
                        'loaded'   => false
1632
                    );
1633
                } else {
1634
                    $this->xdebug('import namespace ' . $attrs['namespace']);
1635
                    $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1636 View Code Duplication
                    if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1637
                        $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
1638
                    }
1639
                }
1640
                break;
1641
            case 'include':
1642
                if (isset($attrs['schemaLocation'])) {
1643
                    $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
1644
                    $this->imports[$this->schemaTargetNamespace][] = array(
1645
                        'location' => $attrs['schemaLocation'],
1646
                        'loaded'   => false
1647
                    );
1648
                } else {
1649
                    $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
1650
                }
1651
                break;
1652
            case 'list':    // simpleType value list
1653
                $this->xdebug("do nothing for element $name");
1654
                break;
1655
            case 'restriction':    // simpleType, simpleContent or complexContent value restriction
1656
                $this->xdebug('restriction ' . $attrs['base']);
1657
                if ($this->currentSimpleType) {
1658
                    $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1659 View Code Duplication
                } elseif ($this->currentComplexType) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1660
                    $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1661
                    if (strstr($attrs['base'], ':') === ':Array') {
1662
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1663
                    }
1664
                }
1665
                break;
1666
            case 'schema':
1667
                $this->schemaInfo                  = $attrs;
1668
                $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1669
                if (isset($attrs['targetNamespace'])) {
1670
                    $this->schemaTargetNamespace = $attrs['targetNamespace'];
1671
                }
1672
                if (!isset($attrs['elementFormDefault'])) {
1673
                    $this->schemaInfo['elementFormDefault'] = 'unqualified';
1674
                }
1675
                if (!isset($attrs['attributeFormDefault'])) {
1676
                    $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1677
                }
1678
                break;
1679
            case 'simpleContent':    // (optional) content for a complexType
1680
                if ($this->currentComplexType) {    // This should *always* be
1681
                    $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
1682
                } else {
1683
                    $this->xdebug("do nothing for element $name because there is no current complexType");
1684
                }
1685
                break;
1686
            case 'simpleType':
1687
                array_push($this->simpleTypeStack, $this->currentSimpleType);
1688
                if (isset($attrs['name'])) {
1689
                    $this->xdebug('processing simpleType for name ' . $attrs['name']);
1690
                    $this->currentSimpleType                        = $attrs['name'];
1691
                    $this->simpleTypes[$attrs['name']]              = $attrs;
1692
                    $this->simpleTypes[$attrs['name']]['typeClass'] = 'simpleType';
1693
                    $this->simpleTypes[$attrs['name']]['phpType']   = 'scalar';
1694
                } else {
1695
                    $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1696
                    $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1697
                    $this->currentSimpleType = $name;
1698
                    //$this->currentElement = false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1699
                    $this->simpleTypes[$this->currentSimpleType]            = $attrs;
1700
                    $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1701
                }
1702
                break;
1703
            case 'union':    // simpleType type list
1704
                $this->xdebug("do nothing for element $name");
1705
                break;
1706
            default:
1707
                $this->xdebug("do not have any logic to process element $name");
1708
        }
1709
    }
1710
1711
    /**
1712
     * end-element handler
1713
     *
1714
     * @param string $parser XML parser object
1715
     * @param string $name   element name
1716
     * @access   private
1717
     */
1718
    public function schemaEndElement($parser, $name)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1719
    {
1720
        // bring depth down a notch
1721
        $this->depth--;
1722
        // position of current element is equal to the last value left in depth_array for my depth
1723
        if (isset($this->depth_array[$this->depth])) {
1724
            $pos = $this->depth_array[$this->depth];
0 ignored issues
show
Unused Code introduced by
$pos is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1725
        }
1726
        // get element prefix
1727
        if ($prefix = $this->getPrefix($name)) {
0 ignored issues
show
Unused Code introduced by
$prefix is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1728
            // get unqualified name
1729
            $name = $this->getLocalPart($name);
1730
        } else {
1731
            $prefix = '';
0 ignored issues
show
Unused Code introduced by
$prefix is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1732
        }
1733
        // move on...
1734
        if ($name === 'complexType') {
1735
            $this->xdebug('done processing complexType ' . ($this->currentComplexType ?: '(unknown)'));
1736
            $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
1737
            $this->currentComplexType = array_pop($this->complexTypeStack);
1738
            //$this->currentElement = false;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1739
        }
1740
        if ($name === 'element') {
1741
            $this->xdebug('done processing element ' . ($this->currentElement ?: '(unknown)'));
1742
            $this->currentElement = array_pop($this->elementStack);
1743
        }
1744
        if ($name === 'simpleType') {
1745
            $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ?: '(unknown)'));
1746
            $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
1747
            $this->currentSimpleType = array_pop($this->simpleTypeStack);
1748
        }
1749
    }
1750
1751
    /**
1752
     * element content handler
1753
     *
1754
     * @param string $parser XML parser object
1755
     * @param string $data   element content
1756
     * @access   private
1757
     */
1758
    public function schemaCharacterData($parser, $data)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1759
    {
1760
        $pos                          = $this->depth_array[$this->depth - 1];
1761
        $this->message[$pos]['cdata'] .= $data;
1762
    }
1763
1764
    /**
1765
     * serialize the schema
1766
     *
1767
     * @access   public
1768
     */
1769
    public function serializeSchema()
1770
    {
1771
        $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1772
        $xml          = '';
1773
        // imports
1774 View Code Duplication
        if (count($this->imports) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1775
            foreach ($this->imports as $ns => $list) {
1776
                foreach ($list as $ii) {
1777
                    if ($ii['location'] != '') {
1778
                        $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\">\n";
1779
                    } else {
1780
                        $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\">\n";
1781
                    }
1782
                }
1783
            }
1784
        }
1785
        // complex types
1786
        foreach ($this->complexTypes as $typeName => $attrs) {
1787
            $contentStr = '';
1788
            // serialize child elements
1789
            if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
1790
                foreach ($attrs['elements'] as $element => $eParts) {
1791
                    if (isset($eParts['ref'])) {
1792
                        $contentStr .= "   <$schemaPrefix:element ref=\"$element\">\n";
1793
                    } else {
1794
                        $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQname($eParts['type']) . "\"";
1795
                        foreach ($eParts as $aName => $aValue) {
1796
                            // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1797
                            if ($aName !== 'name' && $aName !== 'type') {
1798
                                $contentStr .= " $aName=\"$aValue\"";
1799
                            }
1800
                        }
1801
                        $contentStr .= ">\n";
1802
                    }
1803
                }
1804
                // compositor wraps elements
1805
                if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1806
                    $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . "  </$schemaPrefix:$attrs[compositor]>\n";
1807
                }
1808
            }
1809
            // attributes
1810
            if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
1811
                foreach ($attrs['attrs'] as $attr => $aParts) {
1812
                    $contentStr .= "    <$schemaPrefix:attribute";
1813
                    foreach ($aParts as $a => $v) {
1814
                        if ($a === 'ref' || $a === 'type') {
1815
                            $contentStr .= " $a=\"" . $this->contractQname($v) . '"';
1816
                        } elseif ($a === 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1817
                            $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1818
                            $contentStr                   .= ' wsdl:arrayType="' . $this->contractQname($v) . '"';
1819
                        } else {
1820
                            $contentStr .= " $a=\"$v\"";
1821
                        }
1822
                    }
1823
                    $contentStr .= ">\n";
1824
                }
1825
            }
1826
            // if restriction
1827
            if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
1828
                $contentStr = "   <$schemaPrefix:restriction base=\"" . $this->contractQname($attrs['restrictionBase']) . "\">\n" . $contentStr . "   </$schemaPrefix:restriction>\n";
1829
                // complex or simple content
1830
                if ((isset($attrs['elements']) && count($attrs['elements']) > 0)
1831
                    || (isset($attrs['attrs'])
1832
                        && count($attrs['attrs']) > 0)) {
1833
                    $contentStr = "  <$schemaPrefix:complexContent>\n" . $contentStr . "  </$schemaPrefix:complexContent>\n";
1834
                }
1835
            }
1836
            // finalize complex type
1837
            if ($contentStr != '') {
1838
                $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
1839
            } else {
1840
                $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n";
1841
            }
1842
            $xml .= $contentStr;
1843
        }
1844
        // simple types
1845
        if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
1846
            foreach ($this->simpleTypes as $typeName => $eParts) {
1847
                $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"" . $this->contractQname($eParts['type']) . "\">\n";
1848
                if (isset($eParts['enumeration'])) {
1849
                    foreach ($eParts['enumeration'] as $e) {
1850
                        $xml .= "  <$schemaPrefix:enumeration value=\"$e\">\n";
1851
                    }
1852
                }
1853
                $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1854
            }
1855
        }
1856
        // elements
1857
        if (isset($this->elements) && count($this->elements) > 0) {
1858
            foreach ($this->elements as $element => $eParts) {
1859
                $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQname($eParts['type']) . "\">\n";
1860
            }
1861
        }
1862
        // attributes
1863
        if (isset($this->attributes) && count($this->attributes) > 0) {
1864
            foreach ($this->attributes as $attr => $aParts) {
1865
                $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQname($aParts['type']) . "\"\n>";
1866
            }
1867
        }
1868
        // finish 'er up
1869
        $attr = '';
1870
        foreach ($this->schemaInfo as $k => $v) {
1871
            if ($k === 'elementFormDefault' || $k === 'attributeFormDefault') {
1872
                $attr .= " $k=\"$v\"";
1873
            }
1874
        }
1875
        $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1876
        foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1877
            $el .= " xmlns:$nsp=\"$ns\"";
1878
        }
1879
        $xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
1880
1881
        return $xml;
1882
    }
1883
1884
    /**
1885
     * adds debug data to the clas level debug string
1886
     *
1887
     * @param string $string debug data
1888
     * @access   private
1889
     */
1890
    public function xdebug($string)
1891
    {
1892
        $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
1893
    }
1894
1895
    /**
1896
     * get the PHP type of a user defined type in the schema
1897
     * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1898
     * returns false if no type exists, or not w/ the given namespace
1899
     * else returns a string that is either a native php type, or 'struct'
1900
     *
1901
     * @param  string $type name of defined type
1902
     * @param  string $ns   namespace of type
1903
     * @return mixed
1904
     * @access public
1905
     * @deprecated
1906
     */
1907
    public function getPHPType($type, $ns)
1908
    {
1909
        if (isset($this->typemap[$ns][$type])) {
1910
            //print "found type '$type' and ns $ns in typemap<br>";
1911
            return $this->typemap[$ns][$type];
1912
        } elseif (isset($this->complexTypes[$type])) {
1913
            //print "getting type '$type' and ns $ns from complexTypes array<br>";
1914
            return $this->complexTypes[$type]['phpType'];
1915
        }
1916
1917
        return false;
1918
    }
1919
1920
    /**
1921
     * returns an associative array of information about a given type
1922
     * returns false if no type exists by the given name
1923
     *
1924
     *   For a complexType typeDef = array(
1925
     *   'restrictionBase' => '',
1926
     *   'phpType' => '',
1927
     *   'compositor' => '(sequence|all)',
1928
     *   'elements' => array(), // refs to elements array
1929
     *   'attrs' => array() // refs to attributes array
1930
     *   ... and so on (see addComplexType)
1931
     *   )
1932
     *
1933
     *   For simpleType or element, the array has different keys.
1934
     *
1935
     * @param  string $type
1936
     * @return mixed
1937
     * @access public
1938
     * @see    addComplexType
1939
     * @see    addSimpleType
1940
     * @see    addElement
1941
     */
1942
    public function getTypeDef($type)
1943
    {
1944
        //$this->debug("in getTypeDef for type $type");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1945
        if (substr($type, -1) === '^') {
1946
            $is_element = 1;
1947
            $type       = substr($type, 0, -1);
1948
        } else {
1949
            $is_element = 0;
1950
        }
1951
1952
        if ((!$is_element) && isset($this->complexTypes[$type])) {
1953
            $this->xdebug("in getTypeDef, found complexType $type");
1954
1955
            return $this->complexTypes[$type];
1956
        } elseif ((!$is_element) && isset($this->simpleTypes[$type])) {
1957
            $this->xdebug("in getTypeDef, found simpleType $type");
1958
            if (!isset($this->simpleTypes[$type]['phpType'])) {
1959
                // get info for type to tack onto the simple type
1960
                // TODO: can this ever really apply (i.e. what is a simpleType really?)
1961
                $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1962
                $ns     = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
0 ignored issues
show
Unused Code introduced by
$ns is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1963
                $etype  = $this->getTypeDef($uqType);
1964
                if ($etype) {
1965
                    $this->xdebug("in getTypeDef, found type for simpleType $type:");
1966
                    $this->xdebug($this->varDump($etype));
1967
                    if (isset($etype['phpType'])) {
1968
                        $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1969
                    }
1970
                    if (isset($etype['elements'])) {
1971
                        $this->simpleTypes[$type]['elements'] = $etype['elements'];
1972
                    }
1973
                }
1974
            }
1975
1976
            return $this->simpleTypes[$type];
1977
        } elseif (isset($this->elements[$type])) {
1978
            $this->xdebug("in getTypeDef, found element $type");
1979
            if (!isset($this->elements[$type]['phpType'])) {
1980
                // get info for type to tack onto the element
1981
                $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1982
                $ns     = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1983
                $etype  = $this->getTypeDef($uqType);
1984
                if ($etype) {
1985
                    $this->xdebug("in getTypeDef, found type for element $type:");
1986
                    $this->xdebug($this->varDump($etype));
1987
                    if (isset($etype['phpType'])) {
1988
                        $this->elements[$type]['phpType'] = $etype['phpType'];
1989
                    }
1990
                    if (isset($etype['elements'])) {
1991
                        $this->elements[$type]['elements'] = $etype['elements'];
1992
                    }
1993
                    if (isset($etype['extensionBase'])) {
1994
                        $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
1995
                    }
1996
                } elseif ($ns === 'http://www.w3.org/2001/XMLSchema') {
1997
                    $this->xdebug("in getTypeDef, element $type is an XSD type");
1998
                    $this->elements[$type]['phpType'] = 'scalar';
1999
                }
2000
            }
2001
2002
            return $this->elements[$type];
2003
        } elseif (isset($this->attributes[$type])) {
2004
            $this->xdebug("in getTypeDef, found attribute $type");
2005
2006
            return $this->attributes[$type];
2007
        } elseif (preg_match('/_ContainedType$/', $type)) {
2008
            $this->xdebug("in getTypeDef, have an untyped element $type");
2009
            $typeDef['typeClass'] = 'simpleType';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$typeDef was never initialized. Although not strictly required by PHP, it is generally a good practice to add $typeDef = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2010
            $typeDef['phpType']   = 'scalar';
2011
            $typeDef['type']      = 'http://www.w3.org/2001/XMLSchema:string';
2012
2013
            return $typeDef;
2014
        }
2015
        $this->xdebug("in getTypeDef, did not find $type");
2016
2017
        return false;
2018
    }
2019
2020
    /**
2021
     * returns a sample serialization of a given type, or false if no type by the given name
2022
     *
2023
     * @param  string $type name of type
2024
     * @return mixed
2025
     * @access public
2026
     * @deprecated
2027
     */
2028
    public function serializeTypeDef($type)
2029
    {
2030
        //print "in sTD() for type $type<br>";
2031
        if ($typeDef = $this->getTypeDef($type)) {
2032
            $str .= '<' . $type;
0 ignored issues
show
Bug introduced by
The variable $str does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
2033
            if (is_array($typeDef['attrs'])) {
2034
                foreach ($typeDef['attrs'] as $attName => $data) {
2035
                    $str .= " $attName=\"{type = " . $data['type'] . "}\"";
2036
                }
2037
            }
2038
            $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
2039
            if (count($typeDef['elements']) > 0) {
2040
                $str .= '>';
2041
                foreach ($typeDef['elements'] as $element => $eData) {
2042
                    $str .= $this->serializeTypeDef($element);
0 ignored issues
show
Deprecated Code introduced by
The method Nusoap_xmlschema::serializeTypeDef() has been deprecated.

This method has been deprecated.

Loading history...
2043
                }
2044
                $str .= "</$type>";
2045
            } elseif ($typeDef['typeClass'] === 'element') {
2046
                $str .= "></$type>";
2047
            } else {
2048
                $str .= '>';
2049
            }
2050
2051
            return $str;
2052
        }
2053
2054
        return false;
2055
    }
2056
2057
    /**
2058
     * returns HTML form elements that allow a user
2059
     * to enter values for creating an instance of the given type.
2060
     *
2061
     * @param  string $name name for type instance
2062
     * @param  string $type name of type
2063
     * @return string
2064
     * @access public
2065
     * @deprecated
2066
     */
2067
    public function typeToForm($name, $type)
2068
    {
2069
        // get typedef
2070
        if ($typeDef = $this->getTypeDef($type)) {
2071
            // if struct
2072
            if ($typeDef['phpType'] === 'struct') {
2073
                $buffer .= '<table>';
0 ignored issues
show
Bug introduced by
The variable $buffer does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
2074
                foreach ($typeDef['elements'] as $child => $childDef) {
2075
                    $buffer .= "
2076
                    <tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):</td>
2077
                    <td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
2078
                }
2079
                $buffer .= '</table>';
2080
                // if array
2081
            } elseif ($typeDef['phpType'] === 'array') {
2082
                $buffer .= '<table>';
2083
                for ($i = 0; $i < 3; ++$i) {
2084
                    $buffer .= "
2085
                    <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
2086
                    <td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
2087
                }
2088
                $buffer .= '</table>';
2089
                // if scalar
2090
            } else {
2091
                $buffer .= "<input type='text' name='parameters[$name]'>";
2092
            }
2093
        } else {
2094
            $buffer .= "<input type='text' name='parameters[$name]'>";
2095
        }
2096
2097
        return $buffer;
2098
    }
2099
2100
    /**
2101
     * adds a complex type to the schema
2102
     *
2103
     * example: array
2104
     *
2105
     * addType(
2106
     *   'ArrayOfstring',
2107
     *   'complexType',
2108
     *   'array',
2109
     *   '',
2110
     *   'SOAP-ENC:Array',
2111
     *   array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
2112
     *   'xsd:string'
2113
     * );
2114
     *
2115
     * example: PHP associative array ( SOAP Struct )
2116
     *
2117
     * addType(
2118
     *   'SOAPStruct',
2119
     *   'complexType',
2120
     *   'struct',
2121
     *   'all',
2122
     *   array('myVar'=> array('name'=>'myVar','type'=>'string')
2123
     * );
2124
     *
2125
     * @param                  $name
2126
     * @param string           $typeClass
2127
     * @param string           $phpType
2128
     * @param string           $compositor
2129
     * @param namespace|string $restrictionBase
2130
     * @param array            $elements
2131
     * @param array            $attrs
2132
     * @param string           $arrayType
2133
     * @internal param $name
2134
     * @internal param $typeClass (complexType|simpleType|attribute)
2135
     * @internal param $phpType : currently supported are array and struct (php assoc array)
2136
     * @internal param $compositor (all|sequence|choice)
2137
     * @internal param namespace $restrictionBase :name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2138
     * @internal param $elements = array ( name = array(name=>'',type=>'') )
2139
     * @internal param $attrs = array(
2140
     *       array(
2141
     *       'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
2142
     *       "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
2143
     *       )
2144
     *       )
2145
     * @internal param $arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
2146
     * @access   public
2147
     * @see      getTypeDef
2148
     */
2149
    public function addComplexType(
2150
        $name,
2151
        $typeClass = 'complexType',
2152
        $phpType = 'array',
2153
        $compositor = '',
2154
        $restrictionBase = '',
2155
        $elements = array(),
2156
        $attrs = array(),
2157
        $arrayType = '')
2158
    {
2159
        $this->complexTypes[$name] = array(
2160
            'name'            => $name,
2161
            'typeClass'       => $typeClass,
2162
            'phpType'         => $phpType,
2163
            'compositor'      => $compositor,
2164
            'restrictionBase' => $restrictionBase,
2165
            'elements'        => $elements,
2166
            'attrs'           => $attrs,
2167
            'arrayType'       => $arrayType
2168
        );
2169
2170
        $this->xdebug("addComplexType $name:");
2171
        $this->appendDebug($this->varDump($this->complexTypes[$name]));
2172
    }
2173
2174
    /**
2175
     * adds a simple type to the schema
2176
     *
2177
     * @param string $name
2178
     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2179
     * @param string $typeClass       (should always be simpleType)
2180
     * @param string $phpType         (should always be scalar)
2181
     * @param array  $enumeration     array of values
2182
     * @access public
2183
     * @see    nusoap_xmlschema
2184
     * @see    getTypeDef
2185
     */
2186
    public function addSimpleType(
2187
        $name,
2188
        $restrictionBase = '',
2189
        $typeClass = 'simpleType',
2190
        $phpType = 'scalar',
2191
        $enumeration = array())
2192
    {
2193
        $this->simpleTypes[$name] = array(
2194
            'name'        => $name,
2195
            'typeClass'   => $typeClass,
2196
            'phpType'     => $phpType,
2197
            'type'        => $restrictionBase,
2198
            'enumeration' => $enumeration
2199
        );
2200
2201
        $this->xdebug("addSimpleType $name:");
2202
        $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2203
    }
2204
2205
    /**
2206
     * adds an element to the schema
2207
     *
2208
     * @param array $attrs attributes that must include name and type
2209
     * @see    nusoap_xmlschema
2210
     * @access public
2211
     */
2212
    public function addElement($attrs)
2213
    {
2214
        if (!$this->getPrefix($attrs['type'])) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getPrefix($attrs['type']) of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
2215
            $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2216
        }
2217
        $this->elements[$attrs['name']]              = $attrs;
2218
        $this->elements[$attrs['name']]['typeClass'] = 'element';
2219
2220
        $this->xdebug('addElement ' . $attrs['name']);
2221
        $this->appendDebug($this->varDump($this->elements[$attrs['name']]));
2222
    }
2223
}
2224
2225
/**
2226
 * Backward compatibility
2227
 */
2228
class XMLSchema extends Nusoap_xmlschema
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
2229
{
2230
}
2231
2232
?><?php
2233
2234
/**
2235
 * For creating serializable abstractions of native PHP types.  This class
2236
 * allows element name/namespace, XSD type, and XML attributes to be
2237
 * associated with a value.  This is extremely useful when WSDL is not
2238
 * used, but is also useful when WSDL is used with polymorphic types, including
2239
 * xsd:anyType and user-defined types.
2240
 *
2241
 * @author   Dietrich Ayala <[email protected]>
2242
 * @access   public
2243
 */
2244
class Soapval extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
2245
{
2246
    /**
2247
     * The XML element name
2248
     *
2249
     * @var string
2250
     * @access private
2251
     */
2252
    public $name;
2253
    /**
2254
     * The XML type name (string or false)
2255
     *
2256
     * @var mixed
2257
     * @access private
2258
     */
2259
    public $type;
2260
    /**
2261
     * The PHP value
2262
     *
2263
     * @var mixed
2264
     * @access private
2265
     */
2266
    public $value;
2267
    /**
2268
     * The XML element namespace (string or false)
2269
     *
2270
     * @var mixed
2271
     * @access private
2272
     */
2273
    public $element_ns;
2274
    /**
2275
     * The XML type namespace (string or false)
2276
     *
2277
     * @var mixed
2278
     * @access private
2279
     */
2280
    public $type_ns;
2281
    /**
2282
     * The XML element attributes (array or false)
2283
     *
2284
     * @var mixed
2285
     * @access private
2286
     */
2287
    public $attributes;
2288
2289
    /**
2290
     * constructor
2291
     *
2292
     * @param string $name       optional name
2293
     * @param mixed  $type       optional type name
2294
     * @param mixed  $value      optional value
2295
     * @param mixed  $element_ns optional namespace of value
2296
     * @param mixed  $type_ns    optional namespace of type
2297
     * @param mixed  $attributes associative array of attributes to add to element serialization
2298
     * @access   public
2299
     * @return Soapval
0 ignored issues
show
Documentation introduced by
Should the return type not be Soapval|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2300
     */
2301
    public function soapval(
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
2302
        $name = 'soapval',
2303
        $type = false,
2304
        $value = -1,
2305
        $element_ns = false,
2306
        $type_ns = false,
2307
        $attributes = false)
2308
    {
2309
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of soapval()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2310
        $this->name       = $name;
2311
        $this->type       = $type;
2312
        $this->value      = $value;
2313
        $this->element_ns = $element_ns;
2314
        $this->type_ns    = $type_ns;
2315
        $this->attributes = $attributes;
2316
    }
2317
2318
    /**
2319
     * return serialized value
2320
     *
2321
     * @param  string $use The WSDL use value (encoded|literal)
2322
     * @return string XML data
2323
     * @access   public
2324
     */
2325
    public function serialize($use = 'encoded')
2326
    {
2327
        return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2328
    }
2329
2330
    /**
2331
     * decodes a soapval object into a PHP native type
2332
     *
2333
     * @return mixed
2334
     * @access   public
2335
     */
2336
    public function decode()
2337
    {
2338
        return $this->value;
2339
    }
2340
}
2341
2342
?><?php
2343
2344
/**
2345
 * transport class for sending/receiving data via HTTP and HTTPS
2346
 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
2347
 *
2348
 * @author   Dietrich Ayala <[email protected]>
2349
 * @author   Scott Nichol <[email protected]>
2350
 * @access   public
2351
 */
2352
class Soap_transport_http extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
2353
{
2354
    public $url                  = '';
2355
    public $uri                  = '';
2356
    public $digest_uri           = '';
2357
    public $scheme               = '';
2358
    public $host                 = '';
2359
    public $port                 = '';
2360
    public $path                 = '';
2361
    public $request_method       = 'POST';
2362
    public $protocol_version     = '1.0';
2363
    public $encoding             = '';
2364
    public $outgoing_headers     = array();
2365
    public $incoming_headers     = array();
2366
    public $incoming_cookies     = array();
2367
    public $outgoing_payload     = '';
2368
    public $incoming_payload     = '';
2369
    public $response_status_line;    // HTTP response status line
2370
    public $useSOAPAction        = true;
2371
    public $persistentConnection = false;
2372
    public $ch                   = false;    // cURL handle
2373
    public $ch_options           = array();    // cURL custom options
2374
    public $use_curl             = false;        // force cURL use
2375
    public $proxy                = null;            // proxy information (associative array)
2376
    public $username             = '';
2377
    public $password             = '';
2378
    public $authtype             = '';
2379
    public $digestRequest        = array();
2380
    public $certRequest          = array();    // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2381
    // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2382
    // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2383
    // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2384
    // passphrase: SSL key password/passphrase
2385
    // certpassword: SSL certificate password
2386
    // verifypeer: default is 1
2387
    // verifyhost: default is 1
2388
2389
    /**
2390
     * constructor
2391
     *
2392
     * @param string  $url          The URL to which to connect
2393
     * @param array   $curl_options User-specified cURL options
0 ignored issues
show
Documentation introduced by
Should the type for parameter $curl_options not be array|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
2394
     * @param boolean $use_curl     Whether to try to force cURL use
2395
     * @access public
2396
     * @return Soap_transport_http
0 ignored issues
show
Documentation introduced by
Should the return type not be Soap_transport_http|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2397
     */
2398
    public function soap_transport_http($url, $curl_options = null, $use_curl = false)
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
2399
    {
2400
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of soap_transport_http()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
2401
        $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2402
        $this->appendDebug($this->varDump($curl_options));
2403
        $this->setURL($url);
2404
        if (is_array($curl_options)) {
2405
            $this->ch_options = $curl_options;
2406
        }
2407
        $this->use_curl = $use_curl;
2408
        preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2409
        $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')');
2410
    }
2411
2412
    /**
2413
     * sets a cURL option
2414
     *
2415
     * @param mixed $option The cURL option (always integer?)
2416
     * @param mixed $value  The cURL option value
2417
     * @access   private
2418
     */
2419
    public function setCurlOption($option, $value)
2420
    {
2421
        $this->debug("setCurlOption option=$option, value=");
2422
        $this->appendDebug($this->varDump($value));
2423
        curl_setopt($this->ch, $option, $value);
2424
    }
2425
2426
    /**
2427
     * sets an HTTP header
2428
     *
2429
     * @param string $name  The name of the header
2430
     * @param string $value The value of the header
2431
     * @access private
2432
     */
2433
    public function setHeader($name, $value)
2434
    {
2435
        $this->outgoing_headers[$name] = $value;
2436
        $this->debug("set header $name: $value");
2437
    }
2438
2439
    /**
2440
     * unsets an HTTP header
2441
     *
2442
     * @param string $name The name of the header
2443
     * @access private
2444
     */
2445
    public function unsetHeader($name)
2446
    {
2447
        if (isset($this->outgoing_headers[$name])) {
2448
            $this->debug("unset header $name");
2449
            unset($this->outgoing_headers[$name]);
2450
        }
2451
    }
2452
2453
    /**
2454
     * sets the URL to which to connect
2455
     *
2456
     * @param string $url The URL to which to connect
2457
     * @access private
2458
     */
2459
    public function setURL($url)
2460
    {
2461
        $this->url = $url;
2462
2463
        $u = parse_url($url);
2464
        foreach ($u as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $u of type array<string,string>|false 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...
2465
            $this->debug("parsed URL $k = $v");
2466
            $this->$k = $v;
2467
        }
2468
2469
        // add any GET params to path
2470
        if (isset($u['query']) && $u['query'] != '') {
2471
            $this->path .= '?' . $u['query'];
2472
        }
2473
2474
        // set default port
2475
        if (!isset($u['port'])) {
2476
            if ($u['scheme'] === 'https') {
2477
                $this->port = 443;
0 ignored issues
show
Documentation Bug introduced by
The property $port was declared of type string, but 443 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
2478
            } else {
2479
                $this->port = 80;
0 ignored issues
show
Documentation Bug introduced by
The property $port was declared of type string, but 80 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
2480
            }
2481
        }
2482
2483
        $this->uri        = $this->path;
2484
        $this->digest_uri = $this->uri;
2485
2486
        // build headers
2487
        if (!isset($u['port'])) {
2488
            $this->setHeader('Host', $this->host);
2489
        } else {
2490
            $this->setHeader('Host', $this->host . ':' . $this->port);
2491
        }
2492
2493
        if (isset($u['user']) && $u['user'] != '') {
2494
            $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2495
        }
2496
    }
2497
2498
    /**
2499
     * gets the I/O method to use
2500
     *
2501
     * @return string I/O method to use (socket|curl|unknown)
2502
     * @access   private
2503
     */
2504
    public function io_method()
2505
    {
2506
        if ($this->use_curl || ($this->scheme === 'https') || ($this->scheme === 'http' && $this->authtype === 'ntlm')
2507
            || ($this->scheme === 'http'
2508
                && is_array($this->proxy)
2509
                && $this->proxy['authtype'] === 'ntlm')) {
2510
            return 'curl';
2511
        }
2512
        if (($this->scheme === 'http' || $this->scheme === 'ssl') && $this->authtype !== 'ntlm'
2513
            && (!is_array($this->proxy) || $this->proxy['authtype'] !== 'ntlm')) {
2514
            return 'socket';
2515
        }
2516
2517
        return 'unknown';
2518
    }
2519
2520
    /**
2521
     * establish an HTTP connection
2522
     *
2523
     * @param  int     $connection_timeout
2524
     * @param  integer $response_timeout set response timeout in seconds
2525
     * @return bool    true if connected, false if not
2526
     * @internal param int $timeout set connection timeout in seconds
2527
     * @access   private
2528
     */
2529
    public function connect($connection_timeout = 0, $response_timeout = 30)
2530
    {
2531
        // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2532
        // "regular" socket.
2533
        // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2534
        //       loaded), and until PHP5 stream_get_wrappers is not available.
2535
        //      if ($this->scheme == 'https') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2536
        //          if (version_compare(PHP_VERSION, '4.3.0') >= 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2537
        //              if (extension_loaded('openssl')) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2538
        //                  $this->scheme = 'ssl';
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2539
        //                  $this->debug('Using SSL over OpenSSL');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2540
        //              }
2541
        //          }
2542
        //      }
2543
        $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2544
        if ($this->io_method() === 'socket') {
2545
            if (!is_array($this->proxy)) {
2546
                $host = $this->host;
2547
                $port = $this->port;
0 ignored issues
show
Unused Code introduced by
$port is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2548
            } else {
2549
                $host = $this->proxy['host'];
2550
                $port = $this->proxy['port'];
0 ignored issues
show
Unused Code introduced by
$port is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2551
            }
2552
2553
            // use persistent connection
2554
            if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
2555
                if (!feof($this->fp)) {
0 ignored issues
show
Bug introduced by
The property fp does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2556
                    $this->debug('Re-use persistent connection');
2557
2558
                    return true;
2559
                }
2560
                fclose($this->fp);
2561
                $this->debug('Closed persistent connection at EOF');
2562
            }
2563
2564
            // munge host if using OpenSSL
2565
            if ($this->scheme === 'ssl') {
2566
                $host = 'ssl://' . $host;
2567
            }
2568
            $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2569
2570
            // open socket
2571
            if ($connection_timeout > 0) {
2572
                $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
0 ignored issues
show
Bug introduced by
The property errno does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2573
            } else {
2574
                $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
2575
            }
2576
2577
            // test pointer
2578
            if (!$this->fp) {
2579
                $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2580
                if ($this->errno) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->errno of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
2581
                    $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
2582
                } else {
2583
                    $msg .= ' prior to connect().  This is often a problem looking up the host name.';
2584
                }
2585
                $this->debug($msg);
2586
                $this->setError($msg);
2587
2588
                return false;
2589
            }
2590
2591
            // set response timeout
2592
            $this->debug('set response timeout to ' . $response_timeout);
2593
            socket_set_timeout($this->fp, $response_timeout);
2594
2595
            $this->debug('socket connected');
2596
2597
            return true;
2598
        } elseif ($this->io_method() === 'curl') {
2599
            if (!extension_loaded('curl')) {
2600
                //          $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2601
                $this->setError('The PHP cURL Extension is required for HTTPS or NLTM.  You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.');
2602
2603
                return false;
2604
            }
2605
            // Avoid warnings when PHP does not have these options
2606
            if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
2607
                $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2608
            } else {
2609
                $CURLOPT_CONNECTIONTIMEOUT = 78;
2610
            }
2611
            if (defined('CURLOPT_HTTPAUTH')) {
2612
                $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2613
            } else {
2614
                $CURLOPT_HTTPAUTH = 107;
2615
            }
2616
            if (defined('CURLOPT_PROXYAUTH')) {
2617
                $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2618
            } else {
2619
                $CURLOPT_PROXYAUTH = 111;
2620
            }
2621
            if (defined('CURLAUTH_BASIC')) {
2622
                $CURLAUTH_BASIC = CURLAUTH_BASIC;
2623
            } else {
2624
                $CURLAUTH_BASIC = 1;
2625
            }
2626
            if (defined('CURLAUTH_DIGEST')) {
2627
                $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2628
            } else {
2629
                $CURLAUTH_DIGEST = 2;
2630
            }
2631
            if (defined('CURLAUTH_NTLM')) {
2632
                $CURLAUTH_NTLM = CURLAUTH_NTLM;
2633
            } else {
2634
                $CURLAUTH_NTLM = 8;
2635
            }
2636
2637
            $this->debug('connect using cURL');
2638
            // init CURL
2639
            $this->ch = curl_init();
0 ignored issues
show
Documentation Bug introduced by
It seems like curl_init() of type resource is incompatible with the declared type boolean of property $ch.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
2640
            // set url
2641
            $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2642
            // add path
2643
            $hostURL .= $this->path;
2644
            $this->setCurlOption(CURLOPT_URL, $hostURL);
2645
            // follow location headers (re-directs)
2646
            // if (ini_get('safe_mode') || ini_get('open_basedir')) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2647
            //    $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2648
            //    $this->debug('safe_mode = ');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2649
            //    $this->appendDebug($this->varDump(ini_get('safe_mode')));
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2650
            //    $this->debug('open_basedir = ');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2651
            //    $this->appendDebug($this->varDump(ini_get('open_basedir')));
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2652
            // } else {
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2653
                $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2654
            //}
2655
            // ask for headers in the response output
2656
            $this->setCurlOption(CURLOPT_HEADER, 1);
2657
            // ask for the response output as the return value
2658
            $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2659
            // encode
2660
            // We manage this ourselves through headers and encoding
2661
            //      if (function_exists('gzuncompress')) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2662
            //          $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2663
            //      }
2664
            // persistent connection
2665
            if ($this->persistentConnection) {
2666
                // I believe the following comment is now bogus, having applied to
2667
                // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2668
                // The way we send data, we cannot use persistent connections, since
2669
                // there will be some "junk" at the end of our request.
2670
                //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2671
                $this->persistentConnection = false;
2672
                $this->setHeader('Connection', 'close');
2673
            }
2674
            // set timeouts
2675
            if ($connection_timeout != 0) {
2676
                $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2677
            }
2678
            if ($response_timeout != 0) {
2679
                $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2680
            }
2681
2682
            if ($this->scheme === 'https') {
2683
                $this->debug('set cURL SSL verify options');
2684
                // recent versions of cURL turn on peer/host checking by default,
2685
                // while PHP binaries are not compiled with a default location for the
2686
                // CA cert bundle, so disable peer/host checking.
2687
                //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2688
                $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2689
                $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2690
2691
                // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2692
                if ($this->authtype === 'certificate') {
2693
                    $this->debug('set cURL certificate options');
2694
                    if (isset($this->certRequest['cainfofile'])) {
2695
                        $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2696
                    }
2697
                    if (isset($this->certRequest['verifypeer'])) {
2698
                        $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2699
                    } else {
2700
                        $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2701
                    }
2702
                    if (isset($this->certRequest['verifyhost'])) {
2703
                        $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2704
                    } else {
2705
                        $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2706
                    }
2707
                    if (isset($this->certRequest['sslcertfile'])) {
2708
                        $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2709
                    }
2710
                    if (isset($this->certRequest['sslkeyfile'])) {
2711
                        $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2712
                    }
2713
                    if (isset($this->certRequest['passphrase'])) {
2714
                        $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2715
                    }
2716
                    if (isset($this->certRequest['certpassword'])) {
2717
                        $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2718
                    }
2719
                }
2720
            }
2721
            if ($this->authtype && ($this->authtype !== 'certificate')) {
2722
                if ($this->username) {
2723
                    $this->debug('set cURL username/password');
2724
                    $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2725
                }
2726
                if ($this->authtype === 'basic') {
2727
                    $this->debug('set cURL for Basic authentication');
2728
                    $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2729
                }
2730
                if ($this->authtype === 'digest') {
2731
                    $this->debug('set cURL for digest authentication');
2732
                    $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2733
                }
2734
                if ($this->authtype === 'ntlm') {
2735
                    $this->debug('set cURL for NTLM authentication');
2736
                    $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2737
                }
2738
            }
2739
            if (is_array($this->proxy)) {
2740
                $this->debug('set cURL proxy options');
2741
                if ($this->proxy['port'] != '') {
2742
                    $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']);
2743
                } else {
2744
                    $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2745
                }
2746
                if ($this->proxy['username'] || $this->proxy['password']) {
2747
                    $this->debug('set cURL proxy authentication options');
2748
                    $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']);
2749
                    if ($this->proxy['authtype'] === 'basic') {
2750
                        $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2751
                    }
2752
                    if ($this->proxy['authtype'] === 'ntlm') {
2753
                        $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2754
                    }
2755
                }
2756
            }
2757
            $this->debug('cURL connection set up');
2758
2759
            return true;
2760
        } else {
2761
            $this->setError('Unknown scheme ' . $this->scheme);
2762
            $this->debug('Unknown scheme ' . $this->scheme);
2763
2764
            return false;
2765
        }
2766
    }
2767
2768
    /**
2769
     * sends the SOAP request and gets the SOAP response via HTTP[S]
2770
     *
2771
     * @param  string  $data             message data
2772
     * @param  integer $timeout          set connection timeout in seconds
2773
     * @param  integer $response_timeout set response timeout in seconds
2774
     * @param  array   $cookies          cookies to send
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cookies not be array|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
2775
     * @return string  data
0 ignored issues
show
Documentation introduced by
Should the return type not be false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2776
     * @access   public
2777
     */
2778
    public function send($data, $timeout = 0, $response_timeout = 30, $cookies = null)
2779
    {
2780
        $this->debug('entered send() with data of length: ' . strlen($data));
2781
2782
        $this->tryagain = true;
0 ignored issues
show
Bug introduced by
The property tryagain does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
2783
        $tries          = 0;
2784
        while ($this->tryagain) {
2785
            $this->tryagain = false;
2786
            if (++$tries < 2) {
2787
                // make connnection
2788
                if (!$this->connect($timeout, $response_timeout)) {
2789
                    return false;
2790
                }
2791
2792
                // send request
2793
                if (!$this->sendRequest($data, $cookies)) {
2794
                    return false;
2795
                }
2796
2797
                // get response
2798
                $respdata = $this->getResponse();
2799
            } else {
2800
                $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2801
            }
2802
        }
2803
        $this->debug('end of send()');
2804
2805
        return $respdata;
0 ignored issues
show
Bug introduced by
The variable $respdata does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2806
    }
2807
2808
    /**
2809
     * sends the SOAP request and gets the SOAP response via HTTPS using CURL
2810
     *
2811
     * @param  string  $data             message data
2812
     * @param  integer $timeout          set connection timeout in seconds
2813
     * @param  integer $response_timeout set response timeout in seconds
2814
     * @param  array   $cookies          cookies to send
2815
     * @return string  data
0 ignored issues
show
Documentation introduced by
Should the return type not be false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
2816
     * @access   public
2817
     * @deprecated
2818
     */
2819
    public function sendHTTPS($data, $timeout = 0, $response_timeout = 30, $cookies)
2820
    {
2821
        return $this->send($data, $timeout, $response_timeout, $cookies);
2822
    }
2823
2824
    /**
2825
     * if authenticating, set user credentials here
2826
     *
2827
     * @param string $username
2828
     * @param string $password
2829
     * @param string $authtype      (basic|digest|certificate|ntlm)
2830
     * @param array  $digestRequest (keys must be nonce, nc, realm, qop)
2831
     * @param array  $certRequest   (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
2832
     * @access   public
2833
     */
2834
    public function setCredentials(
2835
        $username,
2836
        $password,
2837
        $authtype = 'basic',
2838
        $digestRequest = array(),
2839
        $certRequest = array())
2840
    {
2841
        $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2842
        $this->appendDebug($this->varDump($digestRequest));
2843
        $this->debug('certRequest=');
2844
        $this->appendDebug($this->varDump($certRequest));
2845
        // cf. RFC 2617
2846
        if ($authtype === 'basic') {
2847
            $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password));
2848
        } elseif ($authtype === 'digest') {
2849
            if (isset($digestRequest['nonce'])) {
2850
                $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2851
2852
                // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2853
2854
                // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2855
                $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2856
2857
                // H(A1) = MD5(A1)
2858
                $HA1 = md5($A1);
2859
2860
                // A2 = Method ":" digest-uri-value
2861
                $A2 = $this->request_method . ':' . $this->digest_uri;
2862
2863
                // H(A2)
2864
                $HA2 = md5($A2);
2865
2866
                // KD(secret, data) = H(concat(secret, ":", data))
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2867
                // if qop == auth:
2868
                // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
2869
                //                              ":" nc-value
2870
                //                              ":" unq(cnonce-value)
2871
                //                              ":" unq(qop-value)
2872
                //                              ":" H(A2)
0 ignored issues
show
Unused Code Comprehensibility introduced by
43% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2873
                //                            ) <">
2874
                // if qop is missing,
2875
                // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2876
2877
                $unhashedDigest = '';
0 ignored issues
show
Unused Code introduced by
$unhashedDigest is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2878
                $nonce          = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2879
                $cnonce         = $nonce;
2880
                if ($digestRequest['qop'] != '') {
2881
                    $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf('%08d', $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2882
                } else {
2883
                    $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2884
                }
2885
2886
                $hashedDigest = md5($unhashedDigest);
2887
2888
                $opaque = '';
2889
                if (isset($digestRequest['opaque'])) {
2890
                    $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2891
                }
2892
2893
                $this->setHeader('Authorization', 'Digest username="'
2894
                                                  . $username
2895
                                                  . '", realm="'
2896
                                                  . $digestRequest['realm']
2897
                                                  . '", nonce="'
2898
                                                  . $nonce
2899
                                                  . '", uri="'
2900
                                                  . $this->digest_uri
2901
                                                  . $opaque
2902
                                                  . '", cnonce="'
2903
                                                  . $cnonce
2904
                                                  . '", nc='
2905
                                                  . sprintf('%08x', $digestRequest['nc'])
2906
                                                  . ', qop="'
2907
                                                  . $digestRequest['qop']
2908
                                                  . '", response="'
2909
                                                  . $hashedDigest
2910
                                                  . '"');
2911
            }
2912
        } elseif ($authtype === 'certificate') {
2913
            $this->certRequest = $certRequest;
2914
            $this->debug('Authorization header not set for certificate');
2915
        } elseif ($authtype === 'ntlm') {
2916
            // do nothing
2917
            $this->debug('Authorization header not set for ntlm');
2918
        }
2919
        $this->username      = $username;
2920
        $this->password      = $password;
2921
        $this->authtype      = $authtype;
2922
        $this->digestRequest = $digestRequest;
2923
    }
2924
2925
    /**
2926
     * set the soapaction value
2927
     *
2928
     * @param string $soapaction
2929
     * @access   public
2930
     */
2931
    public function setSOAPAction($soapaction)
2932
    {
2933
        $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2934
    }
2935
2936
    /**
2937
     * use http encoding
2938
     *
2939
     * @param string $enc encoding style. supported values: gzip, deflate, or both
2940
     * @access   public
2941
     */
2942
    public function setEncoding($enc = 'gzip, deflate')
2943
    {
2944
        if (function_exists('gzdeflate')) {
2945
            $this->protocol_version = '1.1';
2946
            $this->setHeader('Accept-Encoding', $enc);
2947
            if (!isset($this->outgoing_headers['Connection'])) {
2948
                $this->setHeader('Connection', 'close');
2949
                $this->persistentConnection = false;
2950
            }
2951
            // deprecated as of PHP 5.3.0
2952
            //set_magic_quotes_runtime(0);
2953
            $this->encoding = $enc;
2954
        }
2955
    }
2956
2957
    /**
2958
     * set proxy info here
2959
     *
2960
     * @param string $proxyhost     use an empty string to remove proxy
2961
     * @param string $proxyport
2962
     * @param string $proxyusername
2963
     * @param string $proxypassword
2964
     * @param string $proxyauthtype (basic|ntlm)
2965
     * @access   public
2966
     */
2967
    public function setProxy(
2968
        $proxyhost,
2969
        $proxyport,
2970
        $proxyusername = '',
2971
        $proxypassword = '',
2972
        $proxyauthtype = 'basic')
2973
    {
2974
        if ($proxyhost) {
2975
            $this->proxy = array(
2976
                'host'     => $proxyhost,
2977
                'port'     => $proxyport,
2978
                'username' => $proxyusername,
2979
                'password' => $proxypassword,
2980
                'authtype' => $proxyauthtype
2981
            );
2982
            if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2983
                $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword));
2984
            }
2985
        } else {
2986
            $this->debug('remove proxy');
2987
            $proxy = null;
0 ignored issues
show
Unused Code introduced by
$proxy is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
2988
            unsetHeader('Proxy-Authorization');
2989
        }
2990
    }
2991
2992
    /**
2993
     * Test if the given string starts with a header that is to be skipped.
2994
     * Skippable headers result from chunked transfer and proxy requests.
2995
     *
2996
     * @param string $data The string to check.
2997
     * @returns boolean Whether a skippable header was found.
2998
     * @access  private
2999
     */
3000
    public function isSkippableCurlHeader(&$data)
3001
    {
3002
        $skipHeaders = array(
3003
            'HTTP/1.1 100',
3004
            'HTTP/1.0 301',
3005
            'HTTP/1.1 301',
3006
            'HTTP/1.0 302',
3007
            'HTTP/1.1 302',
3008
            'HTTP/1.0 401',
3009
            'HTTP/1.1 401',
3010
            'HTTP/1.0 200 Connection established'
3011
        );
3012
        foreach ($skipHeaders as $hd) {
3013
            $prefix = substr($data, 0, strlen($hd));
3014
            if ($prefix == $hd) {
3015
                return true;
3016
            }
3017
        }
3018
3019
        return false;
3020
    }
3021
3022
    /**
3023
     * decode a string that is encoded w/ "chunked' transfer encoding
3024
     * as defined in RFC2068 19.4.6
3025
     *
3026
     * @param string $buffer
3027
     * @param string $lb
3028
     * @returns  string
3029
     * @access   public
3030
     * @deprecated
3031
     */
3032
    public function decodeChunked($buffer, $lb)
3033
    {
3034
        // length := 0
3035
        $length = 0;
3036
        $new    = '';
3037
3038
        // read chunk-size, chunk-extension (if any) and CRLF
3039
        // get the position of the linebreak
3040
        $chunkend = strpos($buffer, $lb);
3041
        if (false === $chunkend) {
3042
            $this->debug('no linebreak found in decodeChunked');
3043
3044
            return $new;
3045
        }
3046
        $temp       = substr($buffer, 0, $chunkend);
3047
        $chunk_size = hexdec(trim($temp));
3048
        $chunkstart = $chunkend + strlen($lb);
3049
        // while (chunk-size > 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3050
        while ($chunk_size > 0) {
3051
            $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
3052
            $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
3053
3054
            // Just in case we got a broken connection
3055
            if (false === $chunkend) {
3056
                $chunk = substr($buffer, $chunkstart);
3057
                // append chunk-data to entity-body
3058
                $new    .= $chunk;
3059
                $length += strlen($chunk);
3060
                break;
3061
            }
3062
3063
            // read chunk-data and CRLF
3064
            $chunk = substr($buffer, $chunkstart, $chunkend - $chunkstart);
3065
            // append chunk-data to entity-body
3066
            $new .= $chunk;
3067
            // length := length + chunk-size
3068
            $length += strlen($chunk);
3069
            // read chunk-size and CRLF
3070
            $chunkstart = $chunkend + strlen($lb);
3071
3072
            $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
3073
            if (false === $chunkend) {
3074
                break; //Just in case we got a broken connection
3075
            }
3076
            $temp       = substr($buffer, $chunkstart, $chunkend - $chunkstart);
3077
            $chunk_size = hexdec(trim($temp));
3078
            $chunkstart = $chunkend;
3079
        }
3080
3081
        return $new;
3082
    }
3083
3084
    /**
3085
     * Writes the payload, including HTTP headers, to $this->outgoing_payload.
3086
     *
3087
     * @param  string $data       HTTP body
3088
     * @param  string $cookie_str data for HTTP Cookie header
3089
     * @return void
3090
     * @access  private
3091
     */
3092
    public function buildPayload($data, $cookie_str = '')
3093
    {
3094
        // Note: for cURL connections, $this->outgoing_payload is ignored,
3095
        // as is the Content-Length header, but these are still created as
3096
        // debugging guides.
3097
3098
        // add content-length header
3099
        if ($this->request_method !== 'GET') {
3100
            $this->setHeader('Content-Length', strlen($data));
3101
        }
3102
3103
        // start building outgoing payload:
3104
        if ($this->proxy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->proxy of type array<string,string> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3105
            $uri = $this->url;
3106
        } else {
3107
            $uri = $this->uri;
3108
        }
3109
        $req = "$this->request_method $uri HTTP/$this->protocol_version";
3110
        $this->debug("HTTP request: $req");
3111
        $this->outgoing_payload = "$req\r\n";
3112
3113
        // loop thru headers, serializing
3114
        foreach ($this->outgoing_headers as $k => $v) {
3115
            $hdr = $k . ': ' . $v;
3116
            $this->debug("HTTP header: $hdr");
3117
            $this->outgoing_payload .= "$hdr\r\n";
3118
        }
3119
3120
        // add any cookies
3121
        if ($cookie_str != '') {
3122
            $hdr = 'Cookie: ' . $cookie_str;
3123
            $this->debug("HTTP header: $hdr");
3124
            $this->outgoing_payload .= "$hdr\r\n";
3125
        }
3126
3127
        // header/body separator
3128
        $this->outgoing_payload .= "\r\n";
3129
3130
        // add data
3131
        $this->outgoing_payload .= $data;
3132
    }
3133
3134
    /**
3135
     * sends the SOAP request via HTTP[S]
3136
     *
3137
     * @param  string $data    message data
3138
     * @param  array  $cookies cookies to send
0 ignored issues
show
Documentation introduced by
Should the type for parameter $cookies not be array|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
3139
     * @return boolean true if OK, false if problem
0 ignored issues
show
Documentation introduced by
Should the return type not be boolean|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
3140
     * @access   private
3141
     */
3142
    public function sendRequest($data, $cookies = null)
3143
    {
3144
        // build cookie string
3145
        $cookie_str = $this->getCookiesForRequest($cookies, ($this->scheme === 'ssl') || ($this->scheme === 'https'));
0 ignored issues
show
Bug introduced by
It seems like $cookies defined by parameter $cookies on line 3142 can also be of type null; however, Soap_transport_http::getCookiesForRequest() does only seem to accept array, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
3146
3147
        // build payload
3148
        $this->buildPayload($data, $cookie_str);
3149
3150
        if ($this->io_method() === 'socket') {
3151
            // send payload
3152
            if (!fwrite($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
3153
                $this->setError('couldn\'t write message data to socket');
3154
                $this->debug('couldn\'t write message data to socket');
3155
3156
                return false;
3157
            }
3158
            $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
3159
3160
            return true;
3161
        } elseif ($this->io_method() === 'curl') {
3162
            // set payload
3163
            // cURL does say this should only be the verb, and in fact it
3164
            // turns out that the URI and HTTP version are appended to this, which
3165
            // some servers refuse to work with (so we no longer use this method!)
3166
            //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3167
            $curl_headers = array();
3168
            foreach ($this->outgoing_headers as $k => $v) {
3169
                if ($k === 'Connection' || $k === 'Content-Length' || $k === 'Host' || $k === 'Authorization'
3170
                    || $k === 'Proxy-Authorization') {
3171
                    $this->debug("Skip cURL header $k: $v");
3172
                } else {
3173
                    $curl_headers[] = "$k: $v";
3174
                }
3175
            }
3176
            if ($cookie_str != '') {
3177
                $curl_headers[] = 'Cookie: ' . $cookie_str;
3178
            }
3179
            $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
3180
            $this->debug('set cURL HTTP headers');
3181
            if ($this->request_method === 'POST') {
3182
                $this->setCurlOption(CURLOPT_POST, 1);
3183
                $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
3184
                $this->debug('set cURL POST data');
3185
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches 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 else branches can be removed.

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

could be turned into

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

This is much more concise to read.

Loading history...
3186
            }
3187
            // insert custom user-set cURL options
3188
            foreach ($this->ch_options as $key => $val) {
3189
                $this->setCurlOption($key, $val);
3190
            }
3191
3192
            $this->debug('set cURL payload');
3193
3194
            return true;
3195
        }
3196
    }
3197
3198
    /**
3199
     * gets the SOAP response via HTTP[S]
3200
     *
3201
     * @return string the response (also sets member variables like incoming_payload)
3202
     * @access   private
3203
     */
3204
    public function getResponse()
3205
    {
3206
        $this->incoming_payload = '';
3207
3208
        if ($this->io_method() === 'socket') {
3209
            // loop until headers have been retrieved
3210
            $data = '';
3211
            while (!isset($lb)) {
3212
3213
                // We might EOF during header read.
3214 View Code Duplication
                if (feof($this->fp)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3215
                    $this->incoming_payload = $data;
3216
                    $this->debug('found no headers before EOF after length ' . strlen($data));
3217
                    $this->debug("received before EOF:\n" . $data);
3218
                    $this->setError('server failed to send headers');
3219
3220
                    return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3221
                }
3222
3223
                $tmp    = fgets($this->fp, 256);
3224
                $tmplen = strlen($tmp);
3225
                $this->debug("read line of $tmplen bytes: " . trim($tmp));
3226
3227 View Code Duplication
                if ($tmplen == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3228
                    $this->incoming_payload = $data;
3229
                    $this->debug('socket read of headers timed out after length ' . strlen($data));
3230
                    $this->debug('read before timeout: ' . $data);
3231
                    $this->setError('socket read of headers timed out');
3232
3233
                    return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3234
                }
3235
3236
                $data .= $tmp;
3237
                $pos  = strpos($data, "\r\n\r\n");
3238
                if ($pos > 1) {
3239
                    $lb = "\r\n";
3240
                } else {
3241
                    $pos = strpos($data, "\n\n");
3242
                    if ($pos > 1) {
3243
                        $lb = "\n";
3244
                    }
3245
                }
3246
                // remove 100 headers
3247
                if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
3248
                    unset($lb);
3249
                    $data = '';
3250
                }//
3251
            }
3252
            // store header data
3253
            $this->incoming_payload .= $data;
3254
            $this->debug('found end of headers after length ' . strlen($data));
3255
            // process headers
3256
            $header_data            = trim(substr($data, 0, $pos));
0 ignored issues
show
Bug introduced by
The variable $pos does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
3257
            $header_array           = explode($lb, $header_data);
3258
            $this->incoming_headers = array();
3259
            $this->incoming_cookies = array();
3260 View Code Duplication
            foreach ($header_array as $header_line) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3261
                $arr = explode(':', $header_line, 2);
3262
                if (count($arr) > 1) {
3263
                    $header_name                          = strtolower(trim($arr[0]));
3264
                    $this->incoming_headers[$header_name] = trim($arr[1]);
3265
                    if ($header_name === 'set-cookie') {
3266
                        // TODO: allow multiple cookies from parseCookie
3267
                        $cookie = $this->parseCookie(trim($arr[1]));
3268
                        if ($cookie) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cookie of type array<string,string|boolean> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3269
                            $this->incoming_cookies[] = $cookie;
3270
                            $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3271
                        } else {
3272
                            $this->debug('did not find cookie in ' . trim($arr[1]));
3273
                        }
3274
                    }
3275
                } elseif (isset($header_name)) {
3276
                    // append continuation line to previous header
3277
                    $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3278
                }
3279
            }
3280
3281
            // loop until msg has been received
3282
            if (isset($this->incoming_headers['transfer-encoding'])
3283
                && strtolower($this->incoming_headers['transfer-encoding']) === 'chunked') {
3284
                $content_length = 2147483647;    // ignore any content-length header
3285
                $chunked        = true;
3286
                $this->debug('want to read chunked content');
3287
            } elseif (isset($this->incoming_headers['content-length'])) {
3288
                $content_length = $this->incoming_headers['content-length'];
3289
                $chunked        = false;
3290
                $this->debug("want to read content of length $content_length");
3291
            } else {
3292
                $content_length = 2147483647;
3293
                $chunked        = false;
3294
                $this->debug('want to read content to EOF');
3295
            }
3296
            $data = '';
3297
            do {
3298
                if ($chunked) {
3299
                    $tmp    = fgets($this->fp, 256);
3300
                    $tmplen = strlen($tmp);
3301
                    $this->debug("read chunk line of $tmplen bytes");
3302 View Code Duplication
                    if ($tmplen == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3303
                        $this->incoming_payload = $data;
3304
                        $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3305
                        $this->debug("read before timeout:\n" . $data);
3306
                        $this->setError('socket read of chunk length timed out');
3307
3308
                        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3309
                    }
3310
                    $content_length = hexdec(trim($tmp));
3311
                    $this->debug("chunk length $content_length");
3312
                }
3313
                $strlen = 0;
3314
                while (($strlen < $content_length) && (!feof($this->fp))) {
3315
                    $readlen = min(8192, $content_length - $strlen);
3316
                    $tmp     = fread($this->fp, $readlen);
3317
                    $tmplen  = strlen($tmp);
3318
                    $this->debug("read buffer of $tmplen bytes");
3319 View Code Duplication
                    if (($tmplen == 0) && (!feof($this->fp))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3320
                        $this->incoming_payload = $data;
3321
                        $this->debug('socket read of body timed out after length ' . strlen($data));
3322
                        $this->debug("read before timeout:\n" . $data);
3323
                        $this->setError('socket read of body timed out');
3324
3325
                        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3326
                    }
3327
                    $strlen += $tmplen;
3328
                    $data   .= $tmp;
3329
                }
3330
                if ($chunked && ($content_length > 0)) {
3331
                    $tmp    = fgets($this->fp, 256);
3332
                    $tmplen = strlen($tmp);
3333
                    $this->debug("read chunk terminator of $tmplen bytes");
3334 View Code Duplication
                    if ($tmplen == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3335
                        $this->incoming_payload = $data;
3336
                        $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3337
                        $this->debug("read before timeout:\n" . $data);
3338
                        $this->setError('socket read of chunk terminator timed out');
3339
3340
                        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3341
                    }
3342
                }
3343
            } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3344
            if (feof($this->fp)) {
3345
                $this->debug('read to EOF');
3346
            }
3347
            $this->debug('read body of length ' . strlen($data));
3348
            $this->incoming_payload .= $data;
3349
            $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server');
3350
3351
            // close filepointer
3352
            if ((isset($this->incoming_headers['connection'])
3353
                 && strtolower($this->incoming_headers['connection']) === 'close')
3354
                || (!$this->persistentConnection)
3355
                || feof($this->fp)) {
3356
                fclose($this->fp);
3357
                $this->fp = false;
3358
                $this->debug('closed socket');
3359
            }
3360
3361
            // connection was closed unexpectedly
3362
            if ($this->incoming_payload == '') {
3363
                $this->setError('no response from server');
3364
3365
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3366
            }
3367
3368
            // decode transfer-encoding
3369
            //      if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3370
            //          if (!$data = $this->decodeChunked($data, $lb)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3371
            //              $this->setError('Decoding of chunked data failed');
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3372
            //              return false;
3373
            //          }
3374
            //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3375
            // set decoded payload
3376
            //          $this->incoming_payload = $header_data.$lb.$lb.$data;
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3377
            //      }
3378
        } elseif ($this->io_method() === 'curl') {
3379
            // send and receive
3380
            $this->debug('send and receive with cURL');
3381
            $this->incoming_payload = curl_exec($this->ch);
3382
            $data                   = $this->incoming_payload;
3383
3384
            $cErr = curl_error($this->ch);
3385
            if ($cErr != '') {
3386
                $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . '<br>';
3387
                // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3388
                foreach (curl_getinfo($this->ch) as $k => $v) {
3389
                    $err .= "$k: $v<br>";
3390
                }
3391
                $this->debug($err);
3392
                $this->setError($err);
3393
                curl_close($this->ch);
3394
3395
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3396
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches 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 else branches can be removed.

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

could be turned into

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

This is much more concise to read.

Loading history...
3397
                //echo '<pre>';
3398
                //var_dump(curl_getinfo($this->ch));
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3399
                //echo '</pre>';
3400
            }
3401
            // close curl
3402
            $this->debug('No cURL error, closing cURL');
3403
            curl_close($this->ch);
3404
3405
            // try removing skippable headers
3406
            $savedata = $data;
3407
            while ($this->isSkippableCurlHeader($data)) {
3408
                $this->debug('Found HTTP header to skip');
3409 View Code Duplication
                if ($pos = strpos($data, "\r\n\r\n")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3410
                    $data = ltrim(substr($data, $pos));
3411
                } elseif ($pos = strpos($data, "\n\n")) {
3412
                    $data = ltrim(substr($data, $pos));
3413
                }
3414
            }
3415
3416
            if ($data == '') {
3417
                // have nothing left; just remove 100 header(s)
3418
                $data = $savedata;
3419
                while (preg_match('/^HTTP\/1.1 100/', $data)) {
3420 View Code Duplication
                    if ($pos = strpos($data, "\r\n\r\n")) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3421
                        $data = ltrim(substr($data, $pos));
3422
                    } elseif ($pos = strpos($data, "\n\n")) {
3423
                        $data = ltrim(substr($data, $pos));
3424
                    }
3425
                }
3426
            }
3427
3428
            // separate content from HTTP headers
3429
            if ($pos = strpos($data, "\r\n\r\n")) {
3430
                $lb = "\r\n";
3431
            } elseif ($pos = strpos($data, "\n\n")) {
3432
                $lb = "\n";
3433
            } else {
3434
                $this->debug('no proper separation of headers and document');
3435
                $this->setError('no proper separation of headers and document');
3436
3437
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3438
            }
3439
            $header_data  = trim(substr($data, 0, $pos));
3440
            $header_array = explode($lb, $header_data);
3441
            $data         = ltrim(substr($data, $pos));
3442
            $this->debug('found proper separation of headers and document');
3443
            $this->debug('cleaned data, stringlen: ' . strlen($data));
3444
            // clean headers
3445 View Code Duplication
            foreach ($header_array as $header_line) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3446
                $arr = explode(':', $header_line, 2);
3447
                if (count($arr) > 1) {
3448
                    $header_name                          = strtolower(trim($arr[0]));
3449
                    $this->incoming_headers[$header_name] = trim($arr[1]);
3450
                    if ($header_name === 'set-cookie') {
3451
                        // TODO: allow multiple cookies from parseCookie
3452
                        $cookie = $this->parseCookie(trim($arr[1]));
3453
                        if ($cookie) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cookie of type array<string,string|boolean> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
3454
                            $this->incoming_cookies[] = $cookie;
3455
                            $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3456
                        } else {
3457
                            $this->debug('did not find cookie in ' . trim($arr[1]));
3458
                        }
3459
                    }
3460
                } elseif (isset($header_name)) {
3461
                    // append continuation line to previous header
3462
                    $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3463
                }
3464
            }
3465
        }
3466
3467
        $this->response_status_line = $header_array[0];
0 ignored issues
show
Bug introduced by
The variable $header_array does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
3468
        $arr                        = explode(' ', $this->response_status_line, 3);
3469
        $http_version               = $arr[0];
0 ignored issues
show
Unused Code introduced by
$http_version is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3470
        $http_status                = (int)$arr[1];
3471
        $http_reason                = count($arr) > 2 ? $arr[2] : '';
3472
3473
        // see if we need to resend the request with http digest authentication
3474
        if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3475
            $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3476
            $this->setURL($this->incoming_headers['location']);
3477
            $this->tryagain = true;
3478
3479
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3480
        }
3481
3482
        // see if we need to resend the request with http digest authentication
3483
        if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3484
            $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3485
            if (false !== strpos($this->incoming_headers['www-authenticate'], 'Digest ')) {
3486
                $this->debug('Server wants digest authentication');
3487
                // remove "Digest " from our elements
3488
                $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3489
3490
                // parse elements into array
3491
                $digestElements = explode(',', $digestString);
3492
                foreach ($digestElements as $val) {
3493
                    $tempElement                    = explode('=', trim($val), 2);
3494
                    $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$digestRequest was never initialized. Although not strictly required by PHP, it is generally a good practice to add $digestRequest = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
3495
                }
3496
3497
                // should have (at least) qop, realm, nonce
3498
                if (isset($digestRequest['nonce'])) {
3499
                    $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3500
                    $this->tryagain = true;
3501
3502
                    return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3503
                }
3504
            }
3505
            $this->debug('HTTP authentication failed');
3506
            $this->setError('HTTP authentication failed');
3507
3508
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3509
        }
3510
3511
        if (($http_status >= 300 && $http_status <= 307) || ($http_status >= 400 && $http_status <= 417)
3512
            || ($http_status >= 501 && $http_status <= 505)) {
3513
            $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3514
3515
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3516
        }
3517
3518
        // decode content-encoding
3519
        if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') {
3520
            if (strtolower($this->incoming_headers['content-encoding']) === 'deflate'
3521
                || strtolower($this->incoming_headers['content-encoding']) === 'gzip') {
3522
                // if decoding works, use it. else assume data wasn't gzencoded
3523
                if (function_exists('gzinflate')) {
3524
                    //$timer->setMarker('starting decoding of gzip/deflated content');
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3525
                    // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3526
                    // this means there are no Zlib headers, although there should be
3527
                    $this->debug('The gzinflate function exists');
3528
                    $datalen = strlen($data);
0 ignored issues
show
Bug introduced by
The variable $data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
3529
                    if ($this->incoming_headers['content-encoding'] === 'deflate') {
3530
                        if ($degzdata = @gzinflate($data)) {
3531
                            $data = $degzdata;
3532
                            $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3533 View Code Duplication
                            if (strlen($data) < $datalen) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3534
                                // test for the case that the payload has been compressed twice
3535
                                $this->debug('The inflated payload is smaller than the gzipped one; try again');
3536
                                if ($degzdata = @gzinflate($data)) {
3537
                                    $data = $degzdata;
3538
                                    $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3539
                                }
3540
                            }
3541
                        } else {
3542
                            $this->debug('Error using gzinflate to inflate the payload');
3543
                            $this->setError('Error using gzinflate to inflate the payload');
3544
                        }
3545
                    } elseif ($this->incoming_headers['content-encoding'] === 'gzip') {
3546
                        if ($degzdata = @gzinflate(substr($data, 10))) {    // do our best
3547
                            $data = $degzdata;
3548
                            $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3549 View Code Duplication
                            if (strlen($data) < $datalen) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3550
                                // test for the case that the payload has been compressed twice
3551
                                $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3552
                                if ($degzdata = @gzinflate(substr($data, 10))) {
3553
                                    $data = $degzdata;
3554
                                    $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3555
                                }
3556
                            }
3557
                        } else {
3558
                            $this->debug('Error using gzinflate to un-gzip the payload');
3559
                            $this->setError('Error using gzinflate to un-gzip the payload');
3560
                        }
3561
                    }
3562
                    //$timer->setMarker('finished decoding of gzip/deflated content');
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
3563
                    //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3564
                    // set decoded payload
3565
                    $this->incoming_payload = $header_data . $lb . $lb . $data;
0 ignored issues
show
Bug introduced by
The variable $header_data does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $lb does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
3566
                } else {
3567
                    $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3568
                    $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3569
                }
3570
            } else {
3571
                $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3572
                $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3573
            }
3574
        } else {
3575
            $this->debug('No Content-Encoding header');
3576
        }
3577
3578
        if ('' === $data) {
3579
            $this->debug('no data after headers!');
3580
            $this->setError('no data present after HTTP headers');
3581
3582
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Soap_transport_http::getResponse of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
3583
        }
3584
3585
        return $data;
3586
    }
3587
3588
    /**
3589
     * sets the content-type for the SOAP message to be sent
3590
     *
3591
     * @param string $type    the content type, MIME style
3592
     * @param mixed  $charset character set used for encoding (or false)
3593
     * @access  public
3594
     */
3595
    public function setContentType($type, $charset = false)
3596
    {
3597
        $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3598
    }
3599
3600
    /**
3601
     * specifies that an HTTP persistent connection should be used
3602
     *
3603
     * @return boolean whether the request was honored by this method.
3604
     * @access  public
3605
     */
3606
    public function usePersistentConnection()
3607
    {
3608
        if (isset($this->outgoing_headers['Accept-Encoding'])) {
3609
            return false;
3610
        }
3611
        $this->protocol_version     = '1.1';
3612
        $this->persistentConnection = true;
3613
        $this->setHeader('Connection', 'Keep-Alive');
3614
3615
        return true;
3616
    }
3617
3618
    /**
3619
     * parse an incoming Cookie into it's parts
3620
     *
3621
     * @param  string $cookie_str content of cookie
3622
     * @return array  with data of that cookie
3623
     * @access  private
3624
     */
3625
    /*
3626
     * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3627
     */
3628
    public function parseCookie($cookie_str)
3629
    {
3630
        $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3631
        $data       = preg_split('/;/', $cookie_str);
3632
        $value_str  = $data[0];
3633
3634
        $cookie_param = 'domain=';
3635
        $start        = strpos($cookie_str, $cookie_param);
3636 View Code Duplication
        if ($start > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3637
            $domain = substr($cookie_str, $start + strlen($cookie_param));
3638
            $domain = substr($domain, 0, strpos($domain, ';'));
3639
        } else {
3640
            $domain = '';
3641
        }
3642
3643
        $cookie_param = 'expires=';
3644
        $start        = strpos($cookie_str, $cookie_param);
3645 View Code Duplication
        if ($start > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3646
            $expires = substr($cookie_str, $start + strlen($cookie_param));
3647
            $expires = substr($expires, 0, strpos($expires, ';'));
3648
        } else {
3649
            $expires = '';
3650
        }
3651
3652
        $cookie_param = 'path=';
3653
        $start        = strpos($cookie_str, $cookie_param);
3654 View Code Duplication
        if ($start > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3655
            $path = substr($cookie_str, $start + strlen($cookie_param));
3656
            $path = substr($path, 0, strpos($path, ';'));
3657
        } else {
3658
            $path = '/';
3659
        }
3660
3661
        $cookie_param = ';secure;';
3662
        if (strpos($cookie_str, $cookie_param) !== false) {
3663
            $secure = true;
3664
        } else {
3665
            $secure = false;
3666
        }
3667
3668
        $sep_pos = strpos($value_str, '=');
3669
3670
        if ($sep_pos) {
3671
            $name   = substr($value_str, 0, $sep_pos);
3672
            $value  = substr($value_str, $sep_pos + 1);
3673
            $cookie = array(
3674
                'name'    => $name,
3675
                'value'   => $value,
3676
                'domain'  => $domain,
3677
                'path'    => $path,
3678
                'expires' => $expires,
3679
                'secure'  => $secure
3680
            );
3681
3682
            return $cookie;
3683
        }
3684
3685
        return false;
3686
    }
3687
3688
    /**
3689
     * sort out cookies for the current request
3690
     *
3691
     * @param  array   $cookies array with all cookies
3692
     * @param  boolean $secure  is the send-content secure or not?
3693
     * @return string  for Cookie-HTTP-Header
3694
     * @access  private
3695
     */
3696
    public function getCookiesForRequest($cookies, $secure = false)
3697
    {
3698
        $cookie_str = '';
3699
        if ((null !== $cookies) && is_array($cookies)) {
3700
            foreach ($cookies as $cookie) {
3701
                if (!is_array($cookie)) {
3702
                    continue;
3703
                }
3704
                $this->debug('check cookie for validity: ' . $cookie['name'] . '=' . $cookie['value']);
3705
                if (isset($cookie['expires']) && (!empty($cookie['expires']))) {
3706
                    if (strtotime($cookie['expires']) <= time()) {
3707
                        $this->debug('cookie has expired');
3708
                        continue;
3709
                    }
3710
                }
3711 View Code Duplication
                if (isset($cookie['domain']) && (!empty($cookie['domain']))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3712
                    $domain = preg_quote($cookie['domain']);
3713
                    if (!preg_match("'.*$domain$'i", $this->host)) {
3714
                        $this->debug('cookie has different domain');
3715
                        continue;
3716
                    }
3717
                }
3718 View Code Duplication
                if (isset($cookie['path']) && (!empty($cookie['path']))) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3719
                    $path = preg_quote($cookie['path']);
3720
                    if (!preg_match("'^$path.*'i", $this->path)) {
3721
                        $this->debug('cookie is for a different path');
3722
                        continue;
3723
                    }
3724
                }
3725
                if ((!$secure) && isset($cookie['secure']) && $cookie['secure']) {
3726
                    $this->debug('cookie is secure, transport is not');
3727
                    continue;
3728
                }
3729
                $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3730
                $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3731
            }
3732
        }
3733
3734
        return $cookie_str;
3735
    }
3736
}
3737
3738
?><?php
3739
3740
/**
3741
 *
3742
 * nusoap_server allows the user to create a SOAP server
3743
 * that is capable of receiving messages and returning responses
3744
 *
3745
 * @author   Dietrich Ayala <[email protected]>
3746
 * @author   Scott Nichol <[email protected]>
3747
 * @access   public
3748
 */
3749
class Nusoap_server extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
3750
{
3751
    /**
3752
     * HTTP headers of request
3753
     * @var array
3754
     * @access private
3755
     */
3756
    public $headers = array();
3757
    /**
3758
     * HTTP request
3759
     * @var string
3760
     * @access private
3761
     */
3762
    public $request = '';
3763
    /**
3764
     * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
3765
     * @var string
3766
     * @access public
3767
     */
3768
    public $requestHeaders = '';
3769
    /**
3770
     * SOAP Headers from request (parsed)
3771
     * @var mixed
3772
     * @access public
3773
     */
3774
    public $requestHeader = null;
3775
    /**
3776
     * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
3777
     * @var string
3778
     * @access public
3779
     */
3780
    public $document = '';
3781
    /**
3782
     * SOAP payload for request (text)
3783
     * @var string
3784
     * @access public
3785
     */
3786
    public $requestSOAP = '';
3787
    /**
3788
     * requested method namespace URI
3789
     * @var string
3790
     * @access private
3791
     */
3792
    public $methodURI = '';
3793
    /**
3794
     * name of method requested
3795
     * @var string
3796
     * @access private
3797
     */
3798
    public $methodname = '';
3799
    /**
3800
     * method parameters from request
3801
     * @var array
3802
     * @access private
3803
     */
3804
    public $methodparams = array();
3805
    /**
3806
     * SOAP Action from request
3807
     * @var string
3808
     * @access private
3809
     */
3810
    public $SOAPAction = '';
3811
    /**
3812
     * character set encoding of incoming (request) messages
3813
     * @var string
3814
     * @access public
3815
     */
3816
    public $xml_encoding = '';
3817
    /**
3818
     * toggles whether the parser decodes element content w/ utf8_decode()
3819
     * @var boolean
3820
     * @access public
3821
     */
3822
    public $decode_utf8 = true;
3823
3824
    /**
3825
     * HTTP headers of response
3826
     * @var array
3827
     * @access public
3828
     */
3829
    public $outgoing_headers = array();
3830
    /**
3831
     * HTTP response
3832
     * @var string
3833
     * @access private
3834
     */
3835
    public $response = '';
3836
    /**
3837
     * SOAP headers for response (text or array of soapval or associative array)
3838
     * @var mixed
3839
     * @access public
3840
     */
3841
    public $responseHeaders = '';
3842
    /**
3843
     * SOAP payload for response (text)
3844
     * @var string
3845
     * @access private
3846
     */
3847
    public $responseSOAP = '';
3848
    /**
3849
     * method return value to place in response
3850
     * @var mixed
3851
     * @access private
3852
     */
3853
    public $methodreturn = false;
3854
    /**
3855
     * whether $methodreturn is a string of literal XML
3856
     * @var boolean
3857
     * @access public
3858
     */
3859
    public $methodreturnisliteralxml = false;
3860
    /**
3861
     * SOAP fault for response (or false)
3862
     * @var mixed
3863
     * @access private
3864
     */
3865
    public $fault = false;
3866
    /**
3867
     * text indication of result (for debugging)
3868
     * @var string
3869
     * @access private
3870
     */
3871
    public $result = 'successful';
3872
3873
    /**
3874
     * assoc array of operations => opData; operations are added by the register()
3875
     * method or by parsing an external WSDL definition
3876
     * @var array
3877
     * @access private
3878
     */
3879
    public $operations = array();
3880
    /**
3881
     * wsdl instance (if one)
3882
     * @var mixed
3883
     * @access private
3884
     */
3885
    public $wsdl = false;
3886
    /**
3887
     * URL for WSDL (if one)
3888
     * @var mixed
3889
     * @access private
3890
     */
3891
    public $externalWSDLURL = false;
3892
    /**
3893
     * whether to append debug to response as XML comment
3894
     * @var boolean
3895
     * @access public
3896
     */
3897
    public $debug_flag = false;
3898
3899
    /**
3900
     * constructor
3901
     * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
3902
     *
3903
     * @param mixed $wsdl file path or URL (string) , or wsdl instance (object)
3904
     * @access   public
3905
     * @return Nusoap_server
0 ignored issues
show
Documentation introduced by
Should the return type not be Nusoap_server|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
3906
     */
3907
    public function nusoap_server($wsdl = false)
0 ignored issues
show
Coding Style introduced by
nusoap_server uses the super-global variable $HTTP_SERVER_VARS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
nusoap_server uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
3908
    {
3909
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of nusoap_server()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
3910
        // turn on debugging?
3911
        global $debug;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
3912
        global $HTTP_SERVER_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
3913
3914
        if (isset($_SERVER)) {
3915
            $this->debug('_SERVER is defined:');
3916
            $this->appendDebug($this->varDump($_SERVER));
3917
        } elseif (isset($HTTP_SERVER_VARS)) {
3918
            $this->debug('HTTP_SERVER_VARS is defined:');
3919
            $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3920
        } else {
3921
            $this->debug('Neither _SERVER nor HTTP_SERVER_VARS is defined.');
3922
        }
3923
3924
        if (isset($debug)) {
3925
            $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3926
            $this->debug_flag = $debug;
3927
        } elseif (isset($_SERVER['QUERY_STRING'])) {
3928
            $qs = explode('&', $_SERVER['QUERY_STRING']);
3929 View Code Duplication
            foreach ($qs as $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3930
                if (substr($v, 0, 6) === 'debug=') {
3931
                    $this->debug('In nusoap_server, set debug_flag=' . substr($v, 6) . ' based on query string #1');
3932
                    $this->debug_flag = substr($v, 6);
0 ignored issues
show
Documentation Bug introduced by
The property $debug_flag was declared of type boolean, but substr($v, 6) is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
3933
                }
3934
            }
3935
        } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3936
            $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3937 View Code Duplication
            foreach ($qs as $v) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3938
                if (substr($v, 0, 6) === 'debug=') {
3939
                    $this->debug('In nusoap_server, set debug_flag=' . substr($v, 6) . ' based on query string #2');
3940
                    $this->debug_flag = substr($v, 6);
3941
                }
3942
            }
3943
        }
3944
3945
        // wsdl
3946
        if ($wsdl) {
3947
            $this->debug('In nusoap_server, WSDL is specified');
3948
            if (is_object($wsdl) && (get_class($wsdl) === 'wsdl')) {
3949
                $this->wsdl            = $wsdl;
3950
                $this->externalWSDLURL = $this->wsdl->wsdl;
3951
                $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3952
            } else {
3953
                $this->debug('Create wsdl from ' . $wsdl);
3954
                $this->wsdl            = new wsdl($wsdl);
3955
                $this->externalWSDLURL = $wsdl;
3956
            }
3957
            $this->appendDebug($this->wsdl->getDebug());
3958
            $this->wsdl->clearDebug();
3959
            if ($err = $this->wsdl->getError()) {
3960
                die('WSDL ERROR: ' . $err);
0 ignored issues
show
Coding Style Compatibility introduced by
The method nusoap_server() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
3961
            }
3962
        }
3963
    }
3964
3965
    /**
3966
     * processes request and returns response
3967
     *
3968
     * @param string $data usually is the value of $HTTP_RAW_POST_DATA
3969
     * @access   public
3970
     */
3971
    public function service($data)
0 ignored issues
show
Coding Style introduced by
service uses the super-global variable $HTTP_SERVER_VARS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
service uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
3972
    {
3973
        global $HTTP_SERVER_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
3974
3975 View Code Duplication
        if (isset($_SERVER['REQUEST_METHOD'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3976
            $rm = $_SERVER['REQUEST_METHOD'];
3977
        } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
3978
            $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
3979
        } else {
3980
            $rm = '';
3981
        }
3982
3983 View Code Duplication
        if (isset($_SERVER['QUERY_STRING'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3984
            $qs = $_SERVER['QUERY_STRING'];
3985
        } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3986
            $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3987
        } else {
3988
            $qs = '';
3989
        }
3990
        $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
3991
3992
        if ($rm === 'POST') {
3993
            $this->debug('In service, invoke the request');
3994
            $this->parse_request($data);
3995
            if (!$this->fault) {
3996
                $this->invoke_method();
3997
            }
3998
            if (!$this->fault) {
3999
                $this->serialize_return();
4000
            }
4001
            $this->send_response();
4002
        } elseif (preg_match('/wsdl/', $qs)) {
4003
            $this->debug('In service, this is a request for WSDL');
4004
            if ($this->externalWSDLURL) {
4005
                if (strpos($this->externalWSDLURL, 'http://') !== false) { // assume URL
4006
                    $this->debug('In service, re-direct for WSDL');
4007
                    header('Location: ' . $this->externalWSDLURL);
4008
                } else { // assume file
4009
                    $this->debug('In service, use file passthru for WSDL');
4010
                    header("Content-Type: text/xml\r\n");
4011
                    $pos = strpos($this->externalWSDLURL, 'file://');
4012
                    if ($pos === false) {
4013
                        $filename = $this->externalWSDLURL;
0 ignored issues
show
Unused Code introduced by
$filename is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
4014
                    } else {
4015
                        $filename = substr($this->externalWSDLURL, $pos + 7);
0 ignored issues
show
Unused Code introduced by
$filename is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
4016
                    }
4017
                    $fp = fopen($this->externalWSDLURL, 'r');
4018
                    fpassthru($fp);
4019
                }
4020
            } elseif ($this->wsdl) {
4021
                $this->debug('In service, serialize WSDL');
4022
                header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
4023
                print $this->wsdl->serialize($this->debug_flag);
4024
                if ($this->debug_flag) {
4025
                    $this->debug('wsdl:');
4026
                    $this->appendDebug($this->varDump($this->wsdl));
4027
                    print $this->getDebugAsXMLComment();
4028
                }
4029
            } else {
4030
                $this->debug('In service, there is no WSDL');
4031
                header("Content-Type: text/html; charset=ISO-8859-1\r\n");
4032
                print 'This service does not provide WSDL';
4033
            }
4034
        } elseif ($this->wsdl) {
4035
            $this->debug('In service, return Web description');
4036
            print $this->wsdl->webDescription();
4037
        } else {
4038
            $this->debug('In service, no Web description');
4039
            header("Content-Type: text/html; charset=ISO-8859-1\r\n");
4040
            print 'This service does not provide a Web description';
4041
        }
4042
    }
4043
4044
    /**
4045
     * parses HTTP request headers.
4046
     *
4047
     * The following fields are set by this function (when successful)
4048
     *
4049
     * headers
4050
     * request
4051
     * xml_encoding
4052
     * SOAPAction
4053
     *
4054
     * @access   private
4055
     */
4056
    public function parse_http_headers()
0 ignored issues
show
Coding Style introduced by
parse_http_headers uses the super-global variable $HTTP_SERVER_VARS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
parse_http_headers uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4057
    {
4058
        global $HTTP_SERVER_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
4059
4060
        $this->request    = '';
4061
        $this->SOAPAction = '';
4062
        if (function_exists('getallheaders')) {
4063
            $this->debug('In parse_http_headers, use getallheaders');
4064
            $headers = getallheaders();
4065
            foreach ($headers as $k => $v) {
4066
                $k                 = strtolower($k);
4067
                $this->headers[$k] = $v;
4068
                $this->request     .= "$k: $v\r\n";
4069
                $this->debug("$k: $v");
4070
            }
4071
            // get SOAPAction header
4072
            if (isset($this->headers['soapaction'])) {
4073
                $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
4074
            }
4075
            // get the character encoding of the incoming request
4076
            if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
4077
                $enc = str_replace('"', '', substr(strstr($this->headers['content-type'], '='), 1));
4078
                if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4079
                    $this->xml_encoding = strtoupper($enc);
4080
                } else {
4081
                    $this->xml_encoding = 'US-ASCII';
4082
                }
4083
            } else {
4084
                // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4085
                $this->xml_encoding = 'ISO-8859-1';
4086
            }
4087
        } elseif (isset($_SERVER) && is_array($_SERVER)) {
4088
            $this->debug('In parse_http_headers, use _SERVER');
4089
            foreach ($_SERVER as $k => $v) {
4090
                if (substr($k, 0, 5) === 'HTTP_') {
4091
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
4092
                } else {
4093
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
4094
                }
4095 View Code Duplication
                if ($k === 'soapaction') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4096
                    // get SOAPAction header
4097
                    $k                = 'SOAPAction';
4098
                    $v                = str_replace('"', '', $v);
4099
                    $v                = str_replace('\\', '', $v);
4100
                    $this->SOAPAction = $v;
4101
                } elseif ($k === 'content-type') {
4102
                    // get the character encoding of the incoming request
4103
                    if (strpos($v, '=')) {
4104
                        $enc = substr(strstr($v, '='), 1);
4105
                        $enc = str_replace('"', '', $enc);
4106
                        $enc = str_replace('\\', '', $enc);
4107
                        if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4108
                            $this->xml_encoding = strtoupper($enc);
4109
                        } else {
4110
                            $this->xml_encoding = 'US-ASCII';
4111
                        }
4112
                    } else {
4113
                        // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4114
                        $this->xml_encoding = 'ISO-8859-1';
4115
                    }
4116
                }
4117
                $this->headers[$k] = $v;
4118
                $this->request     .= "$k: $v\r\n";
4119
                $this->debug("$k: $v");
4120
            }
4121
        } elseif (is_array($HTTP_SERVER_VARS)) {
4122
            $this->debug('In parse_http_headers, use HTTP_SERVER_VARS');
4123
            foreach ($HTTP_SERVER_VARS as $k => $v) {
4124
                if (substr($k, 0, 5) === 'HTTP_') {
4125
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
4126
                    $k = strtolower(substr($k, 5));
4127
                } else {
4128
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
4129
                    $k = strtolower($k);
4130
                }
4131 View Code Duplication
                if ($k === 'soapaction') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4132
                    // get SOAPAction header
4133
                    $k                = 'SOAPAction';
4134
                    $v                = str_replace('"', '', $v);
4135
                    $v                = str_replace('\\', '', $v);
4136
                    $this->SOAPAction = $v;
4137
                } elseif ($k === 'content-type') {
4138
                    // get the character encoding of the incoming request
4139
                    if (strpos($v, '=')) {
4140
                        $enc = substr(strstr($v, '='), 1);
4141
                        $enc = str_replace('"', '', $enc);
4142
                        $enc = str_replace('\\', '', $enc);
4143
                        if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4144
                            $this->xml_encoding = strtoupper($enc);
4145
                        } else {
4146
                            $this->xml_encoding = 'US-ASCII';
4147
                        }
4148
                    } else {
4149
                        // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4150
                        $this->xml_encoding = 'ISO-8859-1';
4151
                    }
4152
                }
4153
                $this->headers[$k] = $v;
4154
                $this->request     .= "$k: $v\r\n";
4155
                $this->debug("$k: $v");
4156
            }
4157
        } else {
4158
            $this->debug('In parse_http_headers, HTTP headers not accessible');
4159
            $this->setError('HTTP headers not accessible');
4160
        }
4161
    }
4162
4163
    /**
4164
     * parses a request
4165
     *
4166
     * The following fields are set by this function (when successful)
4167
     *
4168
     * headers
4169
     * request
4170
     * xml_encoding
4171
     * SOAPAction
4172
     * request
4173
     * requestSOAP
4174
     * methodURI
4175
     * methodname
4176
     * methodparams
4177
     * requestHeaders
4178
     * document
4179
     *
4180
     * This sets the fault field on error
4181
     *
4182
     * @param string $data XML string
4183
     * @access   private
4184
     */
4185
    public function parse_request($data = '')
4186
    {
4187
        $this->debug('entering parse_request()');
4188
        $this->parse_http_headers();
4189
        $this->debug('got character encoding: ' . $this->xml_encoding);
4190
        // uncompress if necessary
4191
        if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
4192
            $this->debug('got content encoding: ' . $this->headers['content-encoding']);
4193
            if ($this->headers['content-encoding'] === 'deflate' || $this->headers['content-encoding'] === 'gzip') {
4194
                // if decoding works, use it. else assume data wasn't gzencoded
4195
                if (function_exists('gzuncompress')) {
4196
                    if ($this->headers['content-encoding'] === 'deflate' && $degzdata = @gzuncompress($data)) {
4197
                        $data = $degzdata;
4198
                    } elseif ($this->headers['content-encoding'] === 'gzip'
4199
                              && $degzdata = gzinflate(substr($data, 10))) {
4200
                        $data = $degzdata;
4201
                    } else {
4202
                        $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
4203
4204
                        return;
4205
                    }
4206
                } else {
4207
                    $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
4208
4209
                    return;
4210
                }
4211
            }
4212
        }
4213
        $this->request     .= "\r\n" . $data;
4214
        $data              = $this->parseRequest($this->headers, $data);
4215
        $this->requestSOAP = $data;
0 ignored issues
show
Documentation Bug introduced by
It seems like $data can also be of type false. However, the property $requestSOAP 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...
4216
        $this->debug('leaving parse_request');
4217
    }
4218
4219
    /**
4220
     * invokes a PHP function for the requested SOAP method
4221
     *
4222
     * The following fields are set by this function (when successful)
4223
     *
4224
     * methodreturn
4225
     *
4226
     * Note that the PHP function that is called may also set the following
4227
     * fields to affect the response sent to the client
4228
     *
4229
     * responseHeaders
4230
     * outgoing_headers
4231
     *
4232
     * This sets the fault field on error
4233
     *
4234
     * @access   private
4235
     */
4236
    public function invoke_method()
4237
    {
4238
        $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
4239
4240
        //
4241
        // if you are debugging in this area of the code, your service uses a class to implement methods,
4242
        // you use SOAP RPC, and the client is .NET, please be aware of the following...
4243
        // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
4244
        // method name.  that is fine for naming the .NET methods.  it is not fine for properly constructing
4245
        // the XML request and reading the XML response.  you need to add the RequestElementName and
4246
        // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
4247
        // generates for the method.  these parameters are used to specify the correct XML element names
4248
        // for .NET to use, i.e. the names with the '.' in them.
4249
        //
4250
        $orig_methodname = $this->methodname;
4251
        if ($this->wsdl) {
4252
            if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
4253
                $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
4254
                $this->appendDebug('opData=' . $this->varDump($this->opData));
0 ignored issues
show
Bug introduced by
The property opData does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
4255
            } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
4256
                // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
4257
                $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
4258
                $this->appendDebug('opData=' . $this->varDump($this->opData));
4259
                $this->methodname = $this->opData['name'];
4260
            } else {
4261
                $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
4262
                $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
4263
4264
                return;
4265
            }
4266
        } else {
4267
            $this->debug('in invoke_method, no WSDL to validate method');
4268
        }
4269
4270
        // if a . is present in $this->methodname, we see if there is a class in scope,
4271
        // which could be referred to. We will also distinguish between two deliminators,
4272
        // to allow methods to be called a the class or an instance
4273
        if (strpos($this->methodname, '..') > 0) {
4274
            $delim = '..';
4275
        } elseif (strpos($this->methodname, '.') > 0) {
4276
            $delim = '.';
4277
        } else {
4278
            $delim = '';
4279
        }
4280
        $this->debug("in invoke_method, delim=$delim");
4281
4282
        $class  = '';
4283
        $method = '';
4284
        if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
4285
            $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
4286
            if (class_exists($try_class)) {
4287
                // get the class and method name
4288
                $class  = $try_class;
4289
                $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
4290
                $this->debug("in invoke_method, class=$class method=$method delim=$delim");
4291
            } else {
4292
                $this->debug("in invoke_method, class=$try_class not found");
4293
            }
4294
        } else {
4295
            $try_class = '';
4296
            $this->debug('in invoke_method, no class to try');
4297
        }
4298
4299
        // does method exist?
4300
        if ($class == '') {
4301
            if (!function_exists($this->methodname)) {
4302
                $this->debug("in invoke_method, function '$this->methodname' not found!");
4303
                $this->result = 'fault: method not found';
4304
                $this->fault('SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
4305
4306
                return;
4307
            }
4308
        } else {
4309
            $method_to_compare = (substr(PHP_VERSION, 0, 2) === '4.') ? strtolower($method) : $method;
4310
            if (!in_array($method_to_compare, get_class_methods($class))) {
4311
                $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
4312
                $this->result = 'fault: method not found';
4313
                $this->fault('SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
4314
4315
                return;
4316
            }
4317
        }
4318
4319
        // evaluate message, getting back parameters
4320
        // verify that request parameters match the method's signature
4321
        if (!$this->verify_method($this->methodname, $this->methodparams)) {
4322
            // debug
4323
            $this->debug('ERROR: request not verified against method signature');
4324
            $this->result = 'fault: request failed validation against method signature';
4325
            // return fault
4326
            $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
4327
4328
            return;
4329
        }
4330
4331
        // if there are parameters to pass
4332
        $this->debug('in invoke_method, params:');
4333
        $this->appendDebug($this->varDump($this->methodparams));
4334
        $this->debug("in invoke_method, calling '$this->methodname'");
4335
        if (!function_exists('call_user_func_array')) {
4336
            if ($class == '') {
4337
                $this->debug('in invoke_method, calling function using eval()');
4338
                $funcCall = "\$this->methodreturn = $this->methodname(";
4339
            } else {
4340
                if ($delim === '..') {
4341
                    $this->debug('in invoke_method, calling class method using eval()');
4342
                    $funcCall = "\$this->methodreturn = " . $class . '::' . $method . '(';
4343
                } else {
4344
                    $this->debug('in invoke_method, calling instance method using eval()');
4345
                    // generate unique instance name
4346
                    $instname = "\$inst_" . time();
4347
                    $funcCall = $instname . ' = new ' . $class . '(); ';
4348
                    $funcCall .= "\$this->methodreturn = " . $instname . '->' . $method . '(';
4349
                }
4350
            }
4351
            if ($this->methodparams) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->methodparams of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
4352
                foreach ($this->methodparams as $param) {
4353
                    if (is_array($param) || is_object($param)) {
4354
                        $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
4355
4356
                        return;
4357
                    }
4358
                    $funcCall .= "\"$param\",";
4359
                }
4360
                $funcCall = substr($funcCall, 0, -1);
4361
            }
4362
            $funcCall .= ');';
4363
            $this->debug('in invoke_method, function call: ' . $funcCall);
4364
            @eval($funcCall);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
4365
        } else {
4366
            if ($class == '') {
4367
                $this->debug('in invoke_method, calling function using call_user_func_array()');
4368
                $call_arg = "$this->methodname";    // straight assignment changes $this->methodname to lower case after call_user_func_array()
4369
            } elseif ($delim === '..') {
4370
                $this->debug('in invoke_method, calling class method using call_user_func_array()');
4371
                $call_arg = array($class, $method);
4372
            } else {
4373
                $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4374
                $instance = new $class();
4375
                $call_arg = array(&$instance, $method);
4376
            }
4377
            if (is_array($this->methodparams)) {
4378
                $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4379
            } else {
4380
                $this->methodreturn = call_user_func_array($call_arg, array());
4381
            }
4382
        }
4383
        $this->debug('in invoke_method, methodreturn:');
4384
        $this->appendDebug($this->varDump($this->methodreturn));
4385
        $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn));
4386
    }
4387
4388
    /**
4389
     * serializes the return value from a PHP function into a full SOAP Envelope
4390
     *
4391
     * The following fields are set by this function (when successful)
4392
     *
4393
     * responseSOAP
4394
     *
4395
     * This sets the fault field on error
4396
     *
4397
     * @access   private
4398
     */
4399
    public function serialize_return()
4400
    {
4401
        $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4402
        // if fault
4403
        if (isset($this->methodreturn) && is_object($this->methodreturn)
4404
            && ((get_class($this->methodreturn) === 'soap_fault')
4405
                || (get_class($this->methodreturn) === 'nusoap_fault'))) {
4406
            $this->debug('got a fault object from method');
4407
            $this->fault = $this->methodreturn;
4408
4409
            return;
4410
        } elseif ($this->methodreturnisliteralxml) {
4411
            $return_val = $this->methodreturn;
4412
            // returned value(s)
4413
        } else {
4414
            $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method');
4415
            $this->debug('serializing return value');
4416
            if ($this->wsdl) {
4417
                if (count($this->opData['output']['parts']) > 1) {
4418
                    $this->debug('more than one output part, so use the method return unchanged');
4419
                    $opParams = $this->methodreturn;
4420
                } elseif (count($this->opData['output']['parts']) == 1) {
4421
                    $this->debug('exactly one output part, so wrap the method return in a simple array');
4422
                    // TODO: verify that it is not already wrapped!
4423
                    //foreach ($this->opData['output']['parts'] as $name => $type) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
4424
                    //  $this->debug('wrap in element named ' . $name);
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
4425
                    //}
4426
                    $opParams = array($this->methodreturn);
4427
                }
4428
                $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams);
0 ignored issues
show
Bug introduced by
The variable $opParams does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4429
                $this->appendDebug($this->wsdl->getDebug());
4430
                $this->wsdl->clearDebug();
4431
                if ($errstr = $this->wsdl->getError()) {
4432
                    $this->debug('got wsdl error: ' . $errstr);
4433
                    $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4434
4435
                    return;
4436
                }
4437
            } else {
4438
                if (isset($this->methodreturn)) {
4439
                    $return_val = $this->serialize_val($this->methodreturn, 'return');
4440
                } else {
4441
                    $return_val = '';
4442
                    $this->debug('in absence of WSDL, assume void return for backward compatibility');
4443
                }
4444
            }
4445
        }
4446
        $this->debug('return value:');
4447
        $this->appendDebug($this->varDump($return_val));
4448
4449
        $this->debug('serializing response');
4450
        if ($this->wsdl) {
4451
            $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4452
            if ($this->opData['style'] === 'rpc') {
4453
                $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4454
                if ($this->opData['output']['use'] === 'literal') {
4455
                    // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
4456 View Code Duplication
                    if ($this->methodURI) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4457
                        $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . 'Response>';
4458
                    } else {
4459
                        $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4460
                    }
4461 View Code Duplication
                } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4462
                    if ($this->methodURI) {
4463
                        $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . 'Response>';
4464
                    } else {
4465
                        $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4466
                    }
4467
                }
4468
            } else {
4469
                $this->debug('style is not rpc for serialization: assume document');
4470
                $payload = $return_val;
4471
            }
4472
        } else {
4473
            $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4474
            $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . 'Response>';
4475
        }
4476
        $this->result = 'successful';
4477
        if ($this->wsdl) {
4478
            //if ($this->debug_flag) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
4479
            $this->appendDebug($this->wsdl->getDebug());
4480
            //  }
4481
            if (isset($this->opData['output']['encodingStyle'])) {
4482
                $encodingStyle = $this->opData['output']['encodingStyle'];
4483
            } else {
4484
                $encodingStyle = '';
4485
            }
4486
            // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4487
            $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
4488
        } else {
4489
            $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
4490
        }
4491
        $this->debug('Leaving serialize_return');
4492
    }
4493
4494
    /**
4495
     * sends an HTTP response
4496
     *
4497
     * The following fields are set by this function (when successful)
4498
     *
4499
     * outgoing_headers
4500
     * response
4501
     *
4502
     * @access   private
4503
     */
4504
    public function send_response()
4505
    {
4506
        $this->debug('Enter send_response');
4507
        if ($this->fault) {
4508
            $payload                  = $this->fault->serialize();
4509
            $this->outgoing_headers[] = 'HTTP/1.0 500 Internal Server Error';
4510
            $this->outgoing_headers[] = 'Status: 500 Internal Server Error';
4511
        } else {
4512
            $payload = $this->responseSOAP;
4513
            // Some combinations of PHP+Web server allow the Status
4514
            // to come through as a header.  Since OK is the default
4515
            // just do nothing.
4516
            // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
4517
            // $this->outgoing_headers[] = "Status: 200 OK";
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
4518
        }
4519
        // add debug data if in debug mode
4520
        if (isset($this->debug_flag) && $this->debug_flag) {
4521
            $payload .= $this->getDebugAsXMLComment();
4522
        }
4523
        $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4524
        preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4525
        $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ')';
4526
        // Let the Web server decide about this
4527
        //$this->outgoing_headers[] = "Connection: Close\r\n";
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
4528
        $payload                  = $this->getHTTPBody($payload);
4529
        $type                     = $this->getHTTPContentType();
4530
        $charset                  = $this->getHTTPContentTypeCharset();
4531
        $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4532
        //begin code to compress payload - by John
4533
        // NOTE: there is no way to know whether the Web server will also compress
4534
        // this data.
4535
        if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4536
            if (false !== strpos($this->headers['accept-encoding'], 'gzip')) {
4537 View Code Duplication
                if (function_exists('gzencode')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4538
                    if (isset($this->debug_flag) && $this->debug_flag) {
4539
                        $payload .= '<!-- Content being gzipped -->';
4540
                    }
4541
                    $this->outgoing_headers[] = 'Content-Encoding: gzip';
4542
                    $payload                  = gzencode($payload);
4543
                } else {
4544
                    if (isset($this->debug_flag) && $this->debug_flag) {
4545
                        $payload .= '<!-- Content will not be gzipped: no gzencode -->';
4546
                    }
4547
                }
4548
            } elseif (false !== strpos($this->headers['accept-encoding'], 'deflate')) {
4549
                // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4550
                // instead of gzcompress output,
4551
                // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4552 View Code Duplication
                if (function_exists('gzdeflate')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4553
                    if (isset($this->debug_flag) && $this->debug_flag) {
4554
                        $payload .= '<!-- Content being deflated -->';
4555
                    }
4556
                    $this->outgoing_headers[] = 'Content-Encoding: deflate';
4557
                    $payload                  = gzdeflate($payload);
4558
                } else {
4559
                    if (isset($this->debug_flag) && $this->debug_flag) {
4560
                        $payload .= '<!-- Content will not be deflated: no gzcompress -->';
4561
                    }
4562
                }
4563
            }
4564
        }
4565
        //end code
4566
        $this->outgoing_headers[] = 'Content-Length: ' . strlen($payload);
4567
        reset($this->outgoing_headers);
4568
        foreach ($this->outgoing_headers as $hdr) {
4569
            header($hdr, false);
4570
        }
4571
        print $payload;
4572
        $this->response = implode("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
4573
    }
4574
4575
    /**
4576
     * takes the value that was created by parsing the request
4577
     * and compares to the method's signature, if available.
4578
     *
4579
     * @param  string $operation The operation to be invoked
4580
     * @param  array  $request   The array of parameter values
4581
     * @return boolean Whether the operation was found
4582
     * @access   private
4583
     */
4584
    public function verify_method($operation, $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
4585
    {
4586
        if (isset($this->wsdl) && is_object($this->wsdl)) {
4587
            if ($this->wsdl->getOperationData($operation)) {
4588
                return true;
4589
            }
4590
        } elseif (isset($this->operations[$operation])) {
4591
            return true;
4592
        }
4593
4594
        return false;
4595
    }
4596
4597
    /**
4598
     * processes SOAP message received from client
4599
     *
4600
     * @param  array  $headers The HTTP headers
4601
     * @param  string $data    unprocessed request data from client
4602
     * @return mixed  value of the message, decoded into a PHP type
4603
     * @access   private
4604
     */
4605
    public function parseRequest($headers, $data)
4606
    {
4607
        $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
4608
        $this->appendDebug($this->varDump($headers));
4609
        if (!isset($headers['content-type'])) {
4610
            $this->setError('Request not of type text/xml (no content-type header)');
4611
4612
            return false;
4613
        }
4614 View Code Duplication
        if (false === strpos($headers['content-type'], 'text/xml')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4615
            $this->setError('Request not of type text/xml');
4616
4617
            return false;
4618
        }
4619 View Code Duplication
        if (strpos($headers['content-type'], '=')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4620
            $enc = str_replace('"', '', substr(strstr($headers['content-type'], '='), 1));
4621
            $this->debug('Got response encoding: ' . $enc);
4622
            if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4623
                $this->xml_encoding = strtoupper($enc);
4624
            } else {
4625
                $this->xml_encoding = 'US-ASCII';
4626
            }
4627
        } else {
4628
            // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4629
            $this->xml_encoding = 'ISO-8859-1';
4630
        }
4631
        $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4632
        // parse response, get soap parser obj
4633
        $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
4634
        // parser debug
4635
        $this->debug("parser debug: \n" . $parser->getDebug());
4636
        // if fault occurred during message parsing
4637
        if ($err = $parser->getError()) {
4638
            $this->result = 'fault: error in msg parsing: ' . $err;
4639
            $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err);
4640
            // else successfully parsed request into soapval object
4641
        } else {
4642
            // get/set methodname
4643
            $this->methodURI  = $parser->root_struct_namespace;
4644
            $this->methodname = $parser->root_struct_name;
4645
            $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4646
            $this->debug('calling parser->get_soapbody()');
4647
            $this->methodparams = $parser->get_soapbody();
0 ignored issues
show
Documentation Bug introduced by
It seems like $parser->get_soapbody() of type * is incompatible with the declared type array of property $methodparams.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
4648
            // get SOAP headers
4649
            $this->requestHeaders = $parser->getHeaders();
4650
            // get SOAP Header
4651
            $this->requestHeader = $parser->get_soapheader();
4652
            // add document for doclit support
4653
            $this->document = $parser->document;
4654
        }
4655
    }
4656
4657
    /**
4658
     * gets the HTTP body for the current response.
4659
     *
4660
     * @param  string $soapmsg The SOAP payload
4661
     * @return string The HTTP body, which includes the SOAP payload
4662
     * @access private
4663
     */
4664
    public function getHTTPBody($soapmsg)
4665
    {
4666
        return $soapmsg;
4667
    }
4668
4669
    /**
4670
     * gets the HTTP content type for the current response.
4671
     *
4672
     * Note: getHTTPBody must be called before this.
4673
     *
4674
     * @return string the HTTP content type for the current response.
4675
     * @access private
4676
     */
4677
    public function getHTTPContentType()
4678
    {
4679
        return 'text/xml';
4680
    }
4681
4682
    /**
4683
     * gets the HTTP content type charset for the current response.
4684
     * returns false for non-text content types.
4685
     *
4686
     * Note: getHTTPBody must be called before this.
4687
     *
4688
     * @return string the HTTP content type charset for the current response.
4689
     * @access private
4690
     */
4691
    public function getHTTPContentTypeCharset()
4692
    {
4693
        return $this->soap_defencoding;
4694
    }
4695
4696
    /**
4697
     * add a method to the dispatch map (this has been replaced by the register method)
4698
     *
4699
     * @param string $methodname
4700
     * @param string $in  array of input values
4701
     * @param string $out array of output values
4702
     * @access   public
4703
     * @deprecated
4704
     */
4705
    public function add_to_map($methodname, $in, $out)
4706
    {
4707
        $this->operations[$methodname] = array('name' => $methodname, 'in' => $in, 'out' => $out);
4708
    }
4709
4710
    /**
4711
     * register a service function with the server
4712
     *
4713
     * @param string $name          the name of the PHP function, class.method or class..method
4714
     * @param array  $in            assoc array of input values: key = param name, value = param type
4715
     * @param array  $out           assoc array of output values: key = param name, value = param type
4716
     * @param mixed  $namespace     the element namespace for the method or false
4717
     * @param mixed  $soapaction    the soapaction for the method or false
4718
     * @param mixed  $style         optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
4719
     * @param mixed  $use           optional (encoded|literal) or false
4720
     * @param string $documentation optional Description to include in WSDL
4721
     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
4722
     * @access   public
4723
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be null|boolean?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
4724
     */
4725
    public function register(
0 ignored issues
show
Coding Style introduced by
register uses the super-global variable $HTTP_SERVER_VARS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
register uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4726
        $name,
4727
        $in = array(),
4728
        $out = array(),
4729
        $namespace = false,
4730
        $soapaction = false,
4731
        $style = false,
4732
        $use = false,
4733
        $documentation = '',
4734
        $encodingStyle = '')
4735
    {
4736
        global $HTTP_SERVER_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
4737
4738
        if ($this->externalWSDLURL) {
4739
            die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
0 ignored issues
show
Coding Style Compatibility introduced by
The method register() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
4740
        }
4741
        if (!$name) {
4742
            die('You must specify a name when you register an operation');
0 ignored issues
show
Coding Style Compatibility introduced by
The method register() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
4743
        }
4744
        if (!is_array($in)) {
4745
            die('You must provide an array for operation inputs');
0 ignored issues
show
Coding Style Compatibility introduced by
The method register() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
4746
        }
4747
        if (!is_array($out)) {
4748
            die('You must provide an array for operation outputs');
0 ignored issues
show
Coding Style Compatibility introduced by
The method register() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
4749
        }
4750
        if (false == $namespace) {
0 ignored issues
show
Unused Code introduced by
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...
4751
        }
4752
        if (false == $soapaction) {
4753
            if (isset($_SERVER)) {
4754
                $SERVER_NAME = $_SERVER['SERVER_NAME'];
4755
                $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4756
                $HTTPS       = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4757 View Code Duplication
            } elseif (isset($HTTP_SERVER_VARS)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4758
                $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4759
                $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4760
                $HTTPS       = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4761
            } else {
4762
                $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
4763
            }
4764
            if ($HTTPS == '1' || $HTTPS === 'on') {
0 ignored issues
show
Bug introduced by
The variable $HTTPS does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4765
                $SCHEME = 'https';
4766
            } else {
4767
                $SCHEME = 'http';
4768
            }
4769
            $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
0 ignored issues
show
Bug introduced by
The variable $SERVER_NAME does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $SCRIPT_NAME does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4770
        }
4771
        if (false == $style) {
4772
            $style = 'rpc';
4773
        }
4774
        if (false == $use) {
4775
            $use = 'encoded';
4776
        }
4777
        if ($use === 'encoded' && $encodingStyle == '') {
4778
            $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4779
        }
4780
4781
        $this->operations[$name] = array(
4782
            'name'       => $name,
4783
            'in'         => $in,
4784
            'out'        => $out,
4785
            'namespace'  => $namespace,
4786
            'soapaction' => $soapaction,
4787
            'style'      => $style
4788
        );
4789
        if ($this->wsdl) {
4790
            $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
4791
        }
4792
4793
        return true;
4794
    }
4795
4796
    /**
4797
     * Specify a fault to be returned to the client.
4798
     * This also acts as a flag to the server that a fault has occured.
4799
     *
4800
     * @param string $faultcode
4801
     * @param string $faultstring
4802
     * @param string $faultactor
4803
     * @param string $faultdetail
4804
     * @access   public
4805
     */
4806
    public function fault($faultcode, $faultstring, $faultactor = '', $faultdetail = '')
4807
    {
4808
        if ($faultdetail == '' && $this->debug_flag) {
4809
            $faultdetail = $this->getDebug();
4810
        }
4811
        $this->fault                   = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
4812
        $this->fault->soap_defencoding = $this->soap_defencoding;
4813
    }
4814
4815
    /**
4816
     * Sets up wsdl object.
4817
     * Acts as a flag to enable internal WSDL generation
4818
     *
4819
     * @param string $serviceName           , name of the service
4820
     * @param mixed  $namespace             optional 'tns' service namespace or false
4821
     * @param mixed  $endpoint              optional URL of service endpoint or false
4822
     * @param string $style                 optional (rpc|document) WSDL style (also specified by operation)
4823
     * @param string $transport             optional SOAP transport
4824
     * @param mixed  $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
4825
     */
4826
    public function configureWSDL(
0 ignored issues
show
Coding Style introduced by
configureWSDL uses the super-global variable $HTTP_SERVER_VARS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
configureWSDL uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
4827
        $serviceName,
4828
        $namespace = false,
4829
        $endpoint = false,
4830
        $style = 'rpc',
4831
        $transport = 'http://schemas.xmlsoap.org/soap/http',
4832
        $schemaTargetNamespace = false)
4833
    {
4834
        global $HTTP_SERVER_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
4835
4836
        if (isset($_SERVER)) {
4837
            $SERVER_NAME = $_SERVER['SERVER_NAME'];
4838
            $SERVER_PORT = $_SERVER['SERVER_PORT'];
4839
            $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4840
            $HTTPS       = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4841 View Code Duplication
        } elseif (isset($HTTP_SERVER_VARS)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
4842
            $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4843
            $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4844
            $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4845
            $HTTPS       = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4846
        } else {
4847
            $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
4848
        }
4849
        // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4850
        $colon = strpos($SERVER_NAME, ':');
0 ignored issues
show
Bug introduced by
The variable $SERVER_NAME does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4851
        if ($colon) {
4852
            $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4853
        }
4854
        if ($SERVER_PORT == 80) {
4855
            $SERVER_PORT = '';
4856
        } else {
4857
            $SERVER_PORT = ':' . $SERVER_PORT;
0 ignored issues
show
Bug introduced by
The variable $SERVER_PORT does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4858
        }
4859
        if (false == $namespace) {
4860
            $namespace = "http://$SERVER_NAME/soap/$serviceName";
4861
        }
4862
4863
        if (false == $endpoint) {
4864
            if ($HTTPS == '1' || $HTTPS === 'on') {
0 ignored issues
show
Bug introduced by
The variable $HTTPS does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4865
                $SCHEME = 'https';
4866
            } else {
4867
                $SCHEME = 'http';
4868
            }
4869
            $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
0 ignored issues
show
Bug introduced by
The variable $SCRIPT_NAME does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
4870
        }
4871
4872
        if (false == $schemaTargetNamespace) {
4873
            $schemaTargetNamespace = $namespace;
4874
        }
4875
4876
        $this->wsdl                     = new wsdl;
4877
        $this->wsdl->serviceName        = $serviceName;
0 ignored issues
show
Bug introduced by
The property serviceName does not seem to exist in Wsdl.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
4878
        $this->wsdl->endpoint           = $endpoint;
4879
        $this->wsdl->namespaces['tns']  = $namespace;
4880
        $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4881
        $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4882
        if ($schemaTargetNamespace != $namespace) {
4883
            $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4884
        }
4885
        $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4886
        if ($style === 'document') {
4887
            $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4888
        }
4889
        $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace                                   = $schemaTargetNamespace;
4890
        $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array(
4891
            'location' => '',
4892
            'loaded'   => true
4893
        );
4894
        $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0]          = array(
4895
            'location' => '',
4896
            'loaded'   => true
4897
        );
4898
        $this->wsdl->bindings[$serviceName . 'Binding']                                                          = array(
4899
            'name'      => $serviceName . 'Binding',
4900
            'style'     => $style,
4901
            'transport' => $transport,
4902
            'portType'  => $serviceName . 'PortType'
4903
        );
4904
        $this->wsdl->ports[$serviceName . 'Port']                                                                = array(
4905
            'binding'     => $serviceName . 'Binding',
4906
            'location'    => $endpoint,
4907
            'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/'
4908
        );
4909
    }
4910
}
4911
4912
/**
4913
 * Backward compatibility
4914
 */
4915
class Soap_server extends Nusoap_server
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
4916
{
4917
}
4918
4919
?><?php
4920
4921
/**
4922
 * parses a WSDL file, allows access to it's data, other utility methods.
4923
 * also builds WSDL structures programmatically.
4924
 *
4925
 * @author   Dietrich Ayala <[email protected]>
4926
 * @author   Scott Nichol <[email protected]>
4927
 * @access   public
4928
 */
4929
class Wsdl extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
4930
{
4931
    // URL or filename of the root of this WSDL
4932
    public $wsdl;
4933
    // define internal arrays of bindings, ports, operations, messages, etc.
4934
    public $schemas       = array();
4935
    public $currentSchema;
4936
    public $message       = array();
4937
    public $complexTypes  = array();
4938
    public $messages      = array();
4939
    public $currentMessage;
4940
    public $currentOperation;
4941
    public $portTypes     = array();
4942
    public $currentPortType;
4943
    public $bindings      = array();
4944
    public $currentBinding;
4945
    public $ports         = array();
4946
    public $currentPort;
4947
    public $opData        = array();
4948
    public $status        = '';
4949
    public $documentation = false;
4950
    public $endpoint      = '';
4951
    // array of wsdl docs to import
4952
    public $import = array();
4953
    // parser vars
4954
    public $parser;
4955
    public $position    = 0;
4956
    public $depth       = 0;
4957
    public $depth_array = array();
4958
    // for getting wsdl
4959
    public $proxyhost        = '';
4960
    public $proxyport        = '';
4961
    public $proxyusername    = '';
4962
    public $proxypassword    = '';
4963
    public $timeout          = 0;
4964
    public $response_timeout = 30;
4965
    public $curl_options     = array();    // User-specified cURL options
4966
    public $use_curl         = false;            // whether to always try to use cURL
4967
    // for HTTP authentication
4968
    public $username    = '';                // Username for HTTP authentication
4969
    public $password    = '';                // Password for HTTP authentication
4970
    public $authtype    = '';                // Type of HTTP authentication
4971
    public $certRequest = array();        // Certificate for HTTP SSL authentication
4972
4973
    /**
4974
     * constructor
4975
     *
4976
     * @param string      $wsdl             WSDL document URL
4977
     * @param bool|string $proxyhost
4978
     * @param bool|string $proxyport
4979
     * @param bool|string $proxyusername
4980
     * @param bool|string $proxypassword
4981
     * @param integer     $timeout          set the connection timeout
4982
     * @param integer     $response_timeout set the response timeout
4983
     * @param array       $curl_options     user-specified cURL options
0 ignored issues
show
Documentation introduced by
Should the type for parameter $curl_options not be array|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
4984
     * @param boolean     $use_curl         try to use cURL
4985
     * @access public
4986
     * @return Wsdl
0 ignored issues
show
Documentation introduced by
Should the return type not be Wsdl|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
4987
     */
4988
    public function wsdl(
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
4989
        $wsdl = '',
4990
        $proxyhost = false,
4991
        $proxyport = false,
4992
        $proxyusername = false,
4993
        $proxypassword = false,
4994
        $timeout = 0,
4995
        $response_timeout = 30,
4996
        $curl_options = null,
4997
        $use_curl = false)
4998
    {
4999
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of wsdl()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
5000
        $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
5001
        $this->proxyhost        = $proxyhost;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyhost can also be of type boolean. 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...
5002
        $this->proxyport        = $proxyport;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyport can also be of type boolean. 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...
5003
        $this->proxyusername    = $proxyusername;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyusername can also be of type boolean. 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...
5004
        $this->proxypassword    = $proxypassword;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxypassword can also be of type boolean. 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...
5005
        $this->timeout          = $timeout;
5006
        $this->response_timeout = $response_timeout;
5007
        if (is_array($curl_options)) {
5008
            $this->curl_options = $curl_options;
5009
        }
5010
        $this->use_curl = $use_curl;
5011
        $this->fetchWSDL($wsdl);
5012
    }
5013
5014
    /**
5015
     * fetches the WSDL document and parses it
5016
     *
5017
     * @access public
5018
     * @param $wsdl
5019
     */
5020
    public function fetchWSDL($wsdl)
5021
    {
5022
        $this->debug("parse and process WSDL path=$wsdl");
5023
        $this->wsdl = $wsdl;
5024
        // parse wsdl file
5025
        if ($this->wsdl != '') {
5026
            $this->parseWSDL($this->wsdl);
5027
        }
5028
        // imports
5029
        // TODO: handle imports more properly, grabbing them in-line and nesting them
5030
        $imported_urls = array();
5031
        $imported      = 1;
5032
        while ($imported > 0) {
5033
            $imported = 0;
5034
            // Schema imports
5035
            foreach ($this->schemas as $ns => $list) {
5036
                foreach ($list as $xs) {
5037
                    $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
5038 View Code Duplication
                    foreach ($xs->imports as $ns2 => $list2) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5039
                        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...
5040
                            if (!$list2[$ii]['loaded']) {
5041
                                $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
5042
                                $url                                              = $list2[$ii]['location'];
5043
                                if ($url != '') {
5044
                                    $urlparts = parse_url($url);
5045
                                    if (!isset($urlparts['host'])) {
5046
                                        $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
5047
                                    }
5048
                                    if (!in_array($url, $imported_urls)) {
5049
                                        $this->parseWSDL($url);
5050
                                        ++$imported;
5051
                                        $imported_urls[] = $url;
5052
                                    }
5053
                                } else {
5054
                                    $this->debug('Unexpected scenario: empty URL for unloaded import');
5055
                                }
5056
                            }
5057
                        }
5058
                    }
5059
                }
5060
            }
5061
            // WSDL imports
5062
            $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
5063 View Code Duplication
            foreach ($this->import as $ns => $list) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5064
                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...
5065
                    if (!$list[$ii]['loaded']) {
5066
                        $this->import[$ns][$ii]['loaded'] = true;
5067
                        $url                              = $list[$ii]['location'];
5068
                        if ($url != '') {
5069
                            $urlparts = parse_url($url);
5070
                            if (!isset($urlparts['host'])) {
5071
                                $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
5072
                            }
5073
                            if (!in_array($url, $imported_urls)) {
5074
                                $this->parseWSDL($url);
5075
                                ++$imported;
5076
                                $imported_urls[] = $url;
5077
                            }
5078
                        } else {
5079
                            $this->debug('Unexpected scenario: empty URL for unloaded import');
5080
                        }
5081
                    }
5082
                }
5083
            }
5084
        }
5085
        // add new data to operation data
5086
        foreach ($this->bindings as $binding => $bindingData) {
5087
            if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
5088
                foreach ($bindingData['operations'] as $operation => $data) {
5089
                    $this->debug('post-parse data gathering for ' . $operation);
5090
                    $this->bindings[$binding]['operations'][$operation]['input']  = isset($this->bindings[$binding]['operations'][$operation]['input']) ? array_merge($this->bindings[$binding]['operations'][$operation]['input'],
5091
                                                                                                                                                                      $this->portTypes[$bindingData['portType']][$operation]['input']) : $this->portTypes[$bindingData['portType']][$operation]['input'];
5092
                    $this->bindings[$binding]['operations'][$operation]['output'] = isset($this->bindings[$binding]['operations'][$operation]['output']) ? array_merge($this->bindings[$binding]['operations'][$operation]['output'],
5093
                                                                                                                                                                       $this->portTypes[$bindingData['portType']][$operation]['output']) : $this->portTypes[$bindingData['portType']][$operation]['output'];
5094 View Code Duplication
                    if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5095
                        $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']];
5096
                    }
5097 View Code Duplication
                    if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5098
                        $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']];
5099
                    }
5100
                    // Set operation style if necessary, but do not override one already provided
5101
                    if (isset($bindingData['style'])
5102
                        && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
5103
                        $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
5104
                    }
5105
                    $this->bindings[$binding]['operations'][$operation]['transport']     = isset($bindingData['transport']) ? $bindingData['transport'] : '';
5106
                    $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[$bindingData['portType']][$operation]['documentation']) ? $this->portTypes[$bindingData['portType']][$operation]['documentation'] : '';
5107
                    $this->bindings[$binding]['operations'][$operation]['endpoint']      = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
5108
                }
5109
            }
5110
        }
5111
    }
5112
5113
    /**
5114
     * parses the wsdl document
5115
     *
5116
     * @param string $wsdl path or URL
5117
     * @access private
5118
     * @return bool
5119
     */
5120
    public function parseWSDL($wsdl = '')
5121
    {
5122
        $this->debug("parse WSDL at path=$wsdl");
5123
5124
        if ($wsdl == '') {
5125
            $this->debug('no wsdl passed to parseWSDL()!!');
5126
            $this->setError('no wsdl passed to parseWSDL()!!');
5127
5128
            return false;
5129
        }
5130
5131
        // parse $wsdl for url format
5132
        $wsdl_props = parse_url($wsdl);
5133
5134
        if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] === 'http' || $wsdl_props['scheme'] === 'https')) {
5135
            $this->debug('getting WSDL http(s) URL ' . $wsdl);
5136
            // get wsdl
5137
            $tr                 = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
5138
            $tr->request_method = 'GET';
5139
            $tr->useSOAPAction  = false;
5140 View Code Duplication
            if ($this->proxyhost && $this->proxyport) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5141
                $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
5142
            }
5143 View Code Duplication
            if ($this->authtype != '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5144
                $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
5145
            }
5146
            $tr->setEncoding('gzip, deflate');
5147
            $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
5148
            //$this->debug("WSDL request\n" . $tr->outgoing_payload);
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5149
            //$this->debug("WSDL response\n" . $tr->incoming_payload);
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5150
            $this->appendDebug($tr->getDebug());
5151
            // catch errors
5152
            if ($err = $tr->getError()) {
5153
                $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err;
5154
                $this->debug($errstr);
5155
                $this->setError($errstr);
5156
                unset($tr);
5157
5158
                return false;
5159
            }
5160
            unset($tr);
5161
            $this->debug('got WSDL URL');
5162
        } else {
5163
            // $wsdl is not http(s), so treat it as a file URL or plain file path
5164
            if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] === 'file') && isset($wsdl_props['path'])) {
5165
                $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
5166
            } else {
5167
                $path = $wsdl;
5168
            }
5169
            $this->debug('getting WSDL file ' . $path);
5170
            if ($fp = @fopen($path, 'r')) {
5171
                $wsdl_string = '';
5172
                while ($data = fread($fp, 32768)) {
5173
                    $wsdl_string .= $data;
5174
                }
5175
                fclose($fp);
5176
            } else {
5177
                $errstr = "Bad path to WSDL file $path";
5178
                $this->debug($errstr);
5179
                $this->setError($errstr);
5180
5181
                return false;
5182
            }
5183
        }
5184
        $this->debug('Parse WSDL');
5185
        // end new code added
5186
        // Create an XML parser.
5187
        $this->parser = xml_parser_create();
5188
        // Set the options for parsing the XML data.
5189
        // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5190
        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
5191
        // Set the object for the parser.
5192
        xml_set_object($this->parser, $this);
5193
        // Set the element handlers for the parser.
5194
        xml_set_element_handler($this->parser, 'start_element', 'end_element');
5195
        xml_set_character_data_handler($this->parser, 'character_data');
5196
        // Parse the XML file.
5197 View Code Duplication
        if (!xml_parse($this->parser, $wsdl_string, true)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5198
            // Display an error message.
5199
            $errstr = sprintf('XML error parsing WSDL from %s on line %d: %s', $wsdl, xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)));
5200
            $this->debug($errstr);
5201
            $this->debug("XML payload:\n" . $wsdl_string);
5202
            $this->setError($errstr);
5203
5204
            return false;
5205
        }
5206
        // free the parser
5207
        xml_parser_free($this->parser);
5208
        $this->debug('Parsing WSDL done');
5209
        // catch wsdl parse errors
5210
        if ($this->getError()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getError() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
5211
            return false;
5212
        }
5213
5214
        return true;
5215
    }
5216
5217
    /**
5218
     * start-element handler
5219
     *
5220
     * @param string $parser XML parser object
5221
     * @param string $name   element name
5222
     * @param string $attrs  associative array of attributes
5223
     * @access private
5224
     */
5225
    public function start_element($parser, $name, $attrs)
5226
    {
5227
        if ($this->status === 'schema') {
5228
            $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5229
            $this->appendDebug($this->currentSchema->getDebug());
5230
            $this->currentSchema->clearDebug();
5231
        } elseif (preg_match('/schema$/', $name)) {
5232
            $this->debug('Parsing WSDL schema');
5233
            // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
0 ignored issues
show
Unused Code Comprehensibility introduced by
71% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5234
            $this->status        = 'schema';
5235
            $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
5236
            $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5237
            $this->appendDebug($this->currentSchema->getDebug());
5238
            $this->currentSchema->clearDebug();
5239
        } else {
5240
            // position in the total number of elements, starting from 0
5241
            $pos   = $this->position++;
5242
            $depth = $this->depth++;
5243
            // set self as current value for this depth
5244
            $this->depth_array[$depth] = $pos;
5245
            $this->message[$pos]       = array('cdata' => '');
5246
            // process attributes
5247
            if (count($attrs) > 0) {
5248
                // register namespace declarations
5249
                foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
5250
                    if (preg_match('/^xmlns/', $k)) {
5251
                        if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
5252
                            $this->namespaces[$ns_prefix] = $v;
5253
                        } else {
5254
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
5255
                        }
5256 View Code Duplication
                        if ($v === 'http://www.w3.org/2001/XMLSchema' || $v === 'http://www.w3.org/1999/XMLSchema'
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5257
                            || $v === 'http://www.w3.org/2000/10/XMLSchema') {
5258
                            $this->XMLSchemaVersion  = $v;
5259
                            $this->namespaces['xsi'] = $v . '-instance';
5260
                        }
5261
                    }
5262
                }
5263
                // expand each attribute prefix to its namespace
5264
                foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
5265
                    $k = strpos($k, ':') ? $this->expandQname($k) : $k;
5266
                    if ($k !== 'location' && $k !== 'soapAction' && $k !== 'namespace') {
5267
                        $v = strpos($v, ':') ? $this->expandQname($v) : $v;
5268
                    }
5269
                    $eAttrs[$k] = $v;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$eAttrs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $eAttrs = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
5270
                }
5271
                $attrs = $eAttrs;
0 ignored issues
show
Bug introduced by
The variable $eAttrs does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5272
            } else {
5273
                $attrs = array();
5274
            }
5275
            // get element prefix, namespace and name
5276
            if (preg_match('/:/', $name)) {
5277
                // get ns prefix
5278
                $prefix = substr($name, 0, strpos($name, ':'));
5279
                // get ns
5280
                $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
5281
                // get unqualified name
5282
                $name = substr(strstr($name, ':'), 1);
5283
            }
5284
            // process attributes, expanding any prefixes to namespaces
5285
            // find status, register data
5286
            switch ($this->status) {
5287
                case 'message':
5288
                    if ($name === 'part') {
5289 View Code Duplication
                        if (isset($attrs['type'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5290
                            $this->debug('msg ' . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
5291
                            $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
5292
                        }
5293 View Code Duplication
                        if (isset($attrs['element'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5294
                            $this->debug('msg ' . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
5295
                            $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
5296
                        }
5297
                    }
5298
                    break;
5299
                case 'portType':
5300
                    switch ($name) {
5301
                        case 'operation':
5302
                            $this->currentPortOperation = $attrs['name'];
0 ignored issues
show
Bug introduced by
The property currentPortOperation does not seem to exist. Did you mean currentPort?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5303
                            $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
0 ignored issues
show
Bug introduced by
The property currentPortOperation does not seem to exist. Did you mean currentPort?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5304
                            if (isset($attrs['parameterOrder'])) {
5305
                                $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
5306
                            }
5307
                            break;
5308
                        case 'documentation':
5309
                            $this->documentation = true;
5310
                            break;
5311
                        // merge input/output data
5312
                        default:
5313
                            $m                                                                                      = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
5314
                            $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
0 ignored issues
show
Bug introduced by
The property currentPortOperation does not seem to exist. Did you mean currentPort?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5315
                            break;
5316
                    }
5317
                    break;
5318
                case 'binding':
5319
                    switch ($name) {
5320
                        case 'binding':
5321
                            // get ns prefix
5322
                            if (isset($attrs['style'])) {
5323
                                $this->bindings[$this->currentBinding]['prefix'] = $prefix;
0 ignored issues
show
Bug introduced by
The variable $prefix does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5324
                            }
5325
                            $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
5326
                            break;
5327
                        case 'header':
5328
                            $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
0 ignored issues
show
Bug introduced by
The property opStatus does not seem to exist. Did you mean status?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5329
                            break;
5330
                        case 'operation':
5331 View Code Duplication
                            if (isset($attrs['soapAction'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5332
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
5333
                            }
5334 View Code Duplication
                            if (isset($attrs['style'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5335
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
5336
                            }
5337
                            if (isset($attrs['name'])) {
5338
                                $this->currentOperation = $attrs['name'];
5339
                                $this->debug("current binding operation: $this->currentOperation");
5340
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name']     = $attrs['name'];
5341
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding']  = $this->currentBinding;
5342
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
5343
                            }
5344
                            break;
5345
                        case 'input':
5346
                            $this->opStatus = 'input';
0 ignored issues
show
Bug introduced by
The property opStatus does not seem to exist. Did you mean status?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5347
                            break;
5348
                        case 'output':
5349
                            $this->opStatus = 'output';
0 ignored issues
show
Bug introduced by
The property opStatus does not seem to exist. Did you mean status?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5350
                            break;
5351
                        case 'body':
5352
                            if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
0 ignored issues
show
Bug introduced by
The property opStatus does not seem to exist. Did you mean status?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5353
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
0 ignored issues
show
Bug introduced by
The property opStatus does not seem to exist. Did you mean status?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5354
                            } else {
5355
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
0 ignored issues
show
Bug introduced by
The property opStatus does not seem to exist. Did you mean status?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
5356
                            }
5357
                            break;
5358
                    }
5359
                    break;
5360
                case 'service':
5361
                    switch ($name) {
5362
                        case 'port':
5363
                            $this->currentPort = $attrs['name'];
5364
                            $this->debug('current port: ' . $this->currentPort);
5365
                            $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
5366
5367
                            break;
5368
                        case 'address':
5369
                            $this->ports[$this->currentPort]['location']                                = $attrs['location'];
5370
                            $this->ports[$this->currentPort]['bindingType']                             = $namespace;
0 ignored issues
show
Bug introduced by
The variable $namespace does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5371
                            $this->bindings[$this->ports[$this->currentPort]['binding']]['bindingType'] = $namespace;
5372
                            $this->bindings[$this->ports[$this->currentPort]['binding']]['endpoint']    = $attrs['location'];
5373
                            break;
5374
                    }
5375
                    break;
5376
            }
5377
            // set status
5378
            switch ($name) {
5379
                case 'import':
5380
                    if (isset($attrs['location'])) {
5381
                        $this->import[$attrs['namespace']][] = array(
5382
                            'location' => $attrs['location'],
5383
                            'loaded'   => false
5384
                        );
5385
                        $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')');
5386
                    } else {
5387
                        $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
5388 View Code Duplication
                        if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5389
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
5390
                        }
5391
                        $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')');
5392
                    }
5393
                    break;
5394
                //wait for schema
5395
                //case 'types':
5396
                //  $this->status = 'schema';
0 ignored issues
show
Unused Code Comprehensibility introduced by
45% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5397
                //  break;
5398
                case 'message':
5399
                    $this->status                   = 'message';
5400
                    $this->messages[$attrs['name']] = array();
5401
                    $this->currentMessage           = $attrs['name'];
5402
                    break;
5403
                case 'portType':
5404
                    $this->status                    = 'portType';
5405
                    $this->portTypes[$attrs['name']] = array();
5406
                    $this->currentPortType           = $attrs['name'];
5407
                    break;
5408
                case 'binding':
5409
                    if (isset($attrs['name'])) {
5410
                        // get binding name
5411
                        if (strpos($attrs['name'], ':')) {
5412
                            $this->currentBinding = $this->getLocalPart($attrs['name']);
5413
                        } else {
5414
                            $this->currentBinding = $attrs['name'];
5415
                        }
5416
                        $this->status                                      = 'binding';
5417
                        $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
5418
                        $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
5419
                    }
5420
                    break;
5421
                case 'service':
5422
                    $this->serviceName = $attrs['name'];
0 ignored issues
show
Bug introduced by
The property serviceName does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
5423
                    $this->status      = 'service';
5424
                    $this->debug('current service: ' . $this->serviceName);
5425
                    break;
5426
                case 'definitions':
5427
                    foreach ($attrs as $name => $value) {
5428
                        $this->wsdl_info[$name] = $value;
0 ignored issues
show
Bug introduced by
The property wsdl_info does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
5429
                    }
5430
                    break;
5431
            }
5432
        }
5433
    }
5434
5435
    /**
5436
     * end-element handler
5437
     *
5438
     * @param string $parser XML parser object
5439
     * @param string $name   element name
5440
     * @access private
5441
     */
5442
    public function end_element($parser, $name)
5443
    {
5444
        // unset schema status
5445
        if (/*preg_match('/types$/', $name) ||*/
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5446
        preg_match('/schema$/', $name)) {
5447
            $this->status = '';
5448
            $this->appendDebug($this->currentSchema->getDebug());
5449
            $this->currentSchema->clearDebug();
5450
            $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5451
            $this->debug('Parsing WSDL schema done');
5452
        }
5453
        if ($this->status === 'schema') {
5454
            $this->currentSchema->schemaEndElement($parser, $name);
5455
        } else {
5456
            // bring depth down a notch
5457
            $this->depth--;
5458
        }
5459
        // end documentation
5460
        if ($this->documentation) {
5461
            //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5462
            //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5463
            $this->documentation = false;
5464
        }
5465
    }
5466
5467
    /**
5468
     * element content handler
5469
     *
5470
     * @param string $parser XML parser object
5471
     * @param string $data   element content
5472
     * @access private
5473
     */
5474
    public function character_data($parser, $data)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
5475
    {
5476
        $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5477 View Code Duplication
        if (isset($this->message[$pos]['cdata'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5478
            $this->message[$pos]['cdata'] .= $data;
5479
        }
5480
        if ($this->documentation) {
5481
            $this->documentation .= $data;
5482
        }
5483
    }
5484
5485
    /**
5486
     * if authenticating, set user credentials here
5487
     *
5488
     * @param string $username
5489
     * @param string $password
5490
     * @param string $authtype    (basic|digest|certificate|ntlm)
5491
     * @param array  $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
5492
     * @access   public
5493
     */
5494 View Code Duplication
    public function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5495
    {
5496
        $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5497
        $this->appendDebug($this->varDump($certRequest));
5498
        $this->username    = $username;
5499
        $this->password    = $password;
5500
        $this->authtype    = $authtype;
5501
        $this->certRequest = $certRequest;
5502
    }
5503
5504
    /**
5505
     * @param $binding
5506
     * @return mixed
5507
     */
5508
    public function getBindingData($binding)
5509
    {
5510
        if (is_array($this->bindings[$binding])) {
5511
            return $this->bindings[$binding];
5512
        }
5513
    }
5514
5515
    /**
5516
     * returns an assoc array of operation names => operation data
5517
     *
5518
     * @param  string $portName    WSDL port name
5519
     * @param  string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
5520
     * @return array
5521
     * @access public
5522
     */
5523
    public function getOperations($portName = '', $bindingType = 'soap')
5524
    {
5525
        $ops = array();
5526
        if ($bindingType === 'soap') {
5527
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5528
        } elseif ($bindingType === 'soap12') {
5529
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5530
        } else {
5531
            $this->debug("getOperations bindingType $bindingType may not be supported");
5532
        }
5533
        $this->debug("getOperations for port '$portName' bindingType $bindingType");
5534
        // loop thru ports
5535
        foreach ($this->ports as $port => $portData) {
5536
            $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
5537
            if ($portName == '' || $port == $portName) {
5538
                // binding type of port matches parameter
5539
                if ($portData['bindingType'] == $bindingType) {
5540
                    $this->debug("getOperations found port $port bindingType $bindingType");
5541
                    //$this->debug("port data: " . $this->varDump($portData));
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5542
                    //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5543
                    // merge bindings
5544
                    if (isset($this->bindings[$portData['binding']]['operations'])) {
5545
                        $ops = array_merge($ops, $this->bindings[$portData['binding']]['operations']);
5546
                    }
5547
                }
5548
            }
5549
        }
5550
        if (count($ops) == 0) {
5551
            $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
5552
        }
5553
5554
        return $ops;
5555
    }
5556
5557
    /**
5558
     * returns an associative array of data necessary for calling an operation
5559
     *
5560
     * @param  string $operation   name of operation
5561
     * @param  string $bindingType type of binding eg: soap, soap12
5562
     * @return array
5563
     * @access public
5564
     */
5565
    public function getOperationData($operation, $bindingType = 'soap')
5566
    {
5567
        if ($bindingType === 'soap') {
5568
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5569
        } elseif ($bindingType === 'soap12') {
5570
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5571
        }
5572
        // loop thru ports
5573
        foreach ($this->ports as $port => $portData) {
5574
            // binding type of port matches parameter
5575
            if ($portData['bindingType'] == $bindingType) {
5576
                // get binding
5577
                //foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
68% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5578
                foreach (array_keys($this->bindings[$portData['binding']]['operations']) as $bOperation) {
5579
                    // note that we could/should also check the namespace here
5580
                    if ($operation == $bOperation) {
5581
                        $opData = $this->bindings[$portData['binding']]['operations'][$operation];
5582
5583
                        return $opData;
5584
                    }
5585
                }
5586
            }
5587
        }
5588
    }
5589
5590
    /**
5591
     * returns an associative array of data necessary for calling an operation
5592
     *
5593
     * @param  string $soapAction  soapAction for operation
5594
     * @param  string $bindingType type of binding eg: soap, soap12
5595
     * @return array
5596
     * @access public
5597
     */
5598
    public function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
5599
    {
5600
        if ($bindingType === 'soap') {
5601
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5602
        } elseif ($bindingType === 'soap12') {
5603
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5604
        }
5605
        // loop thru ports
5606
        foreach ($this->ports as $port => $portData) {
5607
            // binding type of port matches parameter
5608
            if ($portData['bindingType'] == $bindingType) {
5609
                // loop through operations for the binding
5610
                foreach ($this->bindings[$portData['binding']]['operations'] as $bOperation => $opData) {
5611
                    if ($opData['soapAction'] == $soapAction) {
5612
                        return $opData;
5613
                    }
5614
                }
5615
            }
5616
        }
5617
    }
5618
5619
    /**
5620
     * returns an array of information about a given type
5621
     * returns false if no type exists by the given name
5622
     *
5623
     *    typeDef = array(
5624
     *    'elements' => array(), // refs to elements array
5625
     *   'restrictionBase' => '',
5626
     *   'phpType' => '',
5627
     *   'order' => '(sequence|all)',
5628
     *   'attrs' => array() // refs to attributes array
5629
     *   )
5630
     *
5631
     * @param  string $type the type
5632
     * @param  string $ns   namespace (not prefix) of the type
5633
     * @return mixed
5634
     * @access public
5635
     * @see    nusoap_xmlschema
5636
     */
5637
    public function getTypeDef($type, $ns)
5638
    {
5639
        $this->debug("in getTypeDef: type=$type, ns=$ns");
5640
        if ((!$ns) && isset($this->namespaces['tns'])) {
5641
            $ns = $this->namespaces['tns'];
5642
            $this->debug("in getTypeDef: type namespace forced to $ns");
5643
        }
5644
        if (!isset($this->schemas[$ns])) {
5645
            foreach ($this->schemas as $ns0 => $schema0) {
5646
                if (strcasecmp($ns, $ns0) == 0) {
5647
                    $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5648
                    $ns = $ns0;
5649
                    break;
5650
                }
5651
            }
5652
        }
5653
        if (isset($this->schemas[$ns])) {
5654
            $this->debug("in getTypeDef: have schema for namespace $ns");
5655
            for ($i = 0, $iMax = count($this->schemas[$ns]); $i < $iMax; ++$i) {
5656
                $xs =& $this->schemas[$ns][$i];
5657
                $t  = $xs->getTypeDef($type);
5658
                $this->appendDebug($xs->getDebug());
5659
                $xs->clearDebug();
5660
                if ($t) {
5661
                    $this->debug("in getTypeDef: found type $type");
5662
                    if (!isset($t['phpType'])) {
5663
                        // get info for type to tack onto the element
5664
                        $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5665
                        $ns     = substr($t['type'], 0, strrpos($t['type'], ':'));
5666
                        $etype  = $this->getTypeDef($uqType, $ns);
5667
                        if ($etype) {
5668
                            $this->debug("found type for [element] $type:");
5669
                            $this->debug($this->varDump($etype));
5670
                            if (isset($etype['phpType'])) {
5671
                                $t['phpType'] = $etype['phpType'];
5672
                            }
5673
                            if (isset($etype['elements'])) {
5674
                                $t['elements'] = $etype['elements'];
5675
                            }
5676
                            if (isset($etype['attrs'])) {
5677
                                $t['attrs'] = $etype['attrs'];
5678
                            }
5679
                        } else {
5680
                            $this->debug("did not find type for [element] $type");
5681
                        }
5682
                    }
5683
5684
                    return $t;
5685
                }
5686
            }
5687
            $this->debug("in getTypeDef: did not find type $type");
5688
        } else {
5689
            $this->debug("in getTypeDef: do not have schema for namespace $ns");
5690
        }
5691
5692
        return false;
5693
    }
5694
5695
    /**
5696
     * prints html description of services
5697
     *
5698
     * @access private
5699
     */
5700
    public function webDescription()
0 ignored issues
show
Coding Style introduced by
webDescription uses the super-global variable $HTTP_SERVER_VARS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
webDescription uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
5701
    {
5702
        global $HTTP_SERVER_VARS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
5703
5704
        if (isset($_SERVER)) {
5705
            $PHP_SELF = $_SERVER['PHP_SELF'];
5706
        } elseif (isset($HTTP_SERVER_VARS)) {
5707
            $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5708
        } else {
5709
            $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
5710
        }
5711
5712
        $b = '
5713
        <html><head><title>NuSOAP: ' . $this->serviceName . '</title>
5714
        <style type="text/css">
5715
            body    { font-family: Arial, sans-serif; color: #000000; background-color: #ffffff; margin: 0 0 0 0; }
5716
            p       { font-family: Arial, sans-serif; color: #000000; margin-top: 0; margin-bottom: 12px; }
5717
            pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5718
            ul      { margin-top: 10px; margin-left: 20px; }
5719
            li      { list-style-type: none; margin-top: 10px; color: #000000; }
5720
            .content{
5721
            margin-left: 0; padding-bottom: 2em; }
5722
            .nav {
5723
            padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5724
            margin-top: 10px; margin-left: 0; color: #000000;
5725
            background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5726
            .title {
5727
            font-family: Arial, sans-serif; font-size: 26px; color: #ffffff;
5728
            background-color: #999999; width: 100%;
5729
            margin-left: 0; margin-right: 0;
5730
            padding-top: 10px; padding-bottom: 10px;}
5731
            .hidden {
5732
            position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5733
            font-family: Arial, sans-serif; overflow: hidden; width: 600;
5734
            padding: 20px; font-size: 10px; background-color: #999999;
5735
            layer-background-color:#FFFFFF; }
5736
            a,a:active  { color: charcoal; font-weight: bold; }
5737
            a:visited   { color: #666666; font-weight: bold; }
5738
            a:hover     { color: cc3300; font-weight: bold; }
5739
        </style>
5740
        <script language="JavaScript" type="text/javascript">
5741
        <!--
5742
        // POP-UP CAPTIONS...
5743
        function lib_bwcheck(){ //Browsercheck (needed)
5744
            this.ver=navigator.appVersion
5745
            this.agent=navigator.userAgent
5746
            this.dom=document.getElementById?1:0
5747
            this.opera5=this.agent.indexOf("Opera 5")>-1
5748
            this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5749
            this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5750
            this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5751
            this.ie=this.ie4||this.ie5||this.ie6
5752
            this.mac=this.agent.indexOf("Mac")>-1
5753
            this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5754
            this.ns4=(document.layers && !this.dom)?1:0;
5755
            this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5756
5757
            return this
5758
        }
5759
        var bw = new Lib_bwcheck()
5760
        //Makes crossbrowser object.
5761
        function makeObj(obj){
5762
            this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5763
            if(!this.evnt) return false
5764
            this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5765
            this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5766
            this.writeIt=b_writeIt;
5767
5768
            return this
5769
        }
5770
        // A unit of measure that will be added when setting the position of a layer.
5771
        //var px = bw.ns4||window.opera?"":"px";
5772
        function b_writeIt(text){
5773
            if (bw.ns4) {this.wref.write(text);this.wref.close()}
5774
            else this.wref.innerHTML = text
5775
        }
5776
        //Shows the messages
5777
        var oDesc;
5778
        function popup(divid){
5779
            if (oDesc = new MakeObj(divid)) {
5780
            oDesc.css.visibility = "visible"
5781
            }
5782
        }
5783
        function popout(){ // Hides message
5784
            if(oDesc) oDesc.css.visibility = "hidden"
5785
        }
5786
        //-->
5787
        </script>
5788
        </head>
5789
        <body>
5790
        <div class=content>
5791
            <br><br>
5792
            <div class=title>' . $this->serviceName . '</div>
5793
            <div class=nav>
5794
                <p>View the <a href="' . $PHP_SELF . '?wsdl">WSDL</a> for the service.
0 ignored issues
show
Bug introduced by
The variable $PHP_SELF does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
5795
                Click on an operation name to view it&apos;s details.</p>
5796
                <ul>';
5797
        foreach ($this->getOperations() as $op => $data) {
5798
            $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5799
            // create hidden div
5800
            $b .= "<div id='$op' class='hidden'>
5801
                    <a href='#' onclick='popout()'><span style='color: #ffffff;'>Close</span></a><br><br>";
5802
            foreach ($data as $donnie => $marie) { // loop through opdata
5803
                if ($donnie === 'input' || $donnie === 'output') { // show input/output data
5804
                    $b .= "<font color='white'>" . ucfirst($donnie) . ':</font><br>';
5805
                    foreach ($marie as $captain => $tenille) { // loop through data
5806
                        if ($captain === 'parts') { // loop thru parts
5807
                            $b .= "&nbsp;&nbsp;$captain:<br>";
5808
                            //if (is_array($tenille)) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
70% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5809
                            foreach ($tenille as $joanie => $chachi) {
5810
                                $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5811
                            }
5812
                            //}
5813
                        } else {
5814
                            $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5815
                        }
5816
                    }
5817
                } else {
5818
                    $b .= "<font color='white'>" . ucfirst($donnie) . ":</font> $marie<br>";
5819
                }
5820
            }
5821
            $b .= '</div>';
5822
        }
5823
        $b .= '
5824
                <ul>
5825
            </div>
5826
        </div></body></html>';
5827
5828
        return $b;
5829
    }
5830
5831
    /**
5832
     * serialize the parsed wsdl
5833
     *
5834
     * @param  mixed $debug whether to put debug=1 in endpoint URL
5835
     * @return string serialization of WSDL
0 ignored issues
show
Documentation introduced by
Should the return type not be null|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
5836
     * @access public
5837
     */
5838
    public function serialize($debug = 0)
5839
    {
5840
        $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5841
        $xml .= "\n<definitions";
5842
        foreach ($this->namespaces as $k => $v) {
5843
            $xml .= " xmlns:$k=\"$v\"";
5844
        }
5845
        // 10.9.02 - add poulter fix for wsdl and tns declarations
5846 View Code Duplication
        if (isset($this->namespaces['wsdl'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5847
            $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5848
        }
5849 View Code Duplication
        if (isset($this->namespaces['tns'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5850
            $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5851
        }
5852
        $xml .= '>';
5853
        // imports
5854 View Code Duplication
        if (count($this->import) > 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5855
            foreach ($this->import as $ns => $list) {
5856
                foreach ($list as $ii) {
5857
                    if ($ii['location'] != '') {
5858
                        $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '">';
5859
                    } else {
5860
                        $xml .= '<import namespace="' . $ns . '">';
5861
                    }
5862
                }
5863
            }
5864
        }
5865
        // types
5866
        if (count($this->schemas) >= 1) {
5867
            $xml .= "\n<types>\n";
5868
            foreach ($this->schemas as $ns => $list) {
5869
                foreach ($list as $xs) {
5870
                    $xml .= $xs->serializeSchema();
5871
                }
5872
            }
5873
            $xml .= '</types>';
5874
        }
5875
        // messages
5876
        if (count($this->messages) >= 1) {
5877
            foreach ($this->messages as $msgName => $msgParts) {
5878
                $xml .= "\n<message name=\"" . $msgName . '">';
5879
                if (is_array($msgParts)) {
5880
                    foreach ($msgParts as $partName => $partType) {
5881
                        // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'<br>';
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5882
                        if (strpos($partType, ':')) {
5883
                            $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
0 ignored issues
show
Security Bug introduced by
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...
5884
                        } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5885
                            // print 'checking typemap: '.$this->XMLSchemaVersion.'<br>';
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
5886
                            $typePrefix = 'xsd';
5887
                        } else {
5888
                            foreach ($this->typemap as $ns => $types) {
5889
                                if (isset($types[$partType])) {
5890
                                    $typePrefix = $this->getPrefixFromNamespace($ns);
5891
                                }
5892
                            }
5893
                            if (!isset($typePrefix)) {
5894
                                die("$partType has no namespace!");
0 ignored issues
show
Coding Style Compatibility introduced by
The method serialize() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
5895
                            }
5896
                        }
5897
                        $ns        = $this->getNamespaceFromPrefix($typePrefix);
5898
                        $localPart = $this->getLocalPart($partType);
5899
                        $typeDef   = $this->getTypeDef($localPart, $ns);
5900
                        if ($typeDef['typeClass'] === 'element') {
5901
                            $elementortype = 'element';
5902
                            if (substr($localPart, -1) === '^') {
5903
                                $localPart = substr($localPart, 0, -1);
5904
                            }
5905
                        } else {
5906
                            $elementortype = 'type';
5907
                        }
5908
                        $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '">';
5909
                    }
5910
                }
5911
                $xml .= '</message>';
5912
            }
5913
        }
5914
        // bindings & porttypes
5915
        if (count($this->bindings) >= 1) {
5916
            $binding_xml  = '';
5917
            $portType_xml = '';
5918
            foreach ($this->bindings as $bindingName => $attrs) {
5919
                $binding_xml  .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5920
                $binding_xml  .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '">';
5921
                $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5922
                foreach ($attrs['operations'] as $opName => $opParts) {
5923
                    $binding_xml .= "\n" . '  <operation name="' . $opName . '">';
5924
                    $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '">';
5925 View Code Duplication
                    if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5926
                        $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5927
                    } else {
5928
                        $enc_style = '';
5929
                    }
5930
                    $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '></input>';
5931 View Code Duplication
                    if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
5932
                        $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5933
                    } else {
5934
                        $enc_style = '';
5935
                    }
5936
                    $binding_xml  .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '></output>';
5937
                    $binding_xml  .= "\n" . '  </operation>';
5938
                    $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
5939
                    if (isset($opParts['parameterOrder'])) {
5940
                        $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5941
                    }
5942
                    $portType_xml .= '>';
5943
                    if (isset($opParts['documentation']) && $opParts['documentation'] != '') {
5944
                        $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5945
                    }
5946
                    $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '">';
5947
                    $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '">';
5948
                    $portType_xml .= "\n" . '  </operation>';
5949
                }
5950
                $portType_xml .= "\n" . '</portType>';
5951
                $binding_xml  .= "\n" . '</binding>';
5952
            }
5953
            $xml .= $portType_xml . $binding_xml;
5954
        }
5955
        // services
5956
        $xml .= "\n<service name=\"" . $this->serviceName . '">';
5957
        if (count($this->ports) >= 1) {
5958
            foreach ($this->ports as $pName => $attrs) {
5959
                $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5960
                $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '">';
5961
                $xml .= "\n" . '  </port>';
5962
            }
5963
        }
5964
        $xml .= "\n" . '</service>';
5965
5966
        return $xml . "\n</definitions>";
5967
    }
5968
5969
    /**
5970
     * determine whether a set of parameters are unwrapped
5971
     * when they are expect to be wrapped, Microsoft-style.
5972
     *
5973
     * @param  string $type       the type (element name) of the wrapper
5974
     * @param  array  $parameters the parameter values for the SOAP call
5975
     * @return boolean whether they parameters are unwrapped (and should be wrapped)
5976
     * @access private
5977
     */
5978
    public function parametersMatchWrapped($type, &$parameters)
5979
    {
5980
        $this->debug("in parametersMatchWrapped type=$type, parameters=");
5981
        $this->appendDebug($this->varDump($parameters));
5982
5983
        // split type into namespace:unqualified-type
5984
        if (strpos($type, ':')) {
5985
            $uqType = substr($type, strrpos($type, ':') + 1);
5986
            $ns     = substr($type, 0, strrpos($type, ':'));
5987
            $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5988
            if ($this->getNamespaceFromPrefix($ns)) {
5989
                $ns = $this->getNamespaceFromPrefix($ns);
5990
                $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5991
            }
5992
        } else {
5993
            // TODO: should the type be compared to types in XSD, and the namespace
5994
            // set to XSD if the type matches?
5995
            $this->debug("in parametersMatchWrapped: No namespace for type $type");
5996
            $ns     = '';
5997
            $uqType = $type;
5998
        }
5999
6000
        // get the type information
6001
        if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6002
            $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
6003
6004
            return false;
6005
        }
6006
        $this->debug('in parametersMatchWrapped: found typeDef=');
6007
        $this->appendDebug($this->varDump($typeDef));
6008 View Code Duplication
        if (substr($uqType, -1) === '^') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6009
            $uqType = substr($uqType, 0, -1);
6010
        }
6011
        $phpType   = $typeDef['phpType'];
6012
        $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
6013
        $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
6014
6015
        // we expect a complexType or element of complexType
6016
        if ($phpType !== 'struct') {
6017
            $this->debug('in parametersMatchWrapped: not a struct');
6018
6019
            return false;
6020
        }
6021
6022
        // see whether the parameter names match the elements
6023
        if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6024
            $elements = 0;
6025
            $matches  = 0;
6026
            foreach ($typeDef['elements'] as $name => $attrs) {
6027
                if (isset($parameters[$name])) {
6028
                    $this->debug("in parametersMatchWrapped: have parameter named $name");
6029
                    ++$matches;
6030
                } else {
6031
                    $this->debug("in parametersMatchWrapped: do not have parameter named $name");
6032
                }
6033
                ++$elements;
6034
            }
6035
6036
            $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
6037
            if ($matches == 0) {
6038
                return false;
6039
            }
6040
6041
            return true;
6042
        }
6043
6044
        // since there are no elements for the type, if the user passed no
6045
        // parameters, the parameters match wrapped.
6046
        $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
6047
6048
        return count($parameters) == 0;
6049
    }
6050
6051
    /**
6052
     * serialize PHP values according to a WSDL message definition
6053
     * contrary to the method name, this is not limited to RPC
6054
     *
6055
     * TODO
6056
     * - multi-ref serialization
6057
     * - validate PHP values against type definitions, return errors if invalid
6058
     *
6059
     * @param  string $operation   operation name
6060
     * @param  string $direction   (input|output)
6061
     * @param  mixed  $parameters  parameter value(s)
6062
     * @param  string $bindingType (soap|soap12)
6063
     * @return mixed  parameters serialized as XML or false on error (e.g. operation not found)
6064
     * @access public
6065
     */
6066
    public function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
6067
    {
6068
        $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
6069
        $this->appendDebug('parameters=' . $this->varDump($parameters));
6070
6071 View Code Duplication
        if ($direction !== 'input' && $direction !== 'output') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6072
            $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
6073
            $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
6074
6075
            return false;
6076
        }
6077
        if (!$opData = $this->getOperationData($operation, $bindingType)) {
6078
            $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
6079
            $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
6080
6081
            return false;
6082
        }
6083
        $this->debug('in serializeRPCParameters: opData:');
6084
        $this->appendDebug($this->varDump($opData));
6085
6086
        // Get encoding style for output and set to current
6087
        $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6088 View Code Duplication
        if (($direction === 'input') && isset($opData['output']['encodingStyle'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6089
            && ($opData['output']['encodingStyle'] != $encodingStyle)) {
6090
            $encodingStyle = $opData['output']['encodingStyle'];
6091
            $enc_style     = $encodingStyle;
0 ignored issues
show
Unused Code introduced by
$enc_style is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
6092
        }
6093
6094
        // set input params
6095
        $xml = '';
6096
        if (isset($opData[$direction]['parts']) && count($opData[$direction]['parts']) > 0) {
6097
            $parts      =& $opData[$direction]['parts'];
6098
            $part_count = count($parts);
6099
            $style      = $opData['style'];
6100
            $use        = $opData[$direction]['use'];
6101
            $this->debug("have $part_count part(s) to serialize using $style/$use");
6102
            if (is_array($parameters)) {
6103
                $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
6104
                $parameter_count     = count($parameters);
6105
                $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
6106
                // check for Microsoft-style wrapped parameters
6107
                if ($style === 'document' && $use === 'literal' && $part_count == 1 && isset($parts['parameters'])) {
6108
                    $this->debug('check whether the caller has wrapped the parameters');
6109
                    if ($direction === 'output' && $parametersArrayType === 'arraySimple' && $parameter_count == 1) {
6110
                        // TODO: consider checking here for double-wrapping, when
6111
                        // service function wraps, then NuSOAP wraps again
6112
                        $this->debug("change simple array to associative with 'parameters' element");
6113
                        $parameters['parameters'] = $parameters[0];
6114
                        unset($parameters[0]);
6115
                    }
6116
                    if (($parametersArrayType === 'arrayStruct' || $parameter_count == 0)
6117
                        && !isset($parameters['parameters'])) {
6118
                        $this->debug('check whether caller\'s parameters match the wrapped ones');
6119
                        if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
6120
                            $this->debug('wrap the parameters for the caller');
6121
                            $parameters      = array('parameters' => $parameters);
6122
                            $parameter_count = 1;
0 ignored issues
show
Unused Code introduced by
$parameter_count is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
6123
                        }
6124
                    }
6125
                }
6126
                foreach ($parts as $name => $type) {
6127
                    $this->debug("serializing part $name of type $type");
6128
                    // Track encoding style
6129 View Code Duplication
                    if (isset($opData[$direction]['encodingStyle'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6130
                        && $encodingStyle != $opData[$direction]['encodingStyle']) {
6131
                        $encodingStyle = $opData[$direction]['encodingStyle'];
6132
                        $enc_style     = $encodingStyle;
6133
                    } else {
6134
                        $enc_style = false;
6135
                    }
6136
                    // NOTE: add error handling here
6137
                    // if serializeType returns false, then catch global error and fault
6138 View Code Duplication
                    if ($parametersArrayType === 'arraySimple') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6139
                        $p = array_shift($parameters);
6140
                        $this->debug('calling serializeType w/indexed param');
6141
                        $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
6142
                    } elseif (isset($parameters[$name])) {
6143
                        $this->debug('calling serializeType w/named param');
6144
                        $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
6145
                    } else {
6146
                        // TODO: only send nillable
6147
                        $this->debug('calling serializeType w/null param');
6148
                        $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
6149
                    }
6150
                }
6151
            } else {
6152
                $this->debug('no parameters passed.');
6153
            }
6154
        }
6155
        $this->debug("serializeRPCParameters returning: $xml");
6156
6157
        return $xml;
6158
    }
6159
6160
    /**
6161
     * serialize a PHP value according to a WSDL message definition
6162
     *
6163
     * TODO
6164
     * - multi-ref serialization
6165
     * - validate PHP values against type definitions, return errors if invalid
6166
     *
6167
     * @param  string $operation  operation name
6168
     * @param  string $direction  (input|output)
6169
     * @param  mixed  $parameters parameter value(s)
6170
     * @return mixed  parameters serialized as XML or false on error (e.g. operation not found)
6171
     * @access public
6172
     * @deprecated
6173
     */
6174
    public function serializeParameters($operation, $direction, $parameters)
6175
    {
6176
        $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
6177
        $this->appendDebug('parameters=' . $this->varDump($parameters));
6178
6179 View Code Duplication
        if ($direction !== 'input' && $direction !== 'output') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6180
            $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
6181
            $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
6182
6183
            return false;
6184
        }
6185
        if (!$opData = $this->getOperationData($operation)) {
6186
            $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
6187
            $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
6188
6189
            return false;
6190
        }
6191
        $this->debug('opData:');
6192
        $this->appendDebug($this->varDump($opData));
6193
6194
        // Get encoding style for output and set to current
6195
        $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6196 View Code Duplication
        if (($direction === 'input') && isset($opData['output']['encodingStyle'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6197
            && ($opData['output']['encodingStyle'] != $encodingStyle)) {
6198
            $encodingStyle = $opData['output']['encodingStyle'];
6199
            $enc_style     = $encodingStyle;
0 ignored issues
show
Unused Code introduced by
$enc_style is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
6200
        }
6201
6202
        // set input params
6203
        $xml = '';
6204
        if (isset($opData[$direction]['parts']) && count($opData[$direction]['parts']) > 0) {
6205
            $use = $opData[$direction]['use'];
6206
            $this->debug("use=$use");
6207
            $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
6208
            if (is_array($parameters)) {
6209
                $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
6210
                $this->debug('have ' . $parametersArrayType . ' parameters');
6211
                foreach ($opData[$direction]['parts'] as $name => $type) {
6212
                    $this->debug('serializing part "' . $name . '" of type "' . $type . '"');
6213
                    // Track encoding style
6214 View Code Duplication
                    if (isset($opData[$direction]['encodingStyle'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6215
                        && $encodingStyle != $opData[$direction]['encodingStyle']) {
6216
                        $encodingStyle = $opData[$direction]['encodingStyle'];
6217
                        $enc_style     = $encodingStyle;
6218
                    } else {
6219
                        $enc_style = false;
6220
                    }
6221
                    // NOTE: add error handling here
6222
                    // if serializeType returns false, then catch global error and fault
6223 View Code Duplication
                    if ($parametersArrayType === 'arraySimple') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6224
                        $p = array_shift($parameters);
6225
                        $this->debug('calling serializeType w/indexed param');
6226
                        $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
6227
                    } elseif (isset($parameters[$name])) {
6228
                        $this->debug('calling serializeType w/named param');
6229
                        $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
6230
                    } else {
6231
                        // TODO: only send nillable
6232
                        $this->debug('calling serializeType w/null param');
6233
                        $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
6234
                    }
6235
                }
6236
            } else {
6237
                $this->debug('no parameters passed.');
6238
            }
6239
        }
6240
        $this->debug("serializeParameters returning: $xml");
6241
6242
        return $xml;
6243
    }
6244
6245
    /**
6246
     * serializes a PHP value according a given type definition
6247
     *
6248
     * @param  string      $name          name of value (part or element)
6249
     * @param  string      $type          XML schema type of value (type or element)
6250
     * @param  mixed       $value         a native PHP value (parameter value)
6251
     * @param  string      $use           use for part (encoded|literal)
6252
     * @param  bool|string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6253
     * @param  boolean     $unqualified   a kludge for what should be XML namespace form handling
6254
     * @return string      value serialized as an XML string
6255
     * @access private
6256
     */
6257
    public function serializeType(
6258
        $name,
6259
        $type,
6260
        $value,
6261
        $use = 'encoded',
6262
        $encodingStyle = false,
6263
        $unqualified = false)
6264
    {
6265
        $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? 'unqualified' : 'qualified'));
6266
        $this->appendDebug('value=' . $this->varDump($value));
6267
        if ($use === 'encoded' && $encodingStyle) {
6268
            $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
6269
        }
6270
6271
        // if a soapval has been supplied, let its type override the WSDL
6272
        if (is_object($value) && get_class($value) === 'soapval') {
6273
            if ($value->type_ns) {
6274
                $type      = $value->type_ns . ':' . $value->type;
6275
                $forceType = true;
6276
                $this->debug("in serializeType: soapval overrides type to $type");
6277
            } elseif ($value->type) {
6278
                $type      = $value->type;
6279
                $forceType = true;
6280
                $this->debug("in serializeType: soapval overrides type to $type");
6281
            } else {
6282
                $forceType = false;
6283
                $this->debug('in serializeType: soapval does not override type');
6284
            }
6285
            $attrs = $value->attributes;
6286
            $value = $value->value;
6287
            $this->debug("in serializeType: soapval overrides value to $value");
6288
            if ($attrs) {
6289
                if (!is_array($value)) {
6290
                    $value['!'] = $value;
6291
                }
6292
                foreach ($attrs as $n => $v) {
6293
                    $value['!' . $n] = $v;
6294
                }
6295
                $this->debug('in serializeType: soapval provides attributes');
6296
            }
6297
        } else {
6298
            $forceType = false;
6299
        }
6300
6301
        $xml = '';
6302
        if (strpos($type, ':')) {
6303
            $uqType = substr($type, strrpos($type, ':') + 1);
6304
            $ns     = substr($type, 0, strrpos($type, ':'));
6305
            $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
6306
            if ($this->getNamespaceFromPrefix($ns)) {
6307
                $ns = $this->getNamespaceFromPrefix($ns);
6308
                $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
6309
            }
6310
6311
            if ($ns == $this->XMLSchemaVersion || $ns === 'http://schemas.xmlsoap.org/soap/encoding/') {
6312
                $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
6313
                if ($unqualified && $use === 'literal') {
6314
                    $elementNS = " xmlns=\"\"";
6315
                } else {
6316
                    $elementNS = '';
6317
                }
6318 View Code Duplication
                if (null === $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6319
                    if ($use === 'literal') {
6320
                        // TODO: depends on minOccurs
6321
                        $xml = "<$name$elementNS>";
6322
                    } else {
6323
                        // TODO: depends on nillable, which should be checked before calling this method
6324
                        $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6325
                    }
6326
                    $this->debug("in serializeType: returning: $xml");
6327
6328
                    return $xml;
6329
                }
6330
                if ($uqType === 'Array') {
6331
                    // JBoss/Axis does this sometimes
6332
                    return $this->serialize_val($value, $name, false, false, false, false, $use);
6333
                }
6334
                if ($uqType === 'boolean') {
6335
                    if ((is_string($value) && $value === 'false') || (!$value)) {
6336
                        $value = 'false';
6337
                    } else {
6338
                        $value = 'true';
6339
                    }
6340
                }
6341
                if ($uqType === 'string' && gettype($value) === 'string') {
6342
                    $value = $this->expandEntities($value);
6343
                }
6344
                if (($uqType === 'long' || $uqType === 'unsignedLong') && gettype($value) === 'double') {
6345
                    $value = sprintf('%.0lf', $value);
6346
                }
6347
                // it's a scalar
6348
                // TODO: what about null/nil values?
6349
                // check type isn't a custom type extending xmlschema namespace
6350
                if (!$this->getTypeDef($uqType, $ns)) {
6351
                    if ($use === 'literal') {
6352
                        if ($forceType) {
6353
                            $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6354
                        } else {
6355
                            $xml = "<$name$elementNS>$value</$name>";
6356
                        }
6357
                    } else {
6358
                        $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6359
                    }
6360
                    $this->debug("in serializeType: returning: $xml");
6361
6362
                    return $xml;
6363
                }
6364
                $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
6365
            } elseif ($ns === 'http://xml.apache.org/xml-soap') {
6366
                $this->debug('in serializeType: appears to be Apache SOAP type');
6367
                if ($uqType === 'Map') {
6368
                    $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6369
                    if (!$tt_prefix) {
6370
                        $this->debug('in serializeType: Add namespace for Apache SOAP type');
6371
                        $tt_prefix                    = 'ns' . mt_rand(1000, 9999);
6372
                        $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
6373
                        // force this to be added to usedNamespaces
6374
                        $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6375
                    }
6376
                    $contents = '';
6377
                    foreach ($value as $k => $v) {
6378
                        $this->debug("serializing map element: key $k, value $v");
6379
                        $contents .= '<item>';
6380
                        $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
6381
                        $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
6382
                        $contents .= '</item>';
6383
                    }
6384 View Code Duplication
                    if ($use === 'literal') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6385
                        if ($forceType) {
6386
                            $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6387
                        } else {
6388
                            $xml = "<$name>$contents</$name>";
6389
                        }
6390
                    } else {
6391
                        $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6392
                    }
6393
                    $this->debug("in serializeType: returning: $xml");
6394
6395
                    return $xml;
6396
                }
6397
                $this->debug('in serializeType: Apache SOAP type, but only support Map');
6398
            }
6399
        } else {
6400
            // TODO: should the type be compared to types in XSD, and the namespace
6401
            // set to XSD if the type matches?
6402
            $this->debug("in serializeType: No namespace for type $type");
6403
            $ns     = '';
6404
            $uqType = $type;
6405
        }
6406
        if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6407
            $this->setError("$type ($uqType) is not a supported type.");
6408
            $this->debug("in serializeType: $type ($uqType) is not a supported type.");
6409
6410
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Wsdl::serializeType of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
6411
        } else {
6412
            $this->debug('in serializeType: found typeDef');
6413
            $this->appendDebug('typeDef=' . $this->varDump($typeDef));
6414 View Code Duplication
            if (substr($uqType, -1) === '^') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6415
                $uqType = substr($uqType, 0, -1);
6416
            }
6417
        }
6418
        if (!isset($typeDef['phpType'])) {
6419
            $this->setError("$type ($uqType) has no phpType.");
6420
            $this->debug("in serializeType: $type ($uqType) has no phpType.");
6421
6422
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Wsdl::serializeType of type string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
6423
        }
6424
        $phpType = $typeDef['phpType'];
6425
        $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''));
6426
        // if php type == struct, map value to the <all> element names
6427
        if ($phpType === 'struct') {
6428
            if (isset($typeDef['typeClass']) && $typeDef['typeClass'] === 'element') {
6429
                $elementName = $uqType;
6430 View Code Duplication
                if (isset($typeDef['form']) && ($typeDef['form'] === 'qualified')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6431
                    $elementNS = " xmlns=\"$ns\"";
6432
                } else {
6433
                    $elementNS = " xmlns=\"\"";
6434
                }
6435
            } else {
6436
                $elementName = $name;
6437
                if ($unqualified) {
6438
                    $elementNS = " xmlns=\"\"";
6439
                } else {
6440
                    $elementNS = '';
6441
                }
6442
            }
6443 View Code Duplication
            if (null === $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6444
                if ($use === 'literal') {
6445
                    // TODO: depends on minOccurs and nillable
6446
                    $xml = "<$elementName$elementNS>";
6447
                } else {
6448
                    $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6449
                }
6450
                $this->debug("in serializeType: returning: $xml");
6451
6452
                return $xml;
6453
            }
6454
            if (is_object($value)) {
6455
                $value = get_object_vars($value);
6456
            }
6457
            if (is_array($value)) {
6458
                $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6459 View Code Duplication
                if ($use === 'literal') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6460
                    if ($forceType) {
6461
                        $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6462
                    } else {
6463
                        $xml = "<$elementName$elementNS$elementAttrs>";
6464
                    }
6465
                } else {
6466
                    $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
6467
                }
6468
6469
                if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] === 'true') {
6470
                    if (isset($value['!'])) {
6471
                        $xml .= $value['!'];
6472
                        $this->debug("in serializeType: serialized simpleContent for type $type");
6473
                    } else {
6474
                        $this->debug("in serializeType: no simpleContent to serialize for type $type");
6475
                    }
6476
                } else {
6477
                    // complexContent
6478
                    $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6479
                }
6480
                $xml .= "</$elementName>";
6481
            } else {
6482
                $this->debug('in serializeType: phpType is struct, but value is not an array');
6483
                $this->setError('phpType is struct, but value is not an array: see debug output for details');
6484
                $xml = '';
6485
            }
6486
        } elseif ($phpType === 'array') {
6487 View Code Duplication
            if (isset($typeDef['form']) && ($typeDef['form'] === 'qualified')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6488
                $elementNS = " xmlns=\"$ns\"";
6489
            } else {
6490
                if ($unqualified) {
6491
                    $elementNS = " xmlns=\"\"";
6492
                } else {
6493
                    $elementNS = '';
6494
                }
6495
            }
6496
            if (null === $value) {
6497 View Code Duplication
                if ($use === 'literal') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6498
                    // TODO: depends on minOccurs
6499
                    $xml = "<$name$elementNS>";
6500
                } else {
6501
                    $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\""
6502
                           . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6503
                           . ":Array\" "
6504
                           . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6505
                           . ':arrayType="'
6506
                           . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
0 ignored issues
show
Security Bug introduced by
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...
6507
                           . ':'
6508
                           . $this->getLocalPart($typeDef['arrayType'])
6509
                           . "[0]\">";
6510
                }
6511
                $this->debug("in serializeType: returning: $xml");
6512
6513
                return $xml;
6514
            }
6515
            if (isset($typeDef['multidimensional'])) {
6516
                $nv = array();
6517
                foreach ($value as $v) {
6518
                    $cols = ',' . count($v);
6519
                    $nv   = array_merge($nv, $v);
6520
                }
6521
                $value = $nv;
6522
            } else {
6523
                $cols = '';
6524
            }
6525
            if (is_array($value) && count($value) >= 1) {
6526
                $rows     = count($value);
6527
                $contents = '';
6528
                foreach ($value as $k => $v) {
6529
                    $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6530
                    //if (strpos($typeDef['arrayType'], ':') ) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
71% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
6531
                    if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6532
                        $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6533
                    } else {
6534
                        $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6535
                    }
6536
                }
6537
            } else {
6538
                $rows     = 0;
6539
                $contents = null;
6540
            }
6541
            // TODO: for now, an empty value will be serialized as a zero element
6542
            // array.  Revisit this when coding the handling of null/nil values.
6543
            if ($use === 'literal') {
6544
                $xml = "<$name$elementNS>" . $contents . "</$name>";
6545 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6546
                $xml = "<$name$elementNS xsi:type=\""
6547
                       . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6548
                       . ':Array" '
6549
                       . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6550
                       . ':arrayType="'
6551
                       . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
0 ignored issues
show
Security Bug introduced by
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...
6552
                       . ':'
6553
                       . $this->getLocalPart($typeDef['arrayType'])
6554
                       . "[$rows$cols]\">"
0 ignored issues
show
Bug introduced by
The variable $cols does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
6555
                       . $contents
6556
                       . "</$name>";
6557
            }
6558
        } elseif ($phpType === 'scalar') {
6559 View Code Duplication
            if (isset($typeDef['form']) && ($typeDef['form'] === 'qualified')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6560
                $elementNS = " xmlns=\"$ns\"";
6561
            } else {
6562
                if ($unqualified) {
6563
                    $elementNS = " xmlns=\"\"";
6564
                } else {
6565
                    $elementNS = '';
6566
                }
6567
            }
6568
            if ($use === 'literal') {
6569
                if ($forceType) {
6570
                    $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6571
                } else {
6572
                    $xml = "<$name$elementNS>$value</$name>";
6573
                }
6574
            } else {
6575
                $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6576
            }
6577
        }
6578
        $this->debug("in serializeType: returning: $xml");
6579
6580
        return $xml;
6581
    }
6582
6583
    /**
6584
     * serializes the attributes for a complexType
6585
     *
6586
     * @param  array  $typeDef our internal representation of an XML schema type (or element)
6587
     * @param  mixed  $value   a native PHP value (parameter value)
6588
     * @param  string $ns      the namespace of the type
6589
     * @param  string $uqType  the local part of the type
6590
     * @return string value serialized as an XML string
6591
     * @access private
6592
     */
6593
    public function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
6594
    {
6595
        $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
6596
        $xml = '';
6597 View Code Duplication
        if (isset($typeDef['extensionBase'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6598
            $nsx     = $this->getPrefix($typeDef['extensionBase']);
6599
            $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6600
            if ($this->getNamespaceFromPrefix($nsx)) {
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getPrefix($typeDef['extensionBase']) on line 6598 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...
6601
                $nsx = $this->getNamespaceFromPrefix($nsx);
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getNamespaceFromPrefix($nsx) on line 6601 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...
6602
            }
6603
            if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6604
                $this->debug("serialize attributes for extension base $nsx:$uqTypex");
6605
                $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
6606
            } else {
6607
                $this->debug("extension base $nsx:$uqTypex is not a supported type");
6608
            }
6609
        }
6610
        if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6611
            $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6612 View Code Duplication
            if (is_array($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6613
                $xvalue = $value;
6614
            } elseif (is_object($value)) {
6615
                $xvalue = get_object_vars($value);
6616
            } else {
6617
                $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6618
                $xvalue = array();
6619
            }
6620
            foreach ($typeDef['attrs'] as $aName => $attrs) {
6621
                if (isset($xvalue['!' . $aName])) {
6622
                    $xname = '!' . $aName;
6623
                    $this->debug("value provided for attribute $aName with key $xname");
6624
                } elseif (isset($xvalue[$aName])) {
6625
                    $xname = $aName;
6626
                    $this->debug("value provided for attribute $aName with key $xname");
6627 View Code Duplication
                } elseif (isset($attrs['default'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6628
                    $xname          = '!' . $aName;
6629
                    $xvalue[$xname] = $attrs['default'];
6630
                    $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6631
                } else {
6632
                    $xname = '';
6633
                    $this->debug("no value provided for attribute $aName");
6634
                }
6635
                if ($xname) {
6636
                    $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6637
                }
6638
            }
6639
        } else {
6640
            $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6641
        }
6642
6643
        return $xml;
6644
    }
6645
6646
    /**
6647
     * serializes the elements for a complexType
6648
     *
6649
     * @param  array       $typeDef       our internal representation of an XML schema type (or element)
6650
     * @param  mixed       $value         a native PHP value (parameter value)
6651
     * @param  string      $ns            the namespace of the type
6652
     * @param  string      $uqType        the local part of the type
6653
     * @param  string      $use           use for part (encoded|literal)
6654
     * @param  bool|string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6655
     * @return string      value serialized as an XML string
6656
     * @access private
6657
     */
6658
    public function serializeComplexTypeElements(
6659
        $typeDef,
6660
        $value,
6661
        $ns,
6662
        $uqType,
6663
        $use = 'encoded',
6664
        $encodingStyle = false)
6665
    {
6666
        $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
6667
        $xml = '';
6668 View Code Duplication
        if (isset($typeDef['extensionBase'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6669
            $nsx     = $this->getPrefix($typeDef['extensionBase']);
6670
            $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6671
            if ($this->getNamespaceFromPrefix($nsx)) {
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getPrefix($typeDef['extensionBase']) on line 6669 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...
6672
                $nsx = $this->getNamespaceFromPrefix($nsx);
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getNamespaceFromPrefix($nsx) on line 6672 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...
6673
            }
6674
            if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6675
                $this->debug("serialize elements for extension base $nsx:$uqTypex");
6676
                $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
6677
            } else {
6678
                $this->debug("extension base $nsx:$uqTypex is not a supported type");
6679
            }
6680
        }
6681
        if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6682
            $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6683 View Code Duplication
            if (is_array($value)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6684
                $xvalue = $value;
6685
            } elseif (is_object($value)) {
6686
                $xvalue = get_object_vars($value);
6687
            } else {
6688
                $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6689
                $xvalue = array();
6690
            }
6691
            // toggle whether all elements are present - ideally should validate against schema
6692
            if (count($typeDef['elements']) != count($xvalue)) {
6693
                $optionals = true;
6694
            }
6695
            foreach ($typeDef['elements'] as $eName => $attrs) {
6696
                if (!isset($xvalue[$eName])) {
6697 View Code Duplication
                    if (isset($attrs['default'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6698
                        $xvalue[$eName] = $attrs['default'];
6699
                        $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6700
                    }
6701
                }
6702
                // if user took advantage of a minOccurs=0, then only serialize named parameters
6703
                if (isset($optionals) && (!isset($xvalue[$eName]))
6704
                    && ((!isset($attrs['nillable']))
6705
                        || $attrs['nillable'] !== 'true')) {
6706
                    if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6707
                        $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6708
                    }
6709
                    // do nothing
6710
                    $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6711
                } else {
6712
                    // get value
6713
                    if (isset($xvalue[$eName])) {
6714
                        $v = $xvalue[$eName];
6715
                    } else {
6716
                        $v = null;
6717
                    }
6718
                    if (isset($attrs['form'])) {
6719
                        $unqualified = ($attrs['form'] === 'unqualified');
6720
                    } else {
6721
                        $unqualified = false;
6722
                    }
6723
                    if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] === 'unbounded' || $attrs['maxOccurs'] > 1)
6724
                        && isset($v)
6725
                        && is_array($v)
6726
                        && $this->isArraySimpleOrStruct($v) === 'arraySimple') {
6727
                        $vv = $v;
6728
                        foreach ($vv as $k => $v) {
6729
                            if (isset($attrs['type']) || isset($attrs['ref'])) {
6730
                                // serialize schema-defined type
6731
                                $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6732 View Code Duplication
                            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6733
                                // serialize generic type (can this ever really happen?)
6734
                                $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6735
                                $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6736
                            }
6737
                        }
6738
                    } else {
6739
                        if (null === $v && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') {
0 ignored issues
show
Unused Code introduced by
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...
6740
                            // do nothing
6741
                        } elseif (null === $v && isset($attrs['nillable']) && $attrs['nillable'] === 'true') {
6742
                            // TODO: serialize a nil correctly, but for now serialize schema-defined type
6743
                            $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6744
                        } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
6745
                            // serialize schema-defined type
6746
                            $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6747 View Code Duplication
                        } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6748
                            // serialize generic type (can this ever really happen?)
6749
                            $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6750
                            $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6751
                        }
6752
                    }
6753
                }
6754
            }
6755
        } else {
6756
            $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6757
        }
6758
6759
        return $xml;
6760
    }
6761
6762
    /**
6763
     * adds an XML Schema complex type to the WSDL types
6764
     *
6765
     * @param string $name
6766
     * @param string $typeClass       (complexType|simpleType|attribute)
6767
     * @param string $phpType         currently supported are array and struct (php assoc array)
6768
     * @param string $compositor      (all|sequence|choice)
6769
     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6770
     * @param array  $elements        e.g. array ( name => array(name=>'',type=>'') )
6771
     * @param array  $attrs           e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
6772
     * @param string $arrayType       as namespace:name (xsd:string)
6773
     * @see    nusoap_xmlschema
6774
     * @access public
6775
     */
6776
    public function addComplexType(
6777
        $name,
6778
        $typeClass = 'complexType',
6779
        $phpType = 'array',
6780
        $compositor = '',
6781
        $restrictionBase = '',
6782
        $elements = array(),
6783
        $attrs = array(),
6784
        $arrayType = '')
6785
    {
6786
        if (count($elements) > 0) {
6787
            $eElements = array();
6788 View Code Duplication
            foreach ($elements as $n => $e) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6789
                // expand each element
6790
                $ee = array();
6791
                foreach ($e as $k => $v) {
6792
                    $k      = strpos($k, ':') ? $this->expandQname($k) : $k;
6793
                    $v      = strpos($v, ':') ? $this->expandQname($v) : $v;
6794
                    $ee[$k] = $v;
6795
                }
6796
                $eElements[$n] = $ee;
6797
            }
6798
            $elements = $eElements;
6799
        }
6800
6801
        if (count($attrs) > 0) {
6802 View Code Duplication
            foreach ($attrs as $n => $a) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6803
                // expand each attribute
6804
                foreach ($a as $k => $v) {
6805
                    $k      = strpos($k, ':') ? $this->expandQname($k) : $k;
6806
                    $v      = strpos($v, ':') ? $this->expandQname($v) : $v;
6807
                    $aa[$k] = $v;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$aa was never initialized. Although not strictly required by PHP, it is generally a good practice to add $aa = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
6808
                }
6809
                $eAttrs[$n] = $aa;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$eAttrs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $eAttrs = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
Bug introduced by
The variable $aa does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
6810
            }
6811
            $attrs = $eAttrs;
0 ignored issues
show
Bug introduced by
The variable $eAttrs does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
6812
        }
6813
6814
        $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6815
        $arrayType       = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
6816
6817
        $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6818
        $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
6819
    }
6820
6821
    /**
6822
     * adds an XML Schema simple type to the WSDL types
6823
     *
6824
     * @param string $name
6825
     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6826
     * @param string $typeClass       (should always be simpleType)
6827
     * @param string $phpType         (should always be scalar)
6828
     * @param array  $enumeration     array of values
6829
     * @see    nusoap_xmlschema
6830
     * @access public
6831
     */
6832
    public function addSimpleType(
6833
        $name,
6834
        $restrictionBase = '',
6835
        $typeClass = 'simpleType',
6836
        $phpType = 'scalar',
6837
        $enumeration = array())
6838
    {
6839
        $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6840
6841
        $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6842
        $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6843
    }
6844
6845
    /**
6846
     * adds an element to the WSDL types
6847
     *
6848
     * @param array $attrs attributes that must include name and type
6849
     * @see    nusoap_xmlschema
6850
     * @access public
6851
     */
6852
    public function addElement($attrs)
6853
    {
6854
        $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6855
        $this->schemas[$typens][0]->addElement($attrs);
6856
    }
6857
6858
    /**
6859
     * register an operation with the server
6860
     *
6861
     * @param  string      $name          operation (method) name
6862
     * @param  array|bool  $in            assoc array of input values: key = param name, value = param type
6863
     * @param  array|bool  $out           assoc array of output values: key = param name, value = param type
6864
     * @param  bool|string $namespace     optional The namespace for the operation
6865
     * @param  bool|string $soapaction    optional The soapaction for the operation
6866
     * @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
6867
     * @param  string      $use           (encoded|literal) optional The use for the parameters (cannot mix right now)
6868
     * @param  string      $documentation optional The description to include in the WSDL
6869
     * @param  string      $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
6870
     * @return bool
6871
     * @access public
6872
     */
6873
    public function addOperation(
6874
        $name,
6875
        $in = false,
6876
        $out = false,
6877
        $namespace = false,
6878
        $soapaction = false,
6879
        $style = 'rpc',
6880
        $use = 'encoded',
6881
        $documentation = '',
6882
        $encodingStyle = '')
6883
    {
6884
        if ($use === 'encoded' && $encodingStyle == '') {
6885
            $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6886
        }
6887
6888
        if ($style === 'document') {
6889
            $elements = array();
6890 View Code Duplication
            foreach ($in as $n => $t) {
0 ignored issues
show
Bug introduced by
The expression $in of type 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...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6891
                $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
6892
            }
6893
            $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6894
            $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6895
            $in = array('parameters' => 'tns:' . $name . '^');
6896
6897
            $elements = array();
6898 View Code Duplication
            foreach ($out as $n => $t) {
0 ignored issues
show
Bug introduced by
The expression $out of type 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...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6899
                $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
6900
            }
6901
            $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6902
            $this->addElement(array(
6903
                                  'name' => $name . 'Response',
6904
                                  'type' => $name . 'ResponseType',
6905
                                  'form' => 'qualified'
6906
                              ));
6907
            $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6908
        }
6909
6910
        // get binding
6911
        $this->bindings[$this->serviceName . 'Binding']['operations'][$name] = array(
6912
            'name'          => $name,
6913
            'binding'       => $this->serviceName . 'Binding',
6914
            'endpoint'      => $this->endpoint,
6915
            'soapAction'    => $soapaction,
6916
            'style'         => $style,
6917
            'input'         => array(
6918
                'use'           => $use,
6919
                'namespace'     => $namespace,
6920
                'encodingStyle' => $encodingStyle,
6921
                'message'       => $name . 'Request',
6922
                'parts'         => $in
6923
            ),
6924
            'output'        => array(
6925
                'use'           => $use,
6926
                'namespace'     => $namespace,
6927
                'encodingStyle' => $encodingStyle,
6928
                'message'       => $name . 'Response',
6929
                'parts'         => $out
6930
            ),
6931
            'namespace'     => $namespace,
6932
            'transport'     => 'http://schemas.xmlsoap.org/soap/http',
6933
            'documentation' => $documentation
6934
        );
6935
        // add portTypes
6936
        // add messages
6937 View Code Duplication
        if ($in) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6938
            foreach ($in as $pName => $pType) {
0 ignored issues
show
Bug introduced by
The expression $in of type 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...
6939
                if (strpos($pType, ':')) {
6940
                    $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ':' . $this->getLocalPart($pType);
0 ignored issues
show
Security Bug introduced by
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...
6941
                }
6942
                $this->messages[$name . 'Request'][$pName] = $pType;
6943
            }
6944
        } else {
6945
            $this->messages[$name . 'Request'] = '0';
6946
        }
6947 View Code Duplication
        if ($out) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
6948
            foreach ($out as $pName => $pType) {
0 ignored issues
show
Bug introduced by
The expression $out of type 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...
6949
                if (strpos($pType, ':')) {
6950
                    $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ':' . $this->getLocalPart($pType);
0 ignored issues
show
Security Bug introduced by
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...
6951
                }
6952
                $this->messages[$name . 'Response'][$pName] = $pType;
6953
            }
6954
        } else {
6955
            $this->messages[$name . 'Response'] = '0';
6956
        }
6957
6958
        return true;
6959
    }
6960
}
6961
6962
?><?php
6963
6964
/**
6965
 *
6966
 * nusoap_parser class parses SOAP XML messages into native PHP values
6967
 *
6968
 * @author   Dietrich Ayala <[email protected]>
6969
 * @author   Scott Nichol <[email protected]>
6970
 * @access   public
6971
 */
6972
class Nusoap_parser extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
6973
{
6974
    public $xml                   = '';
6975
    public $xml_encoding          = '';
6976
    public $method                = '';
6977
    public $root_struct           = '';
6978
    public $root_struct_name      = '';
6979
    public $root_struct_namespace = '';
6980
    public $root_header           = '';
6981
    public $document              = '';            // incoming SOAP body (text)
6982
    // determines where in the message we are (envelope,header,body,method)
6983
    public $status            = '';
6984
    public $position          = 0;
6985
    public $depth             = 0;
6986
    public $default_namespace = '';
6987
    public $namespaces        = array();
6988
    public $message           = array();
6989
    public $parent            = '';
6990
    public $fault             = false;
6991
    public $fault_code        = '';
6992
    public $fault_str         = '';
6993
    public $fault_detail      = '';
6994
    public $depth_array       = array();
6995
    public $debug_flag        = true;
6996
    public $soapresponse      = null;    // parsed SOAP Body
6997
    public $soapheader        = null;        // parsed SOAP Header
6998
    public $responseHeaders   = '';    // incoming SOAP headers (text)
6999
    public $body_position     = 0;
7000
    // for multiref parsing:
7001
    // array of id => pos
7002
    public $ids = array();
7003
    // array of id => hrefs => pos
7004
    public $multirefs = array();
7005
    // toggle for auto-decoding element content
7006
    public $decode_utf8 = true;
7007
7008
    /**
7009
     * constructor that actually does the parsing
7010
     *
7011
     * @param string      $xml         SOAP message
7012
     * @param string      $encoding    character encoding scheme of message
7013
     * @param string      $method      method for which XML is parsed (unused?)
7014
     * @param bool|string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
7015
     * @access   public
7016
     * @return Nusoap_parser
0 ignored issues
show
Documentation introduced by
Should the return type not be Nusoap_parser|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
7017
     */
7018
    public function nusoap_parser($xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true)
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
7019
    {
7020
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of nusoap_parser()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
7021
        $this->xml          = $xml;
7022
        $this->xml_encoding = $encoding;
7023
        $this->method       = $method;
7024
        $this->decode_utf8  = $decode_utf8;
0 ignored issues
show
Documentation Bug introduced by
It seems like $decode_utf8 can also be of type string. However, the property $decode_utf8 is declared as type boolean. 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...
7025
7026
        // Check whether content has been read.
7027
        if (!empty($xml)) {
7028
            // Check XML encoding
7029
            $pos_xml = strpos($xml, '<?xml');
7030
            if ($pos_xml !== false) {
7031
                $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
7032
                if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
7033
                    $xml_encoding = $res[1];
7034
                    if (strtoupper($xml_encoding) != $encoding) {
7035
                        $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
7036
                        $this->debug($err);
7037
                        if ($encoding !== 'ISO-8859-1' || strtoupper($xml_encoding) !== 'UTF-8') {
7038
                            $this->setError($err);
7039
7040
                            return;
7041
                        }
7042
                        // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
7043
                    } else {
7044
                        $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
7045
                    }
7046
                } else {
7047
                    $this->debug('No encoding specified in XML declaration');
7048
                }
7049
            } else {
7050
                $this->debug('No XML declaration');
7051
            }
7052
            $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding);
7053
            // Create an XML parser - why not xml_parser_create_ns?
7054
            $this->parser = xml_parser_create($this->xml_encoding);
0 ignored issues
show
Bug introduced by
The property parser does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
7055
            // Set the options for parsing the XML data.
7056
            //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
7057
            xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
7058
            xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
7059
            // Set the object for the parser.
7060
            xml_set_object($this->parser, $this);
7061
            // Set the element handlers for the parser.
7062
            xml_set_element_handler($this->parser, 'start_element', 'end_element');
7063
            xml_set_character_data_handler($this->parser, 'character_data');
7064
7065
            // Parse the XML file.
7066
            if (!xml_parse($this->parser, $xml, true)) {
7067
                // Display an error message.
7068
                $err = sprintf('XML error parsing SOAP payload on line %d: %s', xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)));
7069
                $this->debug($err);
7070
                $this->debug("XML payload:\n" . $xml);
7071
                $this->setError($err);
7072
            } else {
7073
                $this->debug('in nusoap_parser ctor, message:');
7074
                $this->appendDebug($this->varDump($this->message));
7075
                $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name);
7076
                // get final value
7077
                $this->soapresponse = $this->message[$this->root_struct]['result'];
7078
                // get header value
7079
                if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) {
7080
                    $this->soapheader = $this->message[$this->root_header]['result'];
7081
                }
7082
                // resolve hrefs/ids
7083
                if (count($this->multirefs) > 0) {
7084
                    foreach ($this->multirefs as $id => $hrefs) {
7085
                        $this->debug('resolving multirefs for id: ' . $id);
7086
                        $idVal = $this->buildVal($this->ids[$id]);
7087
                        if (is_array($idVal) && isset($idVal['!id'])) {
7088
                            unset($idVal['!id']);
7089
                        }
7090
                        foreach ($hrefs as $refPos => $ref) {
7091
                            $this->debug('resolving href at pos ' . $refPos);
7092
                            $this->multirefs[$id][$refPos] = $idVal;
7093
                        }
7094
                    }
7095
                }
7096
            }
7097
            xml_parser_free($this->parser);
7098
        } else {
7099
            $this->debug('xml was empty, didn\'t parse!');
7100
            $this->setError('xml was empty, didn\'t parse!');
7101
        }
7102
    }
7103
7104
    /**
7105
     * start-element handler
7106
     *
7107
     * @param resource $parser XML parser object
7108
     * @param string   $name   element name
7109
     * @param array    $attrs  associative array of attributes
7110
     * @access   private
7111
     */
7112
    public function start_element($parser, $name, $attrs)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
7113
    {
7114
        // position in a total number of elements, starting from 0
7115
        // update class level pos
7116
        $pos = $this->position++;
7117
        // and set mine
7118
        $this->message[$pos] = array('pos' => $pos, 'children' => '', 'cdata' => '');
7119
        // depth = how many levels removed from root?
7120
        // set mine as current global depth and increment global depth value
7121
        $this->message[$pos]['depth'] = $this->depth++;
7122
7123
        // else add self as child to whoever the current parent is
7124
        if ($pos != 0) {
7125
            $this->message[$this->parent]['children'] .= '|' . $pos;
7126
        }
7127
        // set my parent
7128
        $this->message[$pos]['parent'] = $this->parent;
7129
        // set self as current parent
7130
        $this->parent = $pos;
0 ignored issues
show
Documentation Bug introduced by
The property $parent was declared of type string, but $pos is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
7131
        // set self as current value for this depth
7132
        $this->depth_array[$this->depth] = $pos;
7133
        // get element prefix
7134 View Code Duplication
        if (strpos($name, ':')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7135
            // get ns prefix
7136
            $prefix = substr($name, 0, strpos($name, ':'));
7137
            // get unqualified name
7138
            $name = substr(strstr($name, ':'), 1);
7139
        }
7140
        // set status
7141
        if ($name === 'Envelope' && $this->status == '') {
7142
            $this->status = 'envelope';
7143
        } elseif ($name === 'Header' && $this->status === 'envelope') {
7144
            $this->root_header = $pos;
0 ignored issues
show
Documentation Bug introduced by
The property $root_header was declared of type string, but $pos is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
7145
            $this->status      = 'header';
7146
        } elseif ($name === 'Body' && $this->status === 'envelope') {
7147
            $this->status        = 'body';
7148
            $this->body_position = $pos;
7149
            // set method
7150
        } elseif ($this->status === 'body' && $pos == ($this->body_position + 1)) {
7151
            $this->status                = 'method';
7152
            $this->root_struct_name      = $name;
7153
            $this->root_struct           = $pos;
0 ignored issues
show
Documentation Bug introduced by
The property $root_struct was declared of type string, but $pos is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
7154
            $this->message[$pos]['type'] = 'struct';
7155
            $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
7156
        }
7157
        // set my status
7158
        $this->message[$pos]['status'] = $this->status;
7159
        // set name
7160
        $this->message[$pos]['name'] = htmlspecialchars($name);
7161
        // set attrs
7162
        $this->message[$pos]['attrs'] = $attrs;
7163
7164
        // loop through atts, logging ns and type declarations
7165
        $attstr = '';
7166
        foreach ($attrs as $key => $value) {
7167
            $key_prefix    = $this->getPrefix($key);
7168
            $key_localpart = $this->getLocalPart($key);
7169
            // if ns declarations, add to class level array of valid namespaces
7170
            if ($key_prefix === 'xmlns') {
7171
                if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
7172
                    $this->XMLSchemaVersion  = $value;
7173
                    $this->namespaces['xsd'] = $this->XMLSchemaVersion;
7174
                    $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
7175
                }
7176
                $this->namespaces[$key_localpart] = $value;
7177
                // set method namespace
7178
                if ($name == $this->root_struct_name) {
7179
                    $this->methodNamespace = $value;
0 ignored issues
show
Bug introduced by
The property methodNamespace does not seem to exist. Did you mean method?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
7180
                }
7181
                // if it's a type declaration, set type
7182
            } elseif ($key_localpart === 'type') {
7183
                if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] === 'array') {
0 ignored issues
show
Unused Code introduced by
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...
7184
                    // do nothing: already processed arrayType
7185
                } else {
7186
                    $value_prefix                      = $this->getPrefix($value);
7187
                    $value_localpart                   = $this->getLocalPart($value);
7188
                    $this->message[$pos]['type']       = $value_localpart;
7189
                    $this->message[$pos]['typePrefix'] = $value_prefix;
7190
                    if (isset($this->namespaces[$value_prefix])) {
7191
                        $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
7192
                    } elseif (isset($attrs['xmlns:' . $value_prefix])) {
7193
                        $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix];
7194
                    }
7195
                    // should do something here with the namespace of specified type?
7196
                }
7197
            } elseif ($key_localpart === 'arrayType') {
7198
                $this->message[$pos]['type'] = 'array';
7199
                /* do arrayType ereg here
7200
                [1]    arrayTypeValue    ::=    atype asize
7201
                [2]    atype    ::=    QName rank*
7202
                [3]    rank    ::=    '[' (',')* ']'
7203
                [4]    asize    ::=    '[' length~ ']'
7204
                [5]    length    ::=    nextDimension* Digit+
7205
                [6]    nextDimension    ::=    Digit+ ','
7206
                */
7207
                $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
7208
                if (preg_match($expr, $value, $regs)) {
7209
                    $this->message[$pos]['typePrefix']      = $regs[1];
7210
                    $this->message[$pos]['arrayTypePrefix'] = $regs[1];
7211
                    if (isset($this->namespaces[$regs[1]])) {
7212
                        $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
7213
                    } elseif (isset($attrs['xmlns:' . $regs[1]])) {
7214
                        $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]];
7215
                    }
7216
                    $this->message[$pos]['arrayType'] = $regs[2];
7217
                    $this->message[$pos]['arraySize'] = $regs[3];
7218
                    $this->message[$pos]['arrayCols'] = $regs[4];
7219
                }
7220
                // specifies nil value (or not)
7221
            } elseif ($key_localpart === 'nil') {
7222
                $this->message[$pos]['nil'] = ($value === 'true' || $value == '1');
7223
                // some other attribute
7224
            } elseif ($key !== 'href' && $key !== 'xmlns' && $key_localpart !== 'encodingStyle'
7225
                      && $key_localpart !== 'root') {
7226
                $this->message[$pos]['xattrs']['!' . $key] = $value;
7227
            }
7228
7229
            if ($key === 'xmlns') {
7230
                $this->default_namespace = $value;
7231
            }
7232
            // log id
7233
            if ($key === 'id') {
7234
                $this->ids[$value] = $pos;
7235
            }
7236
            // root
7237
            if ($key_localpart === 'root' && $value == 1) {
7238
                $this->status           = 'method';
7239
                $this->root_struct_name = $name;
7240
                $this->root_struct      = $pos;
7241
                $this->debug("found root struct $this->root_struct_name, pos $pos");
7242
            }
7243
            // for doclit
7244
            $attstr .= " $key=\"$value\"";
7245
        }
7246
        // get namespace - must be done after namespace atts are processed
7247
        if (isset($prefix)) {
7248
            $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
7249
            $this->default_namespace          = $this->namespaces[$prefix];
7250
        } else {
7251
            $this->message[$pos]['namespace'] = $this->default_namespace;
7252
        }
7253 View Code Duplication
        if ($this->status === 'header') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7254
            if ($this->root_header != $pos) {
7255
                $this->responseHeaders .= '<' . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
7256
            }
7257
        } elseif ($this->root_struct_name != '') {
7258
            $this->document .= '<' . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
7259
        }
7260
    }
7261
7262
    /**
7263
     * end-element handler
7264
     *
7265
     * @param resource $parser XML parser object
7266
     * @param string   $name   element name
7267
     * @access   private
7268
     */
7269
    public function end_element($parser, $name)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
7270
    {
7271
        // position of current element is equal to the last value left in depth_array for my depth
7272
        $pos = $this->depth_array[$this->depth--];
7273
7274
        // get element prefix
7275 View Code Duplication
        if (strpos($name, ':')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7276
            // get ns prefix
7277
            $prefix = substr($name, 0, strpos($name, ':'));
7278
            // get unqualified name
7279
            $name = substr(strstr($name, ':'), 1);
7280
        }
7281
7282
        // build to native type
7283
        if (isset($this->body_position) && $pos > $this->body_position) {
7284
            // deal w/ multirefs
7285
            if (isset($this->message[$pos]['attrs']['href'])) {
7286
                // get id
7287
                $id = substr($this->message[$pos]['attrs']['href'], 1);
7288
                // add placeholder to href array
7289
                $this->multirefs[$id][$pos] = 'placeholder';
7290
                // add set a reference to it as the result value
7291
                $this->message[$pos]['result'] = $this->multirefs[$id][$pos];
7292
                // build complexType values
7293
            } elseif ($this->message[$pos]['children'] != '') {
7294
                // if result has already been generated (struct/array)
7295
                if (!isset($this->message[$pos]['result'])) {
7296
                    $this->message[$pos]['result'] = $this->buildVal($pos);
7297
                }
7298
                // build complexType values of attributes and possibly simpleContent
7299
            } elseif (isset($this->message[$pos]['xattrs'])) {
7300
                if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7301
                    $this->message[$pos]['xattrs']['!'] = null;
7302
                } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7303
                    if (isset($this->message[$pos]['type'])) {
7304
                        $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7305 View Code Duplication
                    } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7306
                        $parent = $this->message[$pos]['parent'];
7307
                        if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7308
                            && isset($this->message[$parent]['arrayType'])) {
7309
                            $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7310
                        } else {
7311
                            $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
7312
                        }
7313
                    }
7314
                }
7315
                $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
7316
                // set value of simpleType (or nil complexType)
7317
            } else {
7318
                //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
0 ignored issues
show
Unused Code Comprehensibility introduced by
80% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
7319
                if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7320
                    $this->message[$pos]['xattrs']['!'] = null;
7321
                } elseif (isset($this->message[$pos]['type'])) {
7322
                    $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7323 View Code Duplication
                } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7324
                    $parent = $this->message[$pos]['parent'];
7325
                    if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7326
                        && isset($this->message[$parent]['arrayType'])) {
7327
                        $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7328
                    } else {
7329
                        $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
7330
                    }
7331
                }
7332
7333
                /* add value to parent's result, if parent is struct/array
7334
                $parent = $this->message[$pos]['parent'];
7335
                if ($this->message[$parent]['type'] != 'map') {
7336
                    if (strtolower($this->message[$parent]['type']) == 'array') {
7337
                        $this->message[$parent]['result'][] = $this->message[$pos]['result'];
7338
                    } else {
7339
                        $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
7340
                    }
7341
                }
7342
                */
7343
            }
7344
        }
7345
7346
        // for doclit
7347 View Code Duplication
        if ($this->status === 'header') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7348
            if ($this->root_header != $pos) {
7349
                $this->responseHeaders .= '</' . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7350
            }
7351
        } elseif ($pos >= $this->root_struct) {
7352
            $this->document .= '</' . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7353
        }
7354
        // switch status
7355
        if ($pos == $this->root_struct) {
7356
            $this->status                = 'body';
7357
            $this->root_struct_namespace = $this->message[$pos]['namespace'];
7358
        } elseif ($pos == $this->root_header) {
7359
            $this->status = 'envelope';
7360
        } elseif ($name === 'Body' && $this->status === 'body') {
7361
            $this->status = 'envelope';
7362
        } elseif ($name === 'Header' && $this->status === 'header') { // will never happen
7363
            $this->status = 'envelope';
7364
        } elseif ($name === 'Envelope' && $this->status === 'envelope') {
7365
            $this->status = '';
7366
        }
7367
        // set parent back to my parent
7368
        $this->parent = $this->message[$pos]['parent'];
7369
    }
7370
7371
    /**
7372
     * element content handler
7373
     *
7374
     * @param resource $parser XML parser object
7375
     * @param string   $data   element content
7376
     * @access   private
7377
     */
7378
    public function character_data($parser, $data)
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
7379
    {
7380
        $pos = $this->depth_array[$this->depth];
7381
        if ($this->xml_encoding === 'UTF-8') {
7382
            // TODO: add an option to disable this for folks who want
7383
            // raw UTF-8 that, e.g., might not map to iso-8859-1
7384
            // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
7385
            if ($this->decode_utf8) {
7386
                $data = utf8_decode($data);
7387
            }
7388
        }
7389
        $this->message[$pos]['cdata'] .= $data;
7390
        // for doclit
7391
        if ($this->status === 'header') {
7392
            $this->responseHeaders .= $data;
7393
        } else {
7394
            $this->document .= $data;
7395
        }
7396
    }
7397
7398
    /**
7399
     * get the parsed message (SOAP Body)
7400
     *
7401
     * @return mixed
7402
     * @access       public
7403
     * @deprecated   use get_soapbody instead
7404
     */
7405
    public function get_response()
7406
    {
7407
        return $this->soapresponse;
7408
    }
7409
7410
    /**
7411
     * get the parsed SOAP Body (NULL if there was none)
7412
     *
7413
     * @return mixed
7414
     * @access   public
7415
     */
7416
    public function get_soapbody()
7417
    {
7418
        return $this->soapresponse;
7419
    }
7420
7421
    /**
7422
     * get the parsed SOAP Header (NULL if there was none)
7423
     *
7424
     * @return mixed
7425
     * @access   public
7426
     */
7427
    public function get_soapheader()
7428
    {
7429
        return $this->soapheader;
7430
    }
7431
7432
    /**
7433
     * get the unparsed SOAP Header
7434
     *
7435
     * @return string XML or empty if no Header
7436
     * @access   public
7437
     */
7438
    public function getHeaders()
7439
    {
7440
        return $this->responseHeaders;
7441
    }
7442
7443
    /**
7444
     * decodes simple types into PHP variables
7445
     *
7446
     * @param  string $value  value to decode
7447
     * @param  string $type   XML type to decode
7448
     * @param  string $typens XML type namespace to decode
7449
     * @return mixed  PHP value
7450
     * @access   private
7451
     */
7452
    public function decodeSimple($value, $type, $typens)
0 ignored issues
show
Unused Code introduced by
The parameter $typens is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
7453
    {
7454
        // TODO: use the namespace!
7455
        if ((!isset($type)) || $type === 'string' || $type === 'long' || $type === 'unsignedLong') {
7456
            return (string)$value;
7457
        }
7458
        if ($type === 'int' || $type === 'integer' || $type === 'short' || $type === 'byte') {
7459
            return (int)$value;
7460
        }
7461
        if ($type === 'float' || $type === 'double' || $type === 'decimal') {
7462
            return (double)$value;
7463
        }
7464
        if ($type === 'boolean') {
7465
            if (strtolower($value) === 'false' || strtolower($value) === 'f') {
7466
                return false;
7467
            }
7468
7469
            return (boolean)$value;
7470
        }
7471
        if ($type === 'base64' || $type === 'base64Binary') {
7472
            $this->debug('Decode base64 value');
7473
7474
            return base64_decode($value);
7475
        }
7476
        // obscure numeric types
7477
        if ($type === 'nonPositiveInteger'
7478
            || $type === 'negativeInteger'
7479
            || $type === 'nonNegativeInteger'
7480
            || $type === 'positiveInteger'
7481
            || $type === 'unsignedInt'
7482
            || $type === 'unsignedShort'
7483
            || $type === 'unsignedByte') {
7484
            return (int)$value;
7485
        }
7486
        // bogus: parser treats array with no elements as a simple type
7487
        if ($type === 'array') {
7488
            return array();
7489
        }
7490
7491
        // everything else
7492
        return (string)$value;
7493
    }
7494
7495
    /**
7496
     * builds response structures for compound values (arrays/structs)
7497
     * and scalars
7498
     *
7499
     * @param  integer $pos position in node tree
7500
     * @return mixed   PHP value
7501
     * @access   private
7502
     */
7503
    public function buildVal($pos)
7504
    {
7505 View Code Duplication
        if (!isset($this->message[$pos]['type'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7506
            $this->message[$pos]['type'] = '';
7507
        }
7508
        $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']);
7509
        // if there are children...
7510
        if ($this->message[$pos]['children'] != '') {
7511
            $this->debug('in buildVal, there are children');
7512
            $children = explode('|', $this->message[$pos]['children']);
7513
            array_shift($children); // knock off empty
7514
            // md array
7515
            if (isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != '') {
7516
                $r = 0; // rowcount
7517
                $c = 0; // colcount
7518
                foreach ($children as $child_pos) {
7519
                    $this->debug("in buildVal, got an MD array element: $r, $c");
7520
                    $params[$r][] = $this->message[$child_pos]['result'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
7521
                    ++$c;
7522
                    if ($c == $this->message[$pos]['arrayCols']) {
7523
                        $c = 0;
7524
                        ++$r;
7525
                    }
7526
                }
7527
                // array
7528
            } elseif ($this->message[$pos]['type'] === 'array' || $this->message[$pos]['type'] === 'Array') {
7529
                $this->debug('in buildVal, adding array ' . $this->message[$pos]['name']);
7530
                foreach ($children as $child_pos) {
7531
                    $params[] = $this->message[$child_pos]['result'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
7532
                }
7533
                // apache Map type: java hashtable
7534
            } elseif ($this->message[$pos]['type'] === 'Map'
7535
                      && $this->message[$pos]['type_namespace'] === 'http://xml.apache.org/xml-soap') {
7536
                $this->debug('in buildVal, Java Map ' . $this->message[$pos]['name']);
7537
                foreach ($children as $child_pos) {
7538
                    $kv                                       = explode('|', $this->message[$child_pos]['children']);
7539
                    $params[$this->message[$kv[1]]['result']] = $this->message[$kv[2]]['result'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
7540
                }
7541
                // generic compound type
7542
                //} elseif ($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
7543
            } else {
7544
                // Apache Vector type: treat as an array
7545
                $this->debug('in buildVal, adding Java Vector or generic compound type ' . $this->message[$pos]['name']);
7546
                if ($this->message[$pos]['type'] === 'Vector'
7547
                    && $this->message[$pos]['type_namespace'] === 'http://xml.apache.org/xml-soap') {
7548
                    $notstruct = 1;
7549
                } else {
7550
                    $notstruct = 0;
7551
                }
7552
                //
7553
                foreach ($children as $child_pos) {
7554
                    if ($notstruct) {
7555
                        $params[] = $this->message[$child_pos]['result'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
7556
                    } else {
7557
                        if (isset($params[$this->message[$child_pos]['name']])) {
7558
                            // de-serialize repeated element name into an array
7559
                            if ((!is_array($params[$this->message[$child_pos]['name']]))
7560
                                || (!isset($params[$this->message[$child_pos]['name']][0]))) {
7561
                                $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
7562
                            }
7563
                            $params[$this->message[$child_pos]['name']][] = $this->message[$child_pos]['result'];
7564
                        } else {
7565
                            $params[$this->message[$child_pos]['name']] = $this->message[$child_pos]['result'];
0 ignored issues
show
Bug introduced by
The variable $params does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
7566
                        }
7567
                    }
7568
                }
7569
            }
7570
            if (isset($this->message[$pos]['xattrs'])) {
7571
                $this->debug('in buildVal, handling attributes');
7572
                foreach ($this->message[$pos]['xattrs'] as $n => $v) {
7573
                    $params[$n] = $v;
7574
                }
7575
            }
7576
            // handle simpleContent
7577
            if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7578
                $this->debug('in buildVal, handling simpleContent');
7579
                if (isset($this->message[$pos]['type'])) {
7580
                    $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7581
                } else {
7582
                    $parent = $this->message[$pos]['parent'];
7583
                    if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7584
                        && isset($this->message[$parent]['arrayType'])) {
7585
                        $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7586
                    } else {
7587
                        $params['!'] = $this->message[$pos]['cdata'];
7588
                    }
7589
                }
7590
            }
7591
            $ret = is_array($params) ? $params : array();
7592
            $this->debug('in buildVal, return:');
7593
            $this->appendDebug($this->varDump($ret));
7594
7595
            return $ret;
7596
        } else {
7597
            $this->debug('in buildVal, no children, building scalar');
7598
            $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7599
            if (isset($this->message[$pos]['type'])) {
7600
                $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7601
                $this->debug("in buildVal, return: $ret");
7602
7603
                return $ret;
7604
            }
7605
            $parent = $this->message[$pos]['parent'];
7606
            if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7607
                && isset($this->message[$parent]['arrayType'])) {
7608
                $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7609
                $this->debug("in buildVal, return: $ret");
7610
7611
                return $ret;
7612
            }
7613
            $ret = $this->message[$pos]['cdata'];
7614
            $this->debug("in buildVal, return: $ret");
7615
7616
            return $ret;
7617
        }
7618
    }
7619
}
7620
7621
/**
7622
 * Backward compatibility
7623
 */
7624
class Soap_parser extends Nusoap_parser
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
7625
{
7626
}
7627
7628
?><?php
7629
7630
/**
7631
 *
7632
 * [nu]soapclient higher level class for easy usage.
7633
 *
7634
 * usage:
7635
 *
7636
 * // instantiate client with server info
7637
 * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
7638
 *
7639
 * // call method, get results
7640
 * echo $soapclient->call( string methodname [ ,array parameters] );
7641
 *
7642
 * // bye bye client
7643
 * unset($soapclient);
7644
 *
7645
 * @author   Dietrich Ayala <[email protected]>
7646
 * @author   Scott Nichol <[email protected]>
7647
 * @access   public
7648
 */
7649
class Nusoap_client extends Nusoap_base
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
7650
{
7651
    public $username             = '';                // Username for HTTP authentication
7652
    public $password             = '';                // Password for HTTP authentication
7653
    public $authtype             = '';                // Type of HTTP authentication
7654
    public $certRequest          = array();        // Certificate for HTTP SSL authentication
7655
    public $requestHeaders       = false;    // SOAP headers in request (text)
7656
    public $responseHeaders      = '';        // SOAP headers from response (incomplete namespace resolution) (text)
7657
    public $responseHeader       = null;        // SOAP Header from response (parsed)
7658
    public $document             = '';                // SOAP body response portion (incomplete namespace resolution) (text)
7659
    public $endpoint;
7660
    public $forceEndpoint        = '';        // overrides WSDL endpoint
7661
    public $proxyhost            = '';
7662
    public $proxyport            = '';
7663
    public $proxyusername        = '';
7664
    public $proxypassword        = '';
7665
    public $portName             = '';                // port name to use in WSDL
7666
    public $xml_encoding         = '';            // character set encoding of incoming (response) messages
7667
    public $http_encoding        = false;
7668
    public $timeout              = 0;                // HTTP connection timeout
7669
    public $response_timeout     = 30;        // HTTP response timeout
7670
    public $endpointType         = '';            // soap|wsdl, empty for WSDL initialization error
7671
    public $persistentConnection = false;
7672
    public $defaultRpcParams     = false;    // This is no longer used
7673
    public $request              = '';                // HTTP request
7674
    public $response             = '';                // HTTP response
7675
    public $responseData         = '';            // SOAP payload of response
7676
    public $cookies              = array();            // Cookies from response or for request
7677
    public $decode_utf8          = true;        // toggles whether the parser decodes element content w/ utf8_decode()
7678
    public $operations           = array();        // WSDL operations, empty for WSDL initialization error
7679
    public $curl_options         = array();    // User-specified cURL options
7680
    public $bindingType          = '';            // WSDL operation binding type
7681
    public $use_curl             = false;            // whether to always try to use cURL
7682
7683
    /*
7684
     * fault related variables
7685
     */
7686
    /**
7687
     * @var fault
7688
     * @access   public
7689
     */
7690
    public $fault;
7691
    /**
7692
     * @var faultcode
7693
     * @access   public
7694
     */
7695
    public $faultcode;
7696
    /**
7697
     * @var faultstring
7698
     * @access   public
7699
     */
7700
    public $faultstring;
7701
    /**
7702
     * @var faultdetail
7703
     * @access   public
7704
     */
7705
    public $faultdetail;
7706
7707
    /**
7708
     * constructor
7709
     *
7710
     * @param mixed       $endpoint         SOAP server or WSDL URL (string) , or wsdl instance (object)
7711
     * @param mixed       $wsdl             optional, set to 'wsdl' or true if using WSDL
7712
     * @param bool|string $proxyhost        optional
7713
     * @param bool|string $proxyport        optional
7714
     * @param bool|string $proxyusername    optional
7715
     * @param bool|string $proxypassword    optional
7716
     * @param integer     $timeout          set the connection timeout
7717
     * @param integer     $response_timeout set the response timeout
7718
     * @param string      $portName         optional portName in WSDL document
7719
     * @access   public
7720
     * @return Nusoap_client
0 ignored issues
show
Documentation introduced by
Should the return type not be Nusoap_client|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
7721
     */
7722
    public function nusoap_client(
0 ignored issues
show
Coding Style Best Practice introduced by
Please use __construct() instead of a PHP4-style constructor that is named after the class.
Loading history...
7723
        $endpoint,
7724
        $wsdl = false,
7725
        $proxyhost = false,
7726
        $proxyport = false,
7727
        $proxyusername = false,
7728
        $proxypassword = false,
7729
        $timeout = 0,
7730
        $response_timeout = 30,
7731
        $portName = '')
7732
    {
7733
        parent::nusoap_base();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (nusoap_base() instead of nusoap_client()). Are you sure this is correct? If so, you might want to change this to $this->nusoap_base().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
7734
        $this->endpoint         = $endpoint;
7735
        $this->proxyhost        = $proxyhost;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyhost can also be of type boolean. 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...
7736
        $this->proxyport        = $proxyport;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyport can also be of type boolean. 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...
7737
        $this->proxyusername    = $proxyusername;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxyusername can also be of type boolean. 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...
7738
        $this->proxypassword    = $proxypassword;
0 ignored issues
show
Documentation Bug introduced by
It seems like $proxypassword can also be of type boolean. 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...
7739
        $this->timeout          = $timeout;
7740
        $this->response_timeout = $response_timeout;
7741
        $this->portName         = $portName;
7742
7743
        $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7744
        $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7745
7746
        // make values
7747
        if ($wsdl) {
7748
            if (is_object($endpoint) && (get_class($endpoint) === 'wsdl')) {
7749
                $this->wsdl     = $endpoint;
0 ignored issues
show
Bug introduced by
The property wsdl does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
7750
                $this->endpoint = $this->wsdl->wsdl;
7751
                $this->wsdlFile = $this->endpoint;
0 ignored issues
show
Bug introduced by
The property wsdlFile does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
7752
                $this->debug('existing wsdl instance created from ' . $this->endpoint);
7753
                $this->checkWSDL();
7754
            } else {
7755
                $this->wsdlFile = $this->endpoint;
7756
                $this->wsdl     = null;
7757
                $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7758
            }
7759
            $this->endpointType = 'wsdl';
7760
        } else {
7761
            $this->debug("instantiate SOAP with endpoint at $endpoint");
7762
            $this->endpointType = 'soap';
7763
        }
7764
    }
7765
7766
    /**
7767
     * calls method, returns PHP native type
7768
     *
7769
     * @param  string  $operation  SOAP server URL or path
7770
     * @param  mixed   $params     An array, associative or simple, of the parameters
7771
     *                             for the method call, or a string that is the XML
7772
     *                             for the call.  For rpc style, this call will
7773
     *                             wrap the XML in a tag named after the method, as
7774
     *                             well as the SOAP Envelope and Body.  For document
7775
     *                             style, this will only wrap with the Envelope and Body.
7776
     *                             IMPORTANT: when using an array with document style,
7777
     *                             in which case there
7778
     *                             is really one parameter, the root of the fragment
7779
     *                             used in the call, which encloses what programmers
7780
     *                             normally think of parameters.  A parameter array
7781
     *                             *must* include the wrapper.
7782
     * @param  string  $namespace  optional method namespace (WSDL can override)
7783
     * @param  string  $soapAction optional SOAPAction value (WSDL can override)
7784
     * @param  mixed   $headers    optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
7785
     * @param  boolean $rpcParams  optional (no longer used)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $rpcParams not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
7786
     * @param  string  $style      optional (rpc|document) the style to use when serializing parameters (WSDL can override)
7787
     * @param  string  $use        optional (encoded|literal) the use when serializing parameters (WSDL can override)
7788
     * @return mixed   response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
7789
     * @access   public
7790
     */
7791
    public function call(
7792
        $operation,
7793
        $params = array(),
7794
        $namespace = 'http://tempuri.org',
7795
        $soapAction = '',
7796
        $headers = false,
7797
        $rpcParams = null,
7798
        $style = 'rpc',
7799
        $use = 'encoded')
7800
    {
7801
        $this->operation = $operation;
0 ignored issues
show
Bug introduced by
The property operation does not seem to exist. Did you mean operations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
7802
        $this->fault     = false;
0 ignored issues
show
Documentation Bug introduced by
It seems like false of type false is incompatible with the declared type object<fault> of property $fault.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
7803
        $this->setError('');
7804
        $this->request      = '';
7805
        $this->response     = '';
7806
        $this->responseData = '';
7807
        $this->faultstring  = '';
0 ignored issues
show
Documentation Bug introduced by
It seems like '' of type string is incompatible with the declared type object<faultstring> of property $faultstring.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
7808
        $this->faultcode    = '';
0 ignored issues
show
Documentation Bug introduced by
It seems like '' of type string is incompatible with the declared type object<faultcode> of property $faultcode.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
7809
        $this->opData       = array();
0 ignored issues
show
Bug introduced by
The property opData does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
7810
7811
        $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7812
        $this->appendDebug('params=' . $this->varDump($params));
7813
        $this->appendDebug('headers=' . $this->varDump($headers));
7814
        if ($headers) {
7815
            $this->requestHeaders = $headers;
7816
        }
7817 View Code Duplication
        if ($this->endpointType === 'wsdl' && null === $this->wsdl) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7818
            $this->loadWSDL();
7819
            if ($this->getError()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getError() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
7820
                return false;
7821
            }
7822
        }
7823
        // serialize parameters
7824
        if ($this->endpointType === 'wsdl' && $opData = $this->getOperationData($operation)) {
7825
            // use WSDL for operation
7826
            $this->opData = $opData;
7827
            $this->debug('found operation');
7828
            $this->appendDebug('opData=' . $this->varDump($opData));
7829
            if (isset($opData['soapAction'])) {
7830
                $soapAction = $opData['soapAction'];
7831
            }
7832
            if (!$this->forceEndpoint) {
7833
                $this->endpoint = $opData['endpoint'];
7834
            } else {
7835
                $this->endpoint = $this->forceEndpoint;
7836
            }
7837
            $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7838
            $style     = $opData['style'];
7839
            $use       = $opData['input']['use'];
7840
            // add ns to ns array
7841
            if ($namespace != '' && !isset($this->wsdl->namespaces[$namespace])) {
7842
                $nsPrefix                          = 'ns' . mt_rand(1000, 9999);
7843
                $this->wsdl->namespaces[$nsPrefix] = $namespace;
7844
            }
7845
            $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7846
            // serialize payload
7847
            if (is_string($params)) {
7848
                $this->debug("serializing param string for WSDL operation $operation");
7849
                $payload = $params;
7850
            } elseif (is_array($params)) {
7851
                $this->debug("serializing param array for WSDL operation $operation");
7852
                $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType);
7853
            } else {
7854
                $this->debug('params must be array or string');
7855
                $this->setError('params must be array or string');
7856
7857
                return false;
7858
            }
7859
            $usedNamespaces = $this->wsdl->usedNamespaces;
7860
            if (isset($opData['input']['encodingStyle'])) {
7861
                $encodingStyle = $opData['input']['encodingStyle'];
7862
            } else {
7863
                $encodingStyle = '';
7864
            }
7865
            $this->appendDebug($this->wsdl->getDebug());
7866
            $this->wsdl->clearDebug();
7867
            if ($errstr = $this->wsdl->getError()) {
7868
                $this->debug('got wsdl error: ' . $errstr);
7869
                $this->setError('wsdl error: ' . $errstr);
7870
7871
                return false;
7872
            }
7873
        } elseif ($this->endpointType === 'wsdl') {
7874
            // operation not in WSDL
7875
            $this->appendDebug($this->wsdl->getDebug());
7876
            $this->wsdl->clearDebug();
7877
            $this->setError('operation ' . $operation . ' not present in WSDL.');
7878
            $this->debug("operation '$operation' not present in WSDL.");
7879
7880
            return false;
7881
        } else {
7882
            // no WSDL
7883
            //$this->namespaces['ns1'] = $namespace;
0 ignored issues
show
Unused Code Comprehensibility introduced by
64% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
7884
            $nsPrefix = 'ns' . mt_rand(1000, 9999);
7885
            // serialize
7886
            $payload = '';
7887
            if (is_string($params)) {
7888
                $this->debug("serializing param string for operation $operation");
7889
                $payload = $params;
7890
            } elseif (is_array($params)) {
7891
                $this->debug("serializing param array for operation $operation");
7892
                foreach ($params as $k => $v) {
7893
                    $payload .= $this->serialize_val($v, $k, false, false, false, false, $use);
7894
                }
7895
            } else {
7896
                $this->debug('params must be array or string');
7897
                $this->setError('params must be array or string');
7898
7899
                return false;
7900
            }
7901
            $usedNamespaces = array();
7902
            if ($use === 'encoded') {
7903
                $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7904
            } else {
7905
                $encodingStyle = '';
7906
            }
7907
        }
7908
        // wrap RPC calls with method element
7909
        if ($style === 'rpc') {
7910
            if ($use === 'literal') {
7911
                $this->debug('wrapping RPC request with literal method element');
7912 View Code Duplication
                if ($namespace) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7913
                    // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
7914
                    $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . "</$nsPrefix:$operation>";
7915
                } else {
7916
                    $payload = "<$operation>" . $payload . "</$operation>";
7917
                }
7918 View Code Duplication
            } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
7919
                $this->debug('wrapping RPC request with encoded method element');
7920
                if ($namespace) {
7921
                    $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . "</$nsPrefix:$operation>";
7922
                } else {
7923
                    $payload = "<$operation>" . $payload . "</$operation>";
7924
                }
7925
            }
7926
        }
7927
        // serialize envelope
7928
        $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle);
7929
        $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7930
        $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7931
        // send
7932
        $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout);
7933
        if ($errstr = $this->getError()) {
7934
            $this->debug('Error: ' . $errstr);
7935
7936
            return false;
7937
        } else {
7938
            $this->return = $return;
0 ignored issues
show
Bug introduced by
The property return does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
7939
            $this->debug('sent message successfully and got a(n) ' . gettype($return));
7940
            $this->appendDebug('return=' . $this->varDump($return));
7941
7942
            // fault?
7943
            if (is_array($return) && isset($return['faultcode'])) {
7944
                $this->debug('got fault');
7945
                $this->setError($return['faultcode'] . ': ' . $return['faultstring']);
7946
                $this->fault = true;
0 ignored issues
show
Documentation Bug introduced by
It seems like true of type boolean is incompatible with the declared type object<fault> of property $fault.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
7947
                foreach ($return as $k => $v) {
7948
                    $this->$k = $v;
7949
                    $this->debug("$k = $v<br>");
7950
                }
7951
7952
                return $return;
7953
            } elseif ($style === 'document') {
7954
                // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7955
                // we are only going to return the first part here...sorry about that
7956
                return $return;
7957
            } else {
7958
                // array of return values
7959
                if (is_array($return)) {
7960
                    // multiple 'out' parameters, which we return wrapped up
7961
                    // in the array
7962
                    if (count($return) > 1) {
7963
                        return $return;
7964
                    }
7965
                    // single 'out' parameter (normally the return value)
7966
                    $return = array_shift($return);
7967
                    $this->debug('return shifted value: ');
7968
                    $this->appendDebug($this->varDump($return));
7969
7970
                    return $return;
7971
                    // nothing returned (ie, echoVoid)
7972
                } else {
7973
                    return '';
7974
                }
7975
            }
7976
        }
7977
    }
7978
7979
    /**
7980
     * check WSDL passed as an instance or pulled from an endpoint
7981
     *
7982
     * @access   private
7983
     */
7984
    public function checkWSDL()
7985
    {
7986
        $this->appendDebug($this->wsdl->getDebug());
7987
        $this->wsdl->clearDebug();
7988
        $this->debug('checkWSDL');
7989
        // catch errors
7990
        if ($errstr = $this->wsdl->getError()) {
7991
            $this->appendDebug($this->wsdl->getDebug());
7992
            $this->wsdl->clearDebug();
7993
            $this->debug('got wsdl error: ' . $errstr);
7994
            $this->setError('wsdl error: ' . $errstr);
7995
        } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
7996
            $this->appendDebug($this->wsdl->getDebug());
7997
            $this->wsdl->clearDebug();
7998
            $this->bindingType = 'soap';
7999
            $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
8000
        } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
8001
            $this->appendDebug($this->wsdl->getDebug());
8002
            $this->wsdl->clearDebug();
8003
            $this->bindingType = 'soap12';
8004
            $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
8005
            $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
8006
        } else {
8007
            $this->appendDebug($this->wsdl->getDebug());
8008
            $this->wsdl->clearDebug();
8009
            $this->debug('getOperations returned false');
8010
            $this->setError('no operations defined in the WSDL document!');
8011
        }
8012
    }
8013
8014
    /**
8015
     * instantiate wsdl object and parse wsdl file
8016
     *
8017
     * @access  public
8018
     */
8019
    public function loadWSDL()
8020
    {
8021
        $this->debug('instantiating wsdl class with doc: ' . $this->wsdlFile);
8022
        $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl);
8023
        $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
8024
        $this->wsdl->fetchWSDL($this->wsdlFile);
8025
        $this->checkWSDL();
8026
    }
8027
8028
    /**
8029
     * get available data pertaining to an operation
8030
     *
8031
     * @param  string $operation operation name
8032
     * @return array  array of data pertaining to the operation
8033
     * @access   public
8034
     */
8035
    public function getOperationData($operation)
8036
    {
8037 View Code Duplication
        if ($this->endpointType === 'wsdl' && null === $this->wsdl) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
8038
            $this->loadWSDL();
8039
            if ($this->getError()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getError() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
8040
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Nusoap_client::getOperationData of type array.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
8041
            }
8042
        }
8043
        if (isset($this->operations[$operation])) {
8044
            return $this->operations[$operation];
8045
        }
8046
        $this->debug("No data for operation: $operation");
8047
    }
8048
8049
    /**
8050
     * send the SOAP message
8051
     *
8052
     * Note: if the operation has multiple return values
8053
     * the return value of this method will be an array
8054
     * of those values.
8055
     *
8056
     * @param  string  $msg              a SOAPx4 soapmsg object
8057
     * @param  string  $soapaction       SOAPAction value
8058
     * @param  integer $timeout          set connection timeout in seconds
8059
     * @param  integer $response_timeout set response timeout in seconds
8060
     * @return mixed   native PHP types.
8061
     * @access   private
8062
     */
8063
    public function send($msg, $soapaction = '', $timeout = 0, $response_timeout = 30)
8064
    {
8065
        $this->checkCookies();
8066
        // detect transport
8067
        switch (true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/^http/', $this->endpoint) of type integer to the boolean true. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
8068
            // http(s)
8069
            case preg_match('/^http/', $this->endpoint):
8070
                $this->debug('transporting via HTTP');
8071
                if ($this->persistentConnection === true && is_object($this->persistentConnection)) {
8072
                    $http = $this->persistentConnection;
8073
                } else {
8074
                    $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
8075
                    if ($this->persistentConnection) {
8076
                        $http->usePersistentConnection();
8077
                    }
8078
                }
8079
                $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
8080
                $http->setSOAPAction($soapaction);
8081 View Code Duplication
                if ($this->proxyhost && $this->proxyport) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
8082
                    $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
8083
                }
8084 View Code Duplication
                if ($this->authtype !== '') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
8085
                    $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
8086
                }
8087
                if ($this->http_encoding !== '') {
8088
                    $http->setEncoding($this->http_encoding);
0 ignored issues
show
Documentation introduced by
$this->http_encoding is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
8089
                }
8090
                $this->debug('sending message, length=' . strlen($msg));
8091
                if (preg_match('/^http:/', $this->endpoint)) {
8092
                    //if (strpos($this->endpoint,'http:')) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8093
                    $this->responseData = $http->send($msg, $timeout, $response_timeout, $this->cookies);
0 ignored issues
show
Documentation Bug introduced by
It seems like $http->send($msg, $timeo...imeout, $this->cookies) can also be of type false. However, the property $responseData 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...
8094
                } elseif (preg_match('/^https/', $this->endpoint)) {
8095
                    //} elseif (strpos($this->endpoint,'https:')) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
69% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8096
                    //if (PHP_VERSION == '4.3.0-dev') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8097
                    //$response = $http->send($msg,$timeout,$response_timeout);
0 ignored issues
show
Unused Code Comprehensibility introduced by
74% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8098
                    //$this->request = $http->outgoing_payload;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8099
                    //$this->response = $http->incoming_payload;
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8100
                    //} else
8101
                    $this->responseData = $http->sendHTTPS($msg, $timeout, $response_timeout, $this->cookies);
0 ignored issues
show
Documentation Bug introduced by
It seems like $http->sendHTTPS($msg, $...imeout, $this->cookies) can also be of type false. However, the property $responseData 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...
Deprecated Code introduced by
The method Soap_transport_http::sendHTTPS() has been deprecated.

This method has been deprecated.

Loading history...
8102
                } else {
8103
                    $this->setError('no http/s in endpoint url');
8104
                }
8105
                $this->request  = $http->outgoing_payload;
8106
                $this->response = $http->incoming_payload;
8107
                $this->appendDebug($http->getDebug());
8108
                $this->UpdateCookies($http->incoming_cookies);
8109
8110
                // save transport object if using persistent connections
8111
                if ($this->persistentConnection) {
8112
                    $http->clearDebug();
8113
                    if (!is_object($this->persistentConnection)) {
8114
                        $this->persistentConnection = $http;
0 ignored issues
show
Documentation Bug introduced by
It seems like $http of type object<Soap_transport_http> is incompatible with the declared type boolean of property $persistentConnection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
8115
                    }
8116
                }
8117
8118
                if ($err = $http->getError()) {
8119
                    $this->setError('HTTP Error: ' . $err);
8120
8121
                    return false;
8122
                } elseif ($this->getError()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getError() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
8123
                    return false;
8124
                } else {
8125
                    $this->debug('got response, length=' . strlen($this->responseData) . ' type=' . $http->incoming_headers['content-type']);
8126
8127
                    return $this->parseResponse($http->incoming_headers, $this->responseData);
0 ignored issues
show
Security Bug introduced by
It seems like $this->responseData can also be of type false; however, Nusoap_client::parseResponse() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
8128
                }
8129
                break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
8130
            default:
8131
                $this->setError('no transport found, or selected transport is not yet supported!');
8132
8133
                return false;
8134
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
8135
        }
8136
    }
8137
8138
    /**
8139
     * processes SOAP message returned from server
8140
     *
8141
     * @param  array  $headers The HTTP headers
8142
     * @param  string $data    unprocessed response data from server
8143
     * @return mixed  value of the message, decoded into a PHP type
8144
     * @access   private
8145
     */
8146
    public function parseResponse($headers, $data)
8147
    {
8148
        $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
8149
        $this->appendDebug($this->varDump($headers));
8150
        if (!isset($headers['content-type'])) {
8151
            $this->setError('Response not of type text/xml (no content-type header)');
8152
8153
            return false;
8154
        }
8155 View Code Duplication
        if (false === strpos($headers['content-type'], 'text/xml')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
8156
            $this->setError('Response not of type text/xml: ' . $headers['content-type']);
8157
8158
            return false;
8159
        }
8160 View Code Duplication
        if (strpos($headers['content-type'], '=')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
8161
            $enc = str_replace('"', '', substr(strstr($headers['content-type'], '='), 1));
8162
            $this->debug('Got response encoding: ' . $enc);
8163
            if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
8164
                $this->xml_encoding = strtoupper($enc);
8165
            } else {
8166
                $this->xml_encoding = 'US-ASCII';
8167
            }
8168
        } else {
8169
            // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
8170
            $this->xml_encoding = 'ISO-8859-1';
8171
        }
8172
        $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
8173
        $parser = new nusoap_parser($data, $this->xml_encoding, $this->operation, $this->decode_utf8);
0 ignored issues
show
Bug introduced by
The property operation does not seem to exist. Did you mean operations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
8174
        // add parser debug data to our debug
8175
        $this->appendDebug($parser->getDebug());
8176
        // if parse errors
8177
        if ($errstr = $parser->getError()) {
8178
            $this->setError($errstr);
8179
            // destroy the parser object
8180
            unset($parser);
8181
8182
            return false;
8183
        } else {
8184
            // get SOAP headers
8185
            $this->responseHeaders = $parser->getHeaders();
8186
            // get SOAP headers
8187
            $this->responseHeader = $parser->get_soapheader();
8188
            // get decoded message
8189
            $return = $parser->get_soapbody();
8190
            // add document for doclit support
8191
            $this->document = $parser->document;
8192
            // destroy the parser object
8193
            unset($parser);
8194
8195
            // return decode message
8196
            return $return;
8197
        }
8198
    }
8199
8200
    /**
8201
     * sets user-specified cURL options
8202
     *
8203
     * @param mixed $option The cURL option (always integer?)
8204
     * @param mixed $value  The cURL option value
8205
     * @access   public
8206
     */
8207
    public function setCurlOption($option, $value)
8208
    {
8209
        $this->debug("setCurlOption option=$option, value=");
8210
        $this->appendDebug($this->varDump($value));
8211
        $this->curl_options[$option] = $value;
8212
    }
8213
8214
    /**
8215
     * sets the SOAP endpoint, which can override WSDL
8216
     *
8217
     * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
8218
     * @access   public
8219
     */
8220
    public function setEndpoint($endpoint)
8221
    {
8222
        $this->debug("setEndpoint(\"$endpoint\")");
8223
        $this->forceEndpoint = $endpoint;
8224
    }
8225
8226
    /**
8227
     * set the SOAP headers
8228
     *
8229
     * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
8230
     * @access   public
8231
     */
8232
    public function setHeaders($headers)
8233
    {
8234
        $this->debug('setHeaders headers=');
8235
        $this->appendDebug($this->varDump($headers));
8236
        $this->requestHeaders = $headers;
8237
    }
8238
8239
    /**
8240
     * get the SOAP response headers (namespace resolution incomplete)
8241
     *
8242
     * @return string
8243
     * @access   public
8244
     */
8245
    public function getHeaders()
8246
    {
8247
        return $this->responseHeaders;
8248
    }
8249
8250
    /**
8251
     * get the SOAP response Header (parsed)
8252
     *
8253
     * @return mixed
8254
     * @access   public
8255
     */
8256
    public function getHeader()
8257
    {
8258
        return $this->responseHeader;
8259
    }
8260
8261
    /**
8262
     * set proxy info here
8263
     *
8264
     * @param string $proxyhost
8265
     * @param string $proxyport
8266
     * @param string $proxyusername
8267
     * @param string $proxypassword
8268
     * @access   public
8269
     */
8270
    public function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
8271
    {
8272
        $this->proxyhost     = $proxyhost;
8273
        $this->proxyport     = $proxyport;
8274
        $this->proxyusername = $proxyusername;
8275
        $this->proxypassword = $proxypassword;
8276
    }
8277
8278
    /**
8279
     * if authenticating, set user credentials here
8280
     *
8281
     * @param string $username
8282
     * @param string $password
8283
     * @param string $authtype    (basic|digest|certificate|ntlm)
8284
     * @param array  $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
8285
     * @access   public
8286
     */
8287 View Code Duplication
    public function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
8288
    {
8289
        $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
8290
        $this->appendDebug($this->varDump($certRequest));
8291
        $this->username    = $username;
8292
        $this->password    = $password;
8293
        $this->authtype    = $authtype;
8294
        $this->certRequest = $certRequest;
8295
    }
8296
8297
    /**
8298
     * use HTTP encoding
8299
     *
8300
     * @param string $enc HTTP encoding
8301
     * @access   public
8302
     */
8303
    public function setHTTPEncoding($enc = 'gzip, deflate')
8304
    {
8305
        $this->debug("setHTTPEncoding(\"$enc\")");
8306
        $this->http_encoding = $enc;
0 ignored issues
show
Documentation Bug introduced by
The property $http_encoding was declared of type boolean, but $enc is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
8307
    }
8308
8309
    /**
8310
     * Set whether to try to use cURL connections if possible
8311
     *
8312
     * @param boolean $use Whether to try to use cURL
8313
     * @access   public
8314
     */
8315
    public function setUseCURL($use)
8316
    {
8317
        $this->debug("setUseCURL($use)");
8318
        $this->use_curl = $use;
8319
    }
8320
8321
    /**
8322
     * use HTTP persistent connections if possible
8323
     *
8324
     * @access   public
8325
     */
8326
    public function useHTTPPersistentConnection()
8327
    {
8328
        $this->debug('useHTTPPersistentConnection');
8329
        $this->persistentConnection = true;
8330
    }
8331
8332
    /**
8333
     * gets the default RPC parameter setting.
8334
     * If true, default is that call params are like RPC even for document style.
8335
     * Each call() can override this value.
8336
     *
8337
     * This is no longer used.
8338
     *
8339
     * @return boolean
8340
     * @access public
8341
     * @deprecated
8342
     */
8343
    public function getDefaultRpcParams()
8344
    {
8345
        return $this->defaultRpcParams;
8346
    }
8347
8348
    /**
8349
     * sets the default RPC parameter setting.
8350
     * If true, default is that call params are like RPC even for document style
8351
     * Each call() can override this value.
8352
     *
8353
     * This is no longer used.
8354
     *
8355
     * @param boolean $rpcParams
8356
     * @access public
8357
     * @deprecated
8358
     */
8359
    public function setDefaultRpcParams($rpcParams)
8360
    {
8361
        $this->defaultRpcParams = $rpcParams;
8362
    }
8363
8364
    /**
8365
     * dynamically creates an instance of a proxy class,
8366
     * allowing user to directly call methods from wsdl
8367
     *
8368
     * @return object soap_proxy object
8369
     * @access   public
8370
     */
8371
    public function getProxy()
8372
    {
8373
        $r       = mt_rand();
8374
        $evalStr = $this->_getProxyClassCode($r);
8375
        //$this->debug("proxy class: $evalStr");
0 ignored issues
show
Unused Code Comprehensibility introduced by
86% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
8376
        if ($this->getError()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getError() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
8377
            $this->debug('Error from _getProxyClassCode, so return NULL');
8378
8379
            return null;
8380
        }
8381
        // eval the class
8382
        eval($evalStr);
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
8383
        // instantiate proxy object
8384
        eval("\$proxy = new nusoap_proxy_$r('');");
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
8385
        // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
8386
        $proxy->endpointType     = 'wsdl';
0 ignored issues
show
Bug introduced by
The variable $proxy does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
8387
        $proxy->wsdlFile         = $this->wsdlFile;
8388
        $proxy->wsdl             = $this->wsdl;
8389
        $proxy->operations       = $this->operations;
8390
        $proxy->defaultRpcParams = $this->defaultRpcParams;
8391
        // transfer other state
8392
        $proxy->soap_defencoding     = $this->soap_defencoding;
8393
        $proxy->username             = $this->username;
8394
        $proxy->password             = $this->password;
8395
        $proxy->authtype             = $this->authtype;
8396
        $proxy->certRequest          = $this->certRequest;
8397
        $proxy->requestHeaders       = $this->requestHeaders;
8398
        $proxy->endpoint             = $this->endpoint;
8399
        $proxy->forceEndpoint        = $this->forceEndpoint;
8400
        $proxy->proxyhost            = $this->proxyhost;
8401
        $proxy->proxyport            = $this->proxyport;
8402
        $proxy->proxyusername        = $this->proxyusername;
8403
        $proxy->proxypassword        = $this->proxypassword;
8404
        $proxy->http_encoding        = $this->http_encoding;
8405
        $proxy->timeout              = $this->timeout;
8406
        $proxy->response_timeout     = $this->response_timeout;
8407
        $proxy->persistentConnection = $this->persistentConnection;
8408
        $proxy->decode_utf8          = $this->decode_utf8;
8409
        $proxy->curl_options         = $this->curl_options;
8410
        $proxy->bindingType          = $this->bindingType;
8411
        $proxy->use_curl             = $this->use_curl;
8412
8413
        return $proxy;
8414
    }
8415
8416
    /**
8417
     * dynamically creates proxy class code
8418
     *
8419
     * @param $r
8420
     * @return string PHP/NuSOAP code for the proxy class
8421
     * @access   private
8422
     */
8423
    public function _getProxyClassCode($r)
8424
    {
8425
        $this->debug("in getProxy endpointType=$this->endpointType");
8426
        $this->appendDebug('wsdl=' . $this->varDump($this->wsdl));
8427
        if ($this->endpointType !== 'wsdl') {
8428
            $evalStr = 'A proxy can only be created for a WSDL client';
8429
            $this->setError($evalStr);
8430
            $evalStr = "echo \"$evalStr\";";
8431
8432
            return $evalStr;
8433
        }
8434
        if ($this->endpointType === 'wsdl' && null === $this->wsdl) {
8435
            $this->loadWSDL();
8436
            if ($this->getError()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->getError() of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
8437
                return "echo \"" . $this->getError() . "\";";
8438
            }
8439
        }
8440
        $evalStr = '';
8441
        foreach ($this->operations as $operation => $opData) {
8442
            if ($operation != '') {
8443
                // create param string and param comment string
8444
                if (count($opData['input']['parts']) > 0) {
8445
                    $paramStr        = '';
8446
                    $paramArrayStr   = '';
8447
                    $paramCommentStr = '';
8448
                    foreach ($opData['input']['parts'] as $name => $type) {
8449
                        $paramStr        .= "\$$name, ";
8450
                        $paramArrayStr   .= "'$name' => \$$name, ";
8451
                        $paramCommentStr .= "$type \$$name, ";
8452
                    }
8453
                    $paramStr        = substr($paramStr, 0, strlen($paramStr) - 2);
8454
                    $paramArrayStr   = substr($paramArrayStr, 0, strlen($paramArrayStr) - 2);
8455
                    $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr) - 2);
8456
                } else {
8457
                    $paramStr        = '';
8458
                    $paramArrayStr   = '';
8459
                    $paramCommentStr = 'void';
8460
                }
8461
                $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
8462
                $evalStr             .= "// $paramCommentStr
8463
    function " . str_replace('.', '__', $operation) . "($paramStr) {
8464
        \$params = array($paramArrayStr);
8465
8466
        return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . (isset($opData['soapAction']) ? $opData['soapAction'] : '') . "');
8467
    }
8468
    ";
8469
                unset($paramStr, $paramCommentStr);
8470
            }
8471
        }
8472
        $evalStr = 'class nusoap_proxy_' . $r . ' extends Nusoap_client {
8473
    ' . $evalStr . '
8474
}';
8475
8476
        return $evalStr;
8477
    }
8478
8479
    /**
8480
     * dynamically creates proxy class code
8481
     *
8482
     * @return string PHP/NuSOAP code for the proxy class
8483
     * @access   public
8484
     */
8485
    public function getProxyClassCode()
8486
    {
8487
        $r = mt_rand();
8488
8489
        return $this->_getProxyClassCode($r);
8490
    }
8491
8492
    /**
8493
     * gets the HTTP body for the current request.
8494
     *
8495
     * @param  string $soapmsg The SOAP payload
8496
     * @return string The HTTP body, which includes the SOAP payload
8497
     * @access private
8498
     */
8499
    public function getHTTPBody($soapmsg)
8500
    {
8501
        return $soapmsg;
8502
    }
8503
8504
    /**
8505
     * gets the HTTP content type for the current request.
8506
     *
8507
     * Note: getHTTPBody must be called before this.
8508
     *
8509
     * @return string the HTTP content type for the current request.
8510
     * @access private
8511
     */
8512
    public function getHTTPContentType()
8513
    {
8514
        return 'text/xml';
8515
    }
8516
8517
    /**
8518
     * gets the HTTP content type charset for the current request.
8519
     * returns false for non-text content types.
8520
     *
8521
     * Note: getHTTPBody must be called before this.
8522
     *
8523
     * @return string the HTTP content type charset for the current request.
8524
     * @access private
8525
     */
8526
    public function getHTTPContentTypeCharset()
8527
    {
8528
        return $this->soap_defencoding;
8529
    }
8530
8531
    /*
8532
    * whether or not parser should decode utf8 element content
8533
    *
8534
    * @return   always returns true
8535
    * @access   public
8536
    */
8537
    /**
8538
     * @param $bool
8539
     * @return bool
8540
     */
8541
    public function decodeUTF8($bool)
8542
    {
8543
        $this->decode_utf8 = $bool;
8544
8545
        return true;
8546
    }
8547
8548
    /**
8549
     * adds a new Cookie into $this->cookies array
8550
     *
8551
     * @param  string $name  Cookie Name
8552
     * @param  string $value Cookie Value
8553
     * @return boolean if cookie-set was successful returns true, else false
8554
     * @access  public
8555
     */
8556
    public function setCookie($name, $value)
8557
    {
8558
        if ('' === $name) {
8559
            return false;
8560
        }
8561
        $this->cookies[] = array('name' => $name, 'value' => $value);
8562
8563
        return true;
8564
    }
8565
8566
    /**
8567
     * gets all Cookies
8568
     *
8569
     * @return array with all internal cookies
8570
     * @access   public
8571
     */
8572
    public function getCookies()
8573
    {
8574
        return $this->cookies;
8575
    }
8576
8577
    /**
8578
     * checks all Cookies and delete those which are expired
8579
     *
8580
     * @return boolean always return true
8581
     * @access   private
8582
     */
8583
    public function checkCookies()
8584
    {
8585
        if (count($this->cookies) == 0) {
8586
            return true;
8587
        }
8588
        $this->debug('checkCookie: check ' . count($this->cookies) . ' cookies');
8589
        $curr_cookies  = $this->cookies;
8590
        $this->cookies = array();
8591
        foreach ($curr_cookies as $cookie) {
8592
            if (!is_array($cookie)) {
8593
                $this->debug('Remove cookie that is not an array');
8594
                continue;
8595
            }
8596
            if (isset($cookie['expires']) && (!empty($cookie['expires']))) {
8597
                if (strtotime($cookie['expires']) > time()) {
8598
                    $this->cookies[] = $cookie;
8599
                } else {
8600
                    $this->debug('Remove expired cookie ' . $cookie['name']);
8601
                }
8602
            } else {
8603
                $this->cookies[] = $cookie;
8604
            }
8605
        }
8606
        $this->debug('checkCookie: ' . count($this->cookies) . ' cookies left in array');
8607
8608
        return true;
8609
    }
8610
8611
    /**
8612
     * updates the current cookies with a new set
8613
     *
8614
     * @param  array $cookies new cookies with which to update current ones
8615
     * @return boolean always return true
8616
     * @access  private
8617
     */
8618
    public function UpdateCookies($cookies)
8619
    {
8620
        if (count($this->cookies) == 0) {
8621
            // no existing cookies: take whatever is new
8622
            if (count($cookies) > 0) {
8623
                $this->debug('Setting new cookie(s)');
8624
                $this->cookies = $cookies;
8625
            }
8626
8627
            return true;
8628
        }
8629
        if (count($cookies) == 0) {
8630
            // no new cookies: keep what we've got
8631
            return true;
8632
        }
8633
        // merge
8634
        foreach ($cookies as $newCookie) {
8635
            if (!is_array($newCookie)) {
8636
                continue;
8637
            }
8638
            if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
8639
                continue;
8640
            }
8641
            $newName = $newCookie['name'];
8642
8643
            $found = false;
8644
            for ($i = 0, $iMax = count($this->cookies); $i < $iMax; ++$i) {
8645
                $cookie = $this->cookies[$i];
8646
                if (!is_array($cookie)) {
8647
                    continue;
8648
                }
8649
                if (!isset($cookie['name'])) {
8650
                    continue;
8651
                }
8652
                if ($newName != $cookie['name']) {
8653
                    continue;
8654
                }
8655
                $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
8656
                $domain    = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
8657
                if ($newDomain != $domain) {
8658
                    continue;
8659
                }
8660
                $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
8661
                $path    = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
8662
                if ($newPath != $path) {
8663
                    continue;
8664
                }
8665
                $this->cookies[$i] = $newCookie;
8666
                $found             = true;
8667
                $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
8668
                break;
8669
            }
8670
            if (!$found) {
8671
                $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
8672
                $this->cookies[] = $newCookie;
8673
            }
8674
        }
8675
8676
        return true;
8677
    }
8678
}
8679
8680
if (!extension_loaded('soap')) {
8681
    /**
8682
     *  For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
8683
     */
8684
    class Soapclient extends Nusoap_client
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
8685
    {
8686
    }
8687
}
8688
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
8689